[runtime] Fix the calculation of the instance size of ptr/var types. (#3790)
[mono-project.git] / mono / metadata / class.c
blobfe08d0e52b640d3fe21aa85b74eeb5017cb720a4
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, inflated_classes_size, inflated_methods_size;
58 guint32 classes_size, class_ext_size;
60 /* Low level lock which protects data structures in this module */
61 static mono_mutex_t classes_mutex;
63 /* Function supplied by the runtime to find classes by name using information from the AOT file */
64 static MonoGetClassFromName get_class_from_name = NULL;
66 static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error);
67 static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res);
68 static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
69 static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
70 static int generic_array_methods (MonoClass *klass);
71 static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos);
73 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
74 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
75 static void mono_field_resolve_type (MonoClassField *field, MonoError *error);
76 static guint32 mono_field_resolve_flags (MonoClassField *field);
77 static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
78 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
80 static gboolean mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error);
81 static gpointer mono_class_get_exception_data (const MonoClass *klass);
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 inline void
115 classes_lock (void)
117 mono_locks_os_acquire (&classes_mutex, ClassesLock);
120 static inline void
121 classes_unlock (void)
123 mono_locks_os_release (&classes_mutex, ClassesLock);
127 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
129 static void
130 enable_gclass_recording (void)
132 ++record_gclass_instantiation;
136 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
138 static void
139 disable_gclass_recording (gclass_record_func func, void *user_data)
141 GSList **head = &gclass_recorded_list;
143 g_assert (record_gclass_instantiation > 0);
144 --record_gclass_instantiation;
146 while (*head) {
147 GSList *node = *head;
148 if (func ((MonoClass*)node->data, user_data)) {
149 *head = node->next;
150 g_slist_free_1 (node);
151 } else {
152 head = &node->next;
156 /* We automatically discard all recorded gclasses when disabled. */
157 if (!record_gclass_instantiation && gclass_recorded_list) {
158 g_slist_free (gclass_recorded_list);
159 gclass_recorded_list = NULL;
164 * mono_class_from_typeref:
165 * @image: a MonoImage
166 * @type_token: a TypeRef token
168 * Creates the MonoClass* structure representing the type defined by
169 * the typeref token valid inside @image.
170 * Returns: The MonoClass* representing the typeref token, NULL ifcould
171 * not be loaded.
173 MonoClass *
174 mono_class_from_typeref (MonoImage *image, guint32 type_token)
176 MonoError error;
177 MonoClass *klass = mono_class_from_typeref_checked (image, type_token, &error);
178 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
179 return klass;
183 * mono_class_from_typeref_checked:
184 * @image: a MonoImage
185 * @type_token: a TypeRef token
186 * @error: error return code, if any.
188 * Creates the MonoClass* structure representing the type defined by
189 * the typeref token valid inside @image.
191 * Returns: The MonoClass* representing the typeref token, NULL if it could
192 * not be loaded with the @error value filled with the information about the
193 * error.
195 MonoClass *
196 mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
198 guint32 cols [MONO_TYPEREF_SIZE];
199 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
200 guint32 idx;
201 const char *name, *nspace;
202 MonoClass *res = NULL;
203 MonoImage *module;
205 mono_error_init (error);
207 if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
208 return NULL;
210 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
212 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
213 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
215 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
216 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
217 case MONO_RESOLUTION_SCOPE_MODULE:
219 LAMESPEC The spec says that a null module resolution scope should go through the exported type table.
220 This is not the observed behavior of existing implementations.
221 The defacto behavior is that it's just a typedef in disguise.
223 /* a typedef in disguise */
224 res = mono_class_from_name_checked (image, nspace, name, error);
225 goto done;
227 case MONO_RESOLUTION_SCOPE_MODULEREF:
228 module = mono_image_load_module_checked (image, idx, error);
229 if (module)
230 res = mono_class_from_name_checked (module, nspace, name, error);
231 goto done;
233 case MONO_RESOLUTION_SCOPE_TYPEREF: {
234 MonoClass *enclosing;
235 GList *tmp;
237 if (idx == mono_metadata_token_index (type_token)) {
238 mono_error_set_bad_image (error, image, "Image with self-referencing typeref token %08x.", type_token);
239 return NULL;
242 enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
243 return_val_if_nok (error, NULL);
245 if (enclosing->nested_classes_inited && enclosing->ext) {
246 /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
247 for (tmp = enclosing->ext->nested_classes; tmp; tmp = tmp->next) {
248 res = (MonoClass *)tmp->data;
249 if (strcmp (res->name, name) == 0)
250 return res;
252 } else {
253 /* Don't call mono_class_init as we might've been called by it recursively */
254 int i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, 1);
255 while (i) {
256 guint32 class_nested = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, MONO_NESTED_CLASS_NESTED);
257 guint32 string_offset = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
258 const char *nname = mono_metadata_string_heap (enclosing->image, string_offset);
260 if (strcmp (nname, name) == 0)
261 return mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, error);
263 i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1);
266 g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
267 goto done;
269 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
270 break;
273 if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
274 mono_error_set_bad_image (error, image, "Image with invalid assemblyref token %08x.", idx);
275 return NULL;
278 if (!image->references || !image->references [idx - 1])
279 mono_assembly_load_reference (image, idx - 1);
280 g_assert (image->references [idx - 1]);
282 /* If the assembly did not load, register this as a type load exception */
283 if (image->references [idx - 1] == REFERENCE_MISSING){
284 MonoAssemblyName aname;
285 char *human_name;
287 mono_assembly_get_assemblyref (image, idx - 1, &aname);
288 human_name = mono_stringify_assembly_name (&aname);
289 mono_error_set_assembly_load_simple (error, human_name, image->assembly ? image->assembly->ref_only : FALSE);
290 return NULL;
293 res = mono_class_from_name_checked (image->references [idx - 1]->image, nspace, name, error);
295 done:
296 /* Generic case, should be avoided for when a better error is possible. */
297 if (!res && mono_error_ok (error)) {
298 char *name = mono_class_name_from_token (image, type_token);
299 char *assembly = mono_assembly_name_from_token (image, type_token);
300 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
302 return res;
306 static void *
307 mono_image_memdup (MonoImage *image, void *data, guint size)
309 void *res = mono_image_alloc (image, size);
310 memcpy (res, data, size);
311 return res;
314 /* Copy everything mono_metadata_free_array free. */
315 MonoArrayType *
316 mono_dup_array_type (MonoImage *image, MonoArrayType *a)
318 if (image) {
319 a = (MonoArrayType *)mono_image_memdup (image, a, sizeof (MonoArrayType));
320 if (a->sizes)
321 a->sizes = (int *)mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
322 if (a->lobounds)
323 a->lobounds = (int *)mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
324 } else {
325 a = (MonoArrayType *)g_memdup (a, sizeof (MonoArrayType));
326 if (a->sizes)
327 a->sizes = (int *)g_memdup (a->sizes, a->numsizes * sizeof (int));
328 if (a->lobounds)
329 a->lobounds = (int *)g_memdup (a->lobounds, a->numlobounds * sizeof (int));
331 return a;
334 /* Copy everything mono_metadata_free_method_signature free. */
335 MonoMethodSignature*
336 mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
338 int i;
340 sig = mono_metadata_signature_dup_full (image, sig);
342 sig->ret = mono_metadata_type_dup (image, sig->ret);
343 for (i = 0; i < sig->param_count; ++i)
344 sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
346 return sig;
349 static void
350 _mono_type_get_assembly_name (MonoClass *klass, GString *str)
352 MonoAssembly *ta = klass->image->assembly;
353 char *name;
355 name = mono_stringify_assembly_name (&ta->aname);
356 g_string_append_printf (str, ", %s", name);
357 g_free (name);
360 static inline void
361 mono_type_name_check_byref (MonoType *type, GString *str)
363 if (type->byref)
364 g_string_append_c (str, '&');
368 * mono_identifier_escape_type_name_chars:
369 * @str: a destination string
370 * @identifier: an IDENTIFIER in internal form
372 * Returns: str.
374 * The displayed form of the identifier is appended to str.
376 * The displayed form of an identifier has the characters ,+&*[]\
377 * that have special meaning in type names escaped with a preceeding
378 * backslash (\) character.
380 static GString*
381 mono_identifier_escape_type_name_chars (GString* str, const char* identifier)
383 if (!identifier)
384 return str;
386 size_t n = str->len;
387 // reserve space for common case: there will be no escaped characters.
388 g_string_set_size(str, n + strlen(identifier));
389 g_string_set_size(str, n);
391 for (const char* s = identifier; *s != 0 ; s++) {
392 switch (*s) {
393 case ',':
394 case '+':
395 case '&':
396 case '*':
397 case '[':
398 case ']':
399 case '\\':
400 g_string_append_c (str, '\\');
401 g_string_append_c (str, *s);
402 break;
403 default:
404 g_string_append_c (str, *s);
405 break;
408 return str;
411 static void
412 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
413 MonoTypeNameFormat format)
415 MonoClass *klass;
417 switch (type->type) {
418 case MONO_TYPE_ARRAY: {
419 int i, rank = type->data.array->rank;
420 MonoTypeNameFormat nested_format;
422 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
423 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
425 mono_type_get_name_recurse (
426 &type->data.array->eklass->byval_arg, str, FALSE, nested_format);
427 g_string_append_c (str, '[');
428 if (rank == 1)
429 g_string_append_c (str, '*');
430 for (i = 1; i < rank; i++)
431 g_string_append_c (str, ',');
432 g_string_append_c (str, ']');
434 mono_type_name_check_byref (type, str);
436 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
437 _mono_type_get_assembly_name (type->data.array->eklass, str);
438 break;
440 case MONO_TYPE_SZARRAY: {
441 MonoTypeNameFormat nested_format;
443 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
444 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
446 mono_type_get_name_recurse (
447 &type->data.klass->byval_arg, str, FALSE, nested_format);
448 g_string_append (str, "[]");
450 mono_type_name_check_byref (type, str);
452 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
453 _mono_type_get_assembly_name (type->data.klass, str);
454 break;
456 case MONO_TYPE_PTR: {
457 MonoTypeNameFormat nested_format;
459 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
460 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
462 mono_type_get_name_recurse (
463 type->data.type, str, FALSE, nested_format);
464 g_string_append_c (str, '*');
466 mono_type_name_check_byref (type, str);
468 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
469 _mono_type_get_assembly_name (mono_class_from_mono_type (type->data.type), str);
470 break;
472 case MONO_TYPE_VAR:
473 case MONO_TYPE_MVAR:
474 if (!mono_generic_param_info (type->data.generic_param))
475 g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
476 else
477 g_string_append (str, mono_generic_param_info (type->data.generic_param)->name);
479 mono_type_name_check_byref (type, str);
481 break;
482 default:
483 klass = mono_class_from_mono_type (type);
484 if (klass->nested_in) {
485 mono_type_get_name_recurse (
486 &klass->nested_in->byval_arg, str, TRUE, format);
487 if (format == MONO_TYPE_NAME_FORMAT_IL)
488 g_string_append_c (str, '.');
489 else
490 g_string_append_c (str, '+');
491 } else if (*klass->name_space) {
492 if (format == MONO_TYPE_NAME_FORMAT_IL)
493 g_string_append (str, klass->name_space);
494 else
495 mono_identifier_escape_type_name_chars (str, klass->name_space);
496 g_string_append_c (str, '.');
498 if (format == MONO_TYPE_NAME_FORMAT_IL) {
499 char *s = strchr (klass->name, '`');
500 int len = s ? s - klass->name : strlen (klass->name);
501 g_string_append_len (str, klass->name, len);
502 } else {
503 mono_identifier_escape_type_name_chars (str, klass->name);
505 if (is_recursed)
506 break;
507 if (klass->generic_class) {
508 MonoGenericClass *gclass = klass->generic_class;
509 MonoGenericInst *inst = gclass->context.class_inst;
510 MonoTypeNameFormat nested_format;
511 int i;
513 nested_format = format == MONO_TYPE_NAME_FORMAT_FULL_NAME ?
514 MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format;
516 if (format == MONO_TYPE_NAME_FORMAT_IL)
517 g_string_append_c (str, '<');
518 else
519 g_string_append_c (str, '[');
520 for (i = 0; i < inst->type_argc; i++) {
521 MonoType *t = inst->type_argv [i];
523 if (i)
524 g_string_append_c (str, ',');
525 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
526 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
527 g_string_append_c (str, '[');
528 mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
529 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
530 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
531 g_string_append_c (str, ']');
533 if (format == MONO_TYPE_NAME_FORMAT_IL)
534 g_string_append_c (str, '>');
535 else
536 g_string_append_c (str, ']');
537 } else if (klass->generic_container &&
538 (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
539 (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
540 int i;
542 if (format == MONO_TYPE_NAME_FORMAT_IL)
543 g_string_append_c (str, '<');
544 else
545 g_string_append_c (str, '[');
546 for (i = 0; i < klass->generic_container->type_argc; i++) {
547 if (i)
548 g_string_append_c (str, ',');
549 g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name);
551 if (format == MONO_TYPE_NAME_FORMAT_IL)
552 g_string_append_c (str, '>');
553 else
554 g_string_append_c (str, ']');
557 mono_type_name_check_byref (type, str);
559 if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
560 (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
561 _mono_type_get_assembly_name (klass, str);
562 break;
567 * mono_type_get_name_full:
568 * @type: a type
569 * @format: the format for the return string.
572 * Returns: The string representation in a number of formats:
574 * if format is MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
575 * returned in the formatrequired by System.Reflection, this is the
576 * inverse of mono_reflection_parse_type ().
578 * if format is MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
579 * be used by the IL assembler.
581 * if format is MONO_TYPE_NAME_FORMAT_FULL_NAME
583 * if format is MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
585 char*
586 mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
588 GString* result;
590 result = g_string_new ("");
592 mono_type_get_name_recurse (type, result, FALSE, format);
594 return g_string_free (result, FALSE);
598 * mono_type_get_full_name:
599 * @class: a class
601 * Returns: The string representation for type as required by System.Reflection.
602 * The inverse of mono_reflection_parse_type ().
604 char *
605 mono_type_get_full_name (MonoClass *klass)
607 return mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_REFLECTION);
611 * mono_type_get_name:
612 * @type: a type
614 * Returns: The string representation for type as it would be represented in IL code.
616 char*
617 mono_type_get_name (MonoType *type)
619 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
623 * mono_type_get_underlying_type:
624 * @type: a type
626 * Returns: The MonoType for the underlying integer type if @type
627 * is an enum and byref is false, otherwise the type itself.
629 MonoType*
630 mono_type_get_underlying_type (MonoType *type)
632 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype && !type->byref)
633 return mono_class_enum_basetype (type->data.klass);
634 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype && !type->byref)
635 return mono_class_enum_basetype (type->data.generic_class->container_class);
636 return type;
640 * mono_class_is_open_constructed_type:
641 * @type: a type
643 * Returns: TRUE if type represents a generics open constructed type.
644 * IOW, not all type parameters required for the instantiation have
645 * been provided or it's a generic type definition.
647 * An open constructed type means it's a non realizable type. Not to
648 * be mixed up with an abstract type - we can't cast or dispatch to
649 * an open type, for example.
651 gboolean
652 mono_class_is_open_constructed_type (MonoType *t)
654 switch (t->type) {
655 case MONO_TYPE_VAR:
656 case MONO_TYPE_MVAR:
657 return TRUE;
658 case MONO_TYPE_SZARRAY:
659 return mono_class_is_open_constructed_type (&t->data.klass->byval_arg);
660 case MONO_TYPE_ARRAY:
661 return mono_class_is_open_constructed_type (&t->data.array->eklass->byval_arg);
662 case MONO_TYPE_PTR:
663 return mono_class_is_open_constructed_type (t->data.type);
664 case MONO_TYPE_GENERICINST:
665 return t->data.generic_class->context.class_inst->is_open;
666 case MONO_TYPE_CLASS:
667 case MONO_TYPE_VALUETYPE:
668 return t->data.klass->generic_container != NULL;
669 default:
670 return FALSE;
675 This is a simple function to catch the most common bad instances of generic types.
676 Specially those that might lead to further failures in the runtime.
678 static gboolean
679 is_valid_generic_argument (MonoType *type)
681 switch (type->type) {
682 case MONO_TYPE_VOID:
683 //case MONO_TYPE_TYPEDBYREF:
684 return FALSE;
685 default:
686 return TRUE;
690 static MonoType*
691 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
693 mono_error_init (error);
695 switch (type->type) {
696 case MONO_TYPE_MVAR: {
697 MonoType *nt;
698 int num = mono_type_get_generic_param_num (type);
699 MonoGenericInst *inst = context->method_inst;
700 if (!inst)
701 return NULL;
702 if (num >= inst->type_argc) {
703 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
704 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
705 num, info ? info->name : "", inst->type_argc);
706 return NULL;
709 if (!is_valid_generic_argument (inst->type_argv [num])) {
710 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
711 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
712 num, info ? info->name : "", inst->type_argv [num]->type);
713 return NULL;
716 * Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
717 * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
718 * ->byref and ->attrs from @type are propagated to the returned type.
720 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
721 nt->byref = type->byref;
722 nt->attrs = type->attrs;
723 return nt;
725 case MONO_TYPE_VAR: {
726 MonoType *nt;
727 int num = mono_type_get_generic_param_num (type);
728 MonoGenericInst *inst = context->class_inst;
729 if (!inst)
730 return NULL;
731 if (num >= inst->type_argc) {
732 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
733 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
734 num, info ? info->name : "", inst->type_argc);
735 return NULL;
737 if (!is_valid_generic_argument (inst->type_argv [num])) {
738 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
739 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
740 num, info ? info->name : "", inst->type_argv [num]->type);
741 return NULL;
743 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
744 nt->byref = type->byref;
745 nt->attrs = type->attrs;
746 return nt;
748 case MONO_TYPE_SZARRAY: {
749 MonoClass *eclass = type->data.klass;
750 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
751 if (!inflated || !mono_error_ok (error))
752 return NULL;
753 nt = mono_metadata_type_dup (image, type);
754 nt->data.klass = mono_class_from_mono_type (inflated);
755 mono_metadata_free_type (inflated);
756 return nt;
758 case MONO_TYPE_ARRAY: {
759 MonoClass *eclass = type->data.array->eklass;
760 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
761 if (!inflated || !mono_error_ok (error))
762 return NULL;
763 nt = mono_metadata_type_dup (image, type);
764 nt->data.array->eklass = mono_class_from_mono_type (inflated);
765 mono_metadata_free_type (inflated);
766 return nt;
768 case MONO_TYPE_GENERICINST: {
769 MonoGenericClass *gclass = type->data.generic_class;
770 MonoGenericInst *inst;
771 MonoType *nt;
772 if (!gclass->context.class_inst->is_open)
773 return NULL;
775 inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
776 return_val_if_nok (error, NULL);
778 if (inst != gclass->context.class_inst)
779 gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
781 if (gclass == type->data.generic_class)
782 return NULL;
784 nt = mono_metadata_type_dup (image, type);
785 nt->data.generic_class = gclass;
786 return nt;
788 case MONO_TYPE_CLASS:
789 case MONO_TYPE_VALUETYPE: {
790 MonoClass *klass = type->data.klass;
791 MonoGenericContainer *container = klass->generic_container;
792 MonoGenericInst *inst;
793 MonoGenericClass *gclass = NULL;
794 MonoType *nt;
796 if (!container)
797 return NULL;
799 /* We can't use context->class_inst directly, since it can have more elements */
800 inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
801 return_val_if_nok (error, NULL);
803 if (inst == container->context.class_inst)
804 return NULL;
806 gclass = mono_metadata_lookup_generic_class (klass, inst, image_is_dynamic (klass->image));
808 nt = mono_metadata_type_dup (image, type);
809 nt->type = MONO_TYPE_GENERICINST;
810 nt->data.generic_class = gclass;
811 return nt;
813 default:
814 return NULL;
816 return NULL;
819 MonoGenericContext *
820 mono_generic_class_get_context (MonoGenericClass *gclass)
822 return &gclass->context;
825 MonoGenericContext *
826 mono_class_get_context (MonoClass *klass)
828 return klass->generic_class ? mono_generic_class_get_context (klass->generic_class) : NULL;
832 * mono_class_get_generic_container:
834 * Return the generic container of KLASS which should be a generic type definition.
836 MonoGenericContainer*
837 mono_class_get_generic_container (MonoClass *klass)
839 g_assert (klass->is_generic);
841 return klass->generic_container;
845 * mono_class_get_generic_class:
847 * Return the MonoGenericClass of KLASS, which should be a generic instance.
849 MonoGenericClass*
850 mono_class_get_generic_class (MonoClass *klass)
852 g_assert (klass->is_inflated);
854 return klass->generic_class;
858 * mono_class_inflate_generic_type_with_mempool:
859 * @mempool: a mempool
860 * @type: a type
861 * @context: a generics context
862 * @error: error context
864 * The same as mono_class_inflate_generic_type, but allocates the MonoType
865 * from mempool if it is non-NULL. If it is NULL, the MonoType is
866 * allocated on the heap and is owned by the caller.
867 * The returned type can potentially be the same as TYPE, so it should not be
868 * modified by the caller, and it should be freed using mono_metadata_free_type ().
870 MonoType*
871 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
873 MonoType *inflated = NULL;
874 mono_error_init (error);
876 if (context)
877 inflated = inflate_generic_type (image, type, context, error);
878 return_val_if_nok (error, NULL);
880 if (!inflated) {
881 MonoType *shared = mono_metadata_get_shared_type (type);
883 if (shared) {
884 return shared;
885 } else {
886 return mono_metadata_type_dup (image, type);
890 mono_stats.inflated_type_count++;
891 return inflated;
895 * mono_class_inflate_generic_type:
896 * @type: a type
897 * @context: a generics context
899 * If @type is a generic type and @context is not NULL, instantiate it using the
900 * generics context @context.
902 * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
903 * on the heap and is owned by the caller. Returns NULL on error.
905 * @deprecated Please use mono_class_inflate_generic_type_checked instead
907 MonoType*
908 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
910 MonoError error;
911 MonoType *result;
912 result = mono_class_inflate_generic_type_checked (type, context, &error);
913 mono_error_cleanup (&error);
914 return result;
918 * mono_class_inflate_generic_type:
919 * @type: a type
920 * @context: a generics context
921 * @error: error context to use
923 * If @type is a generic type and @context is not NULL, instantiate it using the
924 * generics context @context.
926 * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
927 * on the heap and is owned by the caller.
929 MonoType*
930 mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
932 return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
936 * mono_class_inflate_generic_type_no_copy:
938 * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
939 * was done.
941 static MonoType*
942 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
944 MonoType *inflated = NULL;
946 mono_error_init (error);
947 if (context) {
948 inflated = inflate_generic_type (image, type, context, error);
949 return_val_if_nok (error, NULL);
952 if (!inflated)
953 return type;
955 mono_stats.inflated_type_count++;
956 return inflated;
960 * mono_class_inflate_generic_class:
962 * Inflate the class @gklass with @context. Set @error on failure.
964 MonoClass*
965 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
967 MonoClass *res;
968 MonoType *inflated;
970 inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, error);
971 return_val_if_nok (error, NULL);
973 res = mono_class_from_mono_type (inflated);
974 mono_metadata_free_type (inflated);
976 return res;
979 static MonoGenericContext
980 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
982 MonoGenericInst *class_inst = NULL;
983 MonoGenericInst *method_inst = NULL;
984 MonoGenericContext res = { NULL, NULL };
986 mono_error_init (error);
988 if (context->class_inst) {
989 class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
990 if (!mono_error_ok (error))
991 goto fail;
994 if (context->method_inst) {
995 method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with, error);
996 if (!mono_error_ok (error))
997 goto fail;
1000 res.class_inst = class_inst;
1001 res.method_inst = method_inst;
1002 fail:
1003 return res;
1007 * mono_class_inflate_generic_method:
1008 * @method: a generic method
1009 * @context: a generics context
1011 * Instantiate the generic method @method using the generics context @context.
1013 * Returns: The new instantiated method
1015 MonoMethod *
1016 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
1018 return mono_class_inflate_generic_method_full (method, NULL, context);
1021 MonoMethod *
1022 mono_class_inflate_generic_method_checked (MonoMethod *method, MonoGenericContext *context, MonoError *error)
1024 return mono_class_inflate_generic_method_full_checked (method, NULL, context, error);
1028 * mono_class_inflate_generic_method_full:
1030 * Instantiate method @method with the generic context @context.
1031 * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
1032 * Use mono_method_signature () and mono_method_get_header () to get the correct values.
1034 MonoMethod*
1035 mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context)
1037 MonoError error;
1038 MonoMethod *res = mono_class_inflate_generic_method_full_checked (method, klass_hint, context, &error);
1039 if (!mono_error_ok (&error))
1040 /*FIXME do proper error handling - on this case, kill this function. */
1041 g_error ("Could not inflate generic method due to %s", mono_error_get_message (&error));
1043 return res;
1047 * mono_class_inflate_generic_method_full_checked:
1048 * Same as mono_class_inflate_generic_method_full but return failure using @error.
1050 MonoMethod*
1051 mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error)
1053 MonoMethod *result;
1054 MonoMethodInflated *iresult, *cached;
1055 MonoMethodSignature *sig;
1056 MonoGenericContext tmp_context;
1058 mono_error_init (error);
1060 /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
1061 while (method->is_inflated) {
1062 MonoGenericContext *method_context = mono_method_get_context (method);
1063 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1065 tmp_context = inflate_generic_context (method_context, context, error);
1066 return_val_if_nok (error, NULL);
1068 context = &tmp_context;
1070 if (mono_metadata_generic_context_equal (method_context, context))
1071 return method;
1073 method = imethod->declaring;
1077 * A method only needs to be inflated if the context has argument for which it is
1078 * parametric. Eg:
1080 * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
1081 * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
1084 if (!((method->is_generic && context->method_inst) ||
1085 (method->klass->generic_container && context->class_inst)))
1086 return method;
1088 iresult = g_new0 (MonoMethodInflated, 1);
1089 iresult->context = *context;
1090 iresult->declaring = method;
1092 if (!context->method_inst && method->is_generic)
1093 iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
1095 if (!context->class_inst) {
1096 g_assert (!iresult->declaring->klass->generic_class);
1097 if (iresult->declaring->klass->generic_container)
1098 iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst;
1099 else if (iresult->declaring->klass->generic_class)
1100 iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst;
1102 /* This can happen with some callers like mono_object_get_virtual_method () */
1103 if (!iresult->declaring->klass->generic_container && !iresult->declaring->klass->generic_class)
1104 iresult->context.class_inst = NULL;
1106 MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
1108 // check cache
1109 mono_image_set_lock (set);
1110 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1111 mono_image_set_unlock (set);
1113 if (cached) {
1114 g_free (iresult);
1115 return (MonoMethod*)cached;
1118 mono_stats.inflated_method_count++;
1120 inflated_methods_size += sizeof (MonoMethodInflated);
1122 sig = mono_method_signature (method);
1123 if (!sig) {
1124 char *name = mono_type_get_full_name (method->klass);
1125 mono_error_set_bad_image (error, method->klass->image, "Could not resolve signature of method %s:%s", name, method->name);
1126 g_free (name);
1127 goto fail;
1130 if (sig->pinvoke) {
1131 memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
1132 } else {
1133 memcpy (&iresult->method.method, method, sizeof (MonoMethod));
1136 result = (MonoMethod *) iresult;
1137 result->is_inflated = TRUE;
1138 result->is_generic = FALSE;
1139 result->sre_method = FALSE;
1140 result->signature = NULL;
1142 if (method->wrapper_type) {
1143 MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
1144 MonoMethodWrapper *resw = (MonoMethodWrapper*)result;
1145 int len = GPOINTER_TO_INT (((void**)mw->method_data) [0]);
1147 resw->method_data = (void **)g_malloc (sizeof (gpointer) * (len + 1));
1148 memcpy (resw->method_data, mw->method_data, sizeof (gpointer) * (len + 1));
1151 if (iresult->context.method_inst) {
1152 /* Set the generic_container of the result to the generic_container of method */
1153 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
1155 if (generic_container && iresult->context.method_inst == generic_container->context.method_inst) {
1156 result->is_generic = 1;
1157 mono_method_set_generic_container (result, generic_container);
1161 if (!klass_hint || !klass_hint->generic_class ||
1162 klass_hint->generic_class->container_class != method->klass ||
1163 klass_hint->generic_class->context.class_inst != context->class_inst)
1164 klass_hint = NULL;
1166 if (method->klass->generic_container)
1167 result->klass = klass_hint;
1169 if (!result->klass) {
1170 MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context, error);
1171 if (!mono_error_ok (error))
1172 goto fail;
1174 result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
1175 if (inflated)
1176 mono_metadata_free_type (inflated);
1180 * FIXME: This should hold, but it doesn't:
1182 * if (result->is_inflated && mono_method_get_context (result)->method_inst &&
1183 * mono_method_get_context (result)->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)result)->declaring)->context.method_inst) {
1184 * g_assert (result->is_generic);
1187 * Fixing this here causes other things to break, hence a very
1188 * ugly hack in mini-trampolines.c - see
1189 * is_generic_method_definition().
1192 // check cache
1193 mono_image_set_lock (set);
1194 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1195 if (!cached) {
1196 g_hash_table_insert (set->gmethod_cache, iresult, iresult);
1197 iresult->owner = set;
1198 cached = iresult;
1200 mono_image_set_unlock (set);
1202 return (MonoMethod*)cached;
1204 fail:
1205 g_free (iresult);
1206 return NULL;
1210 * mono_get_inflated_method:
1212 * Obsolete. We keep it around since it's mentioned in the public API.
1214 MonoMethod*
1215 mono_get_inflated_method (MonoMethod *method)
1217 return method;
1221 * mono_method_get_context_general:
1222 * @method: a method
1223 * @uninflated: handle uninflated methods?
1225 * Returns the generic context of a method or NULL if it doesn't have
1226 * one. For an inflated method that's the context stored in the
1227 * method. Otherwise it's in the method's generic container or in the
1228 * generic container of the method's class.
1230 MonoGenericContext*
1231 mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
1233 if (method->is_inflated) {
1234 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1235 return &imethod->context;
1237 if (!uninflated)
1238 return NULL;
1239 if (method->is_generic)
1240 return &(mono_method_get_generic_container (method)->context);
1241 if (method->klass->generic_container)
1242 return &method->klass->generic_container->context;
1243 return NULL;
1247 * mono_method_get_context:
1248 * @method: a method
1250 * Returns the generic context for method if it's inflated, otherwise
1251 * NULL.
1253 MonoGenericContext*
1254 mono_method_get_context (MonoMethod *method)
1256 return mono_method_get_context_general (method, FALSE);
1260 * mono_method_get_generic_container:
1262 * Returns the generic container of METHOD, which should be a generic method definition.
1263 * Returns NULL if METHOD is not a generic method definition.
1264 * LOCKING: Acquires the loader lock.
1266 MonoGenericContainer*
1267 mono_method_get_generic_container (MonoMethod *method)
1269 MonoGenericContainer *container;
1271 if (!method->is_generic)
1272 return NULL;
1274 container = (MonoGenericContainer *)mono_image_property_lookup (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER);
1275 g_assert (container);
1277 return container;
1281 * mono_method_set_generic_container:
1283 * Sets the generic container of METHOD to CONTAINER.
1284 * LOCKING: Acquires the image lock.
1286 void
1287 mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
1289 g_assert (method->is_generic);
1291 mono_image_property_insert (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
1294 /**
1295 * mono_class_find_enum_basetype:
1296 * @class: The enum class
1298 * Determine the basetype of an enum by iterating through its fields. We do this
1299 * in a separate function since it is cheaper than calling mono_class_setup_fields.
1301 static MonoType*
1302 mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
1304 MonoGenericContainer *container = NULL;
1305 MonoImage *m = klass->image;
1306 const int top = klass->field.count;
1307 int i;
1309 g_assert (klass->enumtype);
1311 mono_error_init (error);
1313 if (klass->generic_container)
1314 container = klass->generic_container;
1315 else if (klass->generic_class) {
1316 MonoClass *gklass = klass->generic_class->container_class;
1318 container = gklass->generic_container;
1319 g_assert (container);
1323 * Fetch all the field information.
1325 for (i = 0; i < top; i++){
1326 const char *sig;
1327 guint32 cols [MONO_FIELD_SIZE];
1328 int idx = klass->field.first + i;
1329 MonoType *ftype;
1331 /* klass->field.first and idx points into the fieldptr table */
1332 mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
1334 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
1335 continue;
1337 if (!mono_verifier_verify_field_signature (klass->image, cols [MONO_FIELD_SIGNATURE], NULL)) {
1338 mono_error_set_bad_image (error, klass->image, "Invalid field signature %x", cols [MONO_FIELD_SIGNATURE]);
1339 goto fail;
1342 sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
1343 mono_metadata_decode_value (sig, &sig);
1344 /* FIELD signature == 0x06 */
1345 if (*sig != 0x06) {
1346 mono_error_set_bad_image (error, klass->image, "Invalid field signature %x, expected 0x6 but got %x", cols [MONO_FIELD_SIGNATURE], *sig);
1347 goto fail;
1350 ftype = mono_metadata_parse_type_checked (m, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
1351 if (!ftype)
1352 goto fail;
1354 if (klass->generic_class) {
1355 //FIXME do we leak here?
1356 ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error);
1357 if (!mono_error_ok (error))
1358 goto fail;
1359 ftype->attrs = cols [MONO_FIELD_FLAGS];
1362 return ftype;
1364 mono_error_set_type_load_class (error, klass, "Could not find base type");
1366 fail:
1367 return NULL;
1371 * Checks for MonoClass::has_failure without resolving all MonoType's into MonoClass'es
1373 static gboolean
1374 mono_type_has_exceptions (MonoType *type)
1376 switch (type->type) {
1377 case MONO_TYPE_CLASS:
1378 case MONO_TYPE_VALUETYPE:
1379 case MONO_TYPE_SZARRAY:
1380 return mono_class_has_failure (type->data.klass);
1381 case MONO_TYPE_ARRAY:
1382 return mono_class_has_failure (type->data.array->eklass);
1383 case MONO_TYPE_GENERICINST:
1384 return mono_class_has_failure (mono_generic_class_get_class (type->data.generic_class));
1385 default:
1386 return FALSE;
1390 void
1391 mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
1393 g_assert (mono_class_has_failure (klass));
1394 MonoErrorBoxed *box = (MonoErrorBoxed*)mono_class_get_exception_data (klass);
1395 mono_error_set_from_boxed (oerror, box);
1400 * mono_class_alloc:
1402 * Allocate memory for some data belonging to CLASS, either from its image's mempool,
1403 * or from the heap.
1405 gpointer
1406 mono_class_alloc (MonoClass *klass, int size)
1408 if (klass->generic_class)
1409 return mono_image_set_alloc (klass->generic_class->owner, size);
1410 else
1411 return mono_image_alloc (klass->image, size);
1414 gpointer
1415 mono_class_alloc0 (MonoClass *klass, int size)
1417 gpointer res;
1419 res = mono_class_alloc (klass, size);
1420 memset (res, 0, size);
1421 return res;
1424 #define mono_class_new0(klass,struct_type, n_structs) \
1425 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
1428 * mono_class_setup_basic_field_info:
1429 * @class: The class to initialize
1431 * Initializes the following fields in MonoClass:
1432 * * klass->fields (only field->parent and field->name)
1433 * * klass->field.count
1434 * * klass->field.first
1435 * LOCKING: Acquires the loader lock
1437 static void
1438 mono_class_setup_basic_field_info (MonoClass *klass)
1440 MonoClassField *field;
1441 MonoClassField *fields;
1442 MonoClass *gtd;
1443 MonoImage *image;
1444 int i, top;
1446 if (klass->fields)
1447 return;
1449 gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
1450 image = klass->image;
1452 if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) {
1454 * This happens when a generic instance of an unfinished generic typebuilder
1455 * is used as an element type for creating an array type. We can't initialize
1456 * the fields of this class using the fields of gklass, since gklass is not
1457 * finished yet, fields could be added to it later.
1459 return;
1462 if (gtd) {
1463 mono_class_setup_basic_field_info (gtd);
1465 mono_loader_lock ();
1466 klass->field.first = gtd->field.first;
1467 klass->field.count = gtd->field.count;
1468 mono_loader_unlock ();
1471 top = klass->field.count;
1473 fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
1476 * Fetch all the field information.
1478 for (i = 0; i < top; i++){
1479 field = &fields [i];
1480 field->parent = klass;
1482 if (gtd) {
1483 field->name = mono_field_get_name (&gtd->fields [i]);
1484 } else {
1485 int idx = klass->field.first + i;
1486 /* klass->field.first and idx points into the fieldptr table */
1487 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
1488 /* The name is needed for fieldrefs */
1489 field->name = mono_metadata_string_heap (image, name_idx);
1493 mono_memory_barrier ();
1495 mono_loader_lock ();
1496 if (!klass->fields)
1497 klass->fields = fields;
1498 mono_loader_unlock ();
1502 * mono_class_set_failure_causedby_class:
1503 * @klass: the class that is failing
1504 * @caused_by: the class that caused the failure
1505 * @msg: Why @klass is failing.
1507 * If @caused_by has a failure, sets a TypeLoadException failure on
1508 * @klass with message "@msg, due to: {@caused_by message}".
1510 * Returns: TRUE if a failiure was set, or FALSE if @caused_by doesn't have a failure.
1512 static gboolean
1513 mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg)
1515 if (mono_class_has_failure (caused_by)) {
1516 MonoError cause_error;
1517 mono_error_init (&cause_error);
1518 mono_error_set_for_class_failure (&cause_error, caused_by);
1519 mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (&cause_error));
1520 mono_error_cleanup (&cause_error);
1521 return TRUE;
1522 } else {
1523 return FALSE;
1528 /**
1529 * mono_class_setup_fields:
1530 * @klass: The class to initialize
1532 * Initializes klass->fields, computes class layout and sizes.
1533 * typebuilder_setup_fields () is the corresponding function for dynamic classes.
1534 * Sets the following fields in @klass:
1535 * - packing_size
1536 * - min_align
1537 * - blittable
1538 * - has_references (if the class contains instance references firled or structs that contain references)
1539 * - has_static_refs (same, but for static fields)
1540 * - instance_size (size of the object in memory)
1541 * - class_size (size needed for the static fields)
1542 * - size_inited (flag set when the instance_size is set)
1543 * - element_class/cast_class (for enums)
1544 * - fields_inited
1546 * LOCKING: Acquires the loader lock.
1548 void
1549 mono_class_setup_fields (MonoClass *klass)
1551 MonoError error;
1552 MonoImage *m = klass->image;
1553 int top;
1554 guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
1555 int i;
1556 guint32 real_size = 0;
1557 guint32 packing_size = 0;
1558 int instance_size;
1559 gboolean explicit_size;
1560 MonoClassField *field;
1561 MonoClass *gtd;
1563 if (klass->fields_inited)
1564 return;
1566 if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) {
1568 * This happens when a generic instance of an unfinished generic typebuilder
1569 * is used as an element type for creating an array type. We can't initialize
1570 * the fields of this class using the fields of gklass, since gklass is not
1571 * finished yet, fields could be added to it later.
1573 return;
1576 mono_class_setup_basic_field_info (klass);
1577 top = klass->field.count;
1579 gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
1580 if (gtd) {
1581 mono_class_setup_fields (gtd);
1582 if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
1583 return;
1586 instance_size = 0;
1587 if (klass->parent) {
1588 /* For generic instances, klass->parent might not have been initialized */
1589 mono_class_init (klass->parent);
1590 mono_class_setup_fields (klass->parent);
1591 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
1592 return;
1593 instance_size = klass->parent->instance_size;
1594 } else {
1595 instance_size = sizeof (MonoObject);
1598 /* Get the real size */
1599 explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
1600 if (explicit_size)
1601 instance_size += real_size;
1604 * This function can recursively call itself.
1605 * Prevent infinite recursion by using a list in TLS.
1607 GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
1608 if (g_slist_find (init_list, klass))
1609 return;
1610 init_list = g_slist_prepend (init_list, klass);
1611 mono_native_tls_set_value (setup_fields_tls_id, init_list);
1614 * Fetch all the field information.
1616 for (i = 0; i < top; i++) {
1617 int idx = klass->field.first + i;
1618 field = &klass->fields [i];
1620 if (!field->type) {
1621 mono_field_resolve_type (field, &error);
1622 if (!mono_error_ok (&error)) {
1623 /*mono_field_resolve_type already failed class*/
1624 mono_error_cleanup (&error);
1625 break;
1627 if (!field->type)
1628 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
1629 g_assert (field->type);
1632 if (mono_field_is_deleted (field))
1633 continue;
1634 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
1635 guint32 uoffset;
1636 mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
1637 int offset = uoffset;
1639 if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1640 mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
1641 break;
1643 if (offset < -1) { /*-1 is used to encode special static fields */
1644 mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
1645 break;
1647 if (klass->generic_container) {
1648 mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
1649 break;
1652 if (mono_type_has_exceptions (field->type)) {
1653 char *class_name = mono_type_get_full_name (klass);
1654 char *type_name = mono_type_full_name (field->type);
1656 mono_class_set_type_load_failure (klass, "");
1657 g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
1658 g_free (class_name);
1659 g_free (type_name);
1660 break;
1662 /* The def_value of fields is compute lazily during vtable creation */
1665 if (!mono_class_has_failure (klass))
1666 mono_class_layout_fields (klass, instance_size, packing_size, FALSE);
1668 init_list = g_slist_remove (init_list, klass);
1669 mono_native_tls_set_value (setup_fields_tls_id, init_list);
1673 * mono_class_has_references:
1675 * Returns whenever @klass->has_references is set, initializing it if needed.
1676 * Aquires the loader lock.
1678 static gboolean
1679 mono_class_has_references (MonoClass *klass)
1681 if (klass->init_pending) {
1682 /* Be conservative */
1683 return TRUE;
1684 } else {
1685 mono_class_init (klass);
1687 return klass->has_references;
1692 * mono_type_get_basic_type_from_generic:
1693 * @type: a type
1695 * Returns a closed type corresponding to the possibly open type
1696 * passed to it.
1698 MonoType*
1699 mono_type_get_basic_type_from_generic (MonoType *type)
1701 /* When we do generic sharing we let type variables stand for reference/primitive types. */
1702 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) &&
1703 (!type->data.generic_param->gshared_constraint || type->data.generic_param->gshared_constraint->type == MONO_TYPE_OBJECT))
1704 return &mono_defaults.object_class->byval_arg;
1705 return type;
1708 static gboolean
1709 type_has_references (MonoClass *klass, MonoType *ftype)
1711 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
1712 return TRUE;
1713 if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
1714 MonoGenericParam *gparam = ftype->data.generic_param;
1716 if (gparam->gshared_constraint)
1717 return mono_class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
1719 return FALSE;
1723 * mono_class_layout_fields:
1724 * @class: a class
1725 * @base_instance_size: base instance size
1726 * @packing_size:
1728 * This contains the common code for computing the layout of classes and sizes.
1729 * This should only be called from mono_class_setup_fields () and
1730 * typebuilder_setup_fields ().
1732 * LOCKING: Acquires the loader lock
1734 void
1735 mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, gboolean sre)
1737 int i;
1738 const int top = klass->field.count;
1739 guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
1740 guint32 pass, passes, real_size;
1741 gboolean gc_aware_layout = FALSE;
1742 gboolean has_static_fields = FALSE;
1743 gboolean has_references = FALSE;
1744 gboolean has_static_refs = FALSE;
1745 MonoClassField *field;
1746 gboolean blittable;
1747 int instance_size = base_instance_size;
1748 int class_size, min_align;
1749 int *field_offsets;
1752 * We want to avoid doing complicated work inside locks, so we compute all the required
1753 * information and write it to @klass inside a lock.
1755 if (klass->fields_inited)
1756 return;
1758 if ((packing_size & 0xffffff00) != 0) {
1759 mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
1760 return;
1763 if (klass->parent) {
1764 min_align = klass->parent->min_align;
1765 /* we use | since it may have been set already */
1766 has_references = klass->has_references | klass->parent->has_references;
1767 } else {
1768 min_align = 1;
1770 /* We can't really enable 16 bytes alignment until the GC supports it.
1771 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
1772 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
1773 Bug #506144 is an example of this issue.
1775 if (klass->simd_type)
1776 min_align = 16;
1780 * When we do generic sharing we need to have layout
1781 * information for open generic classes (either with a generic
1782 * context containing type variables or with a generic
1783 * container), so we don't return in that case anymore.
1786 if (klass->enumtype) {
1787 for (i = 0; i < top; i++) {
1788 field = &klass->fields [i];
1789 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1790 klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
1791 break;
1795 if (!mono_class_enum_basetype (klass)) {
1796 mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
1797 return;
1802 * Enable GC aware auto layout: in this mode, reference
1803 * fields are grouped together inside objects, increasing collector
1804 * performance.
1805 * Requires that all classes whose layout is known to native code be annotated
1806 * with [StructLayout (LayoutKind.Sequential)]
1807 * Value types have gc_aware_layout disabled by default, as per
1808 * what the default is for other runtimes.
1810 /* corlib is missing [StructLayout] directives in many places */
1811 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
1812 if (!klass->valuetype)
1813 gc_aware_layout = TRUE;
1816 /* Compute klass->blittable */
1817 blittable = TRUE;
1818 if (klass->parent)
1819 blittable = klass->parent->blittable;
1820 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
1821 blittable = FALSE;
1822 for (i = 0; i < top; i++) {
1823 field = &klass->fields [i];
1825 if (mono_field_is_deleted (field))
1826 continue;
1827 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1828 continue;
1829 if (blittable) {
1830 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
1831 blittable = FALSE;
1832 } else {
1833 MonoClass *field_class = mono_class_from_mono_type (field->type);
1834 if (field_class) {
1835 mono_class_setup_fields (field_class);
1836 if (mono_class_has_failure (field_class)) {
1837 MonoError field_error;
1838 mono_error_init (&field_error);
1839 mono_error_set_for_class_failure (&field_error, field_class);
1840 mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (&field_error));
1841 mono_error_cleanup (&field_error);
1842 break;
1845 if (!field_class || !field_class->blittable)
1846 blittable = FALSE;
1849 if (klass->enumtype)
1850 blittable = klass->element_class->blittable;
1852 if (mono_class_has_failure (klass))
1853 return;
1854 if (klass == mono_defaults.string_class)
1855 blittable = FALSE;
1857 /* Compute klass->has_references */
1859 * Process non-static fields first, since static fields might recursively
1860 * refer to the class itself.
1862 for (i = 0; i < top; i++) {
1863 MonoType *ftype;
1865 field = &klass->fields [i];
1867 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1868 ftype = mono_type_get_underlying_type (field->type);
1869 ftype = mono_type_get_basic_type_from_generic (ftype);
1870 if (type_has_references (klass, ftype))
1871 has_references = TRUE;
1876 * Compute field layout and total size (not considering static fields)
1878 field_offsets = g_new0 (int, top);
1879 switch (layout) {
1880 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
1881 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
1882 if (gc_aware_layout)
1883 passes = 2;
1884 else
1885 passes = 1;
1887 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
1888 passes = 1;
1890 if (klass->parent) {
1891 mono_class_setup_fields (klass->parent);
1892 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
1893 return;
1894 real_size = klass->parent->instance_size;
1895 } else {
1896 real_size = sizeof (MonoObject);
1899 for (pass = 0; pass < passes; ++pass) {
1900 for (i = 0; i < top; i++){
1901 gint32 align;
1902 guint32 size;
1903 MonoType *ftype;
1905 field = &klass->fields [i];
1907 if (mono_field_is_deleted (field))
1908 continue;
1909 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1910 continue;
1912 ftype = mono_type_get_underlying_type (field->type);
1913 ftype = mono_type_get_basic_type_from_generic (ftype);
1914 if (gc_aware_layout) {
1915 if (type_has_references (klass, ftype)) {
1916 if (pass == 1)
1917 continue;
1918 } else {
1919 if (pass == 0)
1920 continue;
1924 if ((top == 1) && (instance_size == sizeof (MonoObject)) &&
1925 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
1926 /* This field is a hack inserted by MCS to empty structures */
1927 continue;
1930 size = mono_type_size (field->type, &align);
1932 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
1933 align = packing_size ? MIN (packing_size, align): align;
1934 /* if the field has managed references, we need to force-align it
1935 * see bug #77788
1937 if (type_has_references (klass, ftype))
1938 align = MAX (align, sizeof (gpointer));
1940 min_align = MAX (align, min_align);
1941 field_offsets [i] = real_size;
1942 if (align) {
1943 field_offsets [i] += align - 1;
1944 field_offsets [i] &= ~(align - 1);
1946 /*TypeBuilders produce all sort of weird things*/
1947 g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
1948 real_size = field_offsets [i] + size;
1951 instance_size = MAX (real_size, instance_size);
1953 if (instance_size & (min_align - 1)) {
1954 instance_size += min_align - 1;
1955 instance_size &= ~(min_align - 1);
1958 break;
1959 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
1960 guint8 *ref_bitmap;
1962 real_size = 0;
1963 for (i = 0; i < top; i++) {
1964 gint32 align;
1965 guint32 size;
1966 MonoType *ftype;
1968 field = &klass->fields [i];
1971 * There must be info about all the fields in a type if it
1972 * uses explicit layout.
1974 if (mono_field_is_deleted (field))
1975 continue;
1976 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1977 continue;
1979 size = mono_type_size (field->type, &align);
1980 align = packing_size ? MIN (packing_size, align): align;
1981 min_align = MAX (align, min_align);
1983 if (sre) {
1984 /* Already set by typebuilder_setup_fields () */
1985 field_offsets [i] = field->offset + sizeof (MonoObject);
1986 } else {
1987 int idx = klass->field.first + i;
1988 guint32 offset;
1989 mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
1990 field_offsets [i] = offset + sizeof (MonoObject);
1992 ftype = mono_type_get_underlying_type (field->type);
1993 ftype = mono_type_get_basic_type_from_generic (ftype);
1994 if (type_has_references (klass, ftype)) {
1995 if (field_offsets [i] % sizeof (gpointer)) {
1996 mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
2001 * Calc max size.
2003 real_size = MAX (real_size, size + field_offsets [i]);
2006 if (klass->has_references) {
2007 ref_bitmap = g_new0 (guint8, real_size / sizeof (gpointer));
2009 /* Check for overlapping reference and non-reference fields */
2010 for (i = 0; i < top; i++) {
2011 MonoType *ftype;
2013 field = &klass->fields [i];
2015 if (mono_field_is_deleted (field))
2016 continue;
2017 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2018 continue;
2019 ftype = mono_type_get_underlying_type (field->type);
2020 if (MONO_TYPE_IS_REFERENCE (ftype))
2021 ref_bitmap [field_offsets [i] / sizeof (gpointer)] = 1;
2023 for (i = 0; i < top; i++) {
2024 field = &klass->fields [i];
2026 if (mono_field_is_deleted (field))
2027 continue;
2028 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2029 continue;
2031 // FIXME: Too much code does this
2032 #if 0
2033 if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / sizeof (gpointer)]) {
2034 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]);
2036 #endif
2038 g_free (ref_bitmap);
2041 instance_size = MAX (real_size, instance_size);
2042 if (instance_size & (min_align - 1)) {
2043 instance_size += min_align - 1;
2044 instance_size &= ~(min_align - 1);
2046 break;
2050 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
2052 * This leads to all kinds of problems with nested structs, so only
2053 * enable it when a MONO_DEBUG property is set.
2055 * For small structs, set min_align to at least the struct size to improve
2056 * performance, and since the JIT memset/memcpy code assumes this and generates
2057 * unaligned accesses otherwise. See #78990 for a testcase.
2059 if (mono_align_small_structs && top) {
2060 if (instance_size <= sizeof (MonoObject) + sizeof (gpointer))
2061 min_align = MAX (min_align, instance_size - sizeof (MonoObject));
2065 if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
2066 instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
2067 else if (klass->byval_arg.type == MONO_TYPE_PTR)
2068 instance_size = sizeof (MonoObject) + sizeof (gpointer);
2070 /* Publish the data */
2071 mono_loader_lock ();
2072 if (klass->instance_size && !klass->image->dynamic) {
2073 /* Might be already set using cached info */
2074 g_assert (klass->instance_size == instance_size);
2075 } else {
2076 klass->instance_size = instance_size;
2078 klass->blittable = blittable;
2079 klass->has_references = has_references;
2080 klass->packing_size = packing_size;
2081 klass->min_align = min_align;
2082 for (i = 0; i < top; ++i) {
2083 field = &klass->fields [i];
2084 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2085 klass->fields [i].offset = field_offsets [i];
2088 mono_memory_barrier ();
2089 klass->size_inited = 1;
2090 mono_loader_unlock ();
2093 * Compute static field layout and size
2094 * Static fields can reference the class itself, so this has to be
2095 * done after instance_size etc. are initialized.
2097 class_size = 0;
2098 for (i = 0; i < top; i++) {
2099 gint32 align;
2100 guint32 size;
2102 field = &klass->fields [i];
2104 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
2105 continue;
2106 if (mono_field_is_deleted (field))
2107 continue;
2109 if (mono_type_has_exceptions (field->type)) {
2110 mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
2111 break;
2114 has_static_fields = TRUE;
2116 size = mono_type_size (field->type, &align);
2117 field_offsets [i] = class_size;
2118 /*align is always non-zero here*/
2119 field_offsets [i] += align - 1;
2120 field_offsets [i] &= ~(align - 1);
2121 class_size = field_offsets [i] + size;
2124 if (has_static_fields && class_size == 0)
2125 /* Simplify code which depends on class_size != 0 if the class has static fields */
2126 class_size = 8;
2128 /* Compute klass->has_static_refs */
2129 has_static_refs = FALSE;
2130 for (i = 0; i < top; i++) {
2131 MonoType *ftype;
2133 field = &klass->fields [i];
2135 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2136 ftype = mono_type_get_underlying_type (field->type);
2137 ftype = mono_type_get_basic_type_from_generic (ftype);
2138 if (type_has_references (klass, ftype))
2139 has_static_refs = TRUE;
2143 /*valuetypes can't be neither bigger than 1Mb or empty. */
2144 if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
2145 mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
2147 /* Publish the data */
2148 mono_loader_lock ();
2149 if (!klass->rank)
2150 klass->sizes.class_size = class_size;
2151 klass->has_static_refs = has_static_refs;
2152 for (i = 0; i < top; ++i) {
2153 field = &klass->fields [i];
2155 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2156 field->offset = field_offsets [i];
2159 mono_memory_barrier ();
2160 klass->fields_inited = 1;
2161 mono_loader_unlock ();
2163 g_free (field_offsets);
2166 static MonoMethod*
2167 create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *sig)
2169 MonoMethod *method;
2171 method = (MonoMethod *) mono_image_alloc0 (klass->image, sizeof (MonoMethodPInvoke));
2172 method->klass = klass;
2173 method->flags = METHOD_ATTRIBUTE_PUBLIC;
2174 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
2175 method->signature = sig;
2176 method->name = name;
2177 method->slot = -1;
2178 /* .ctor */
2179 if (name [0] == '.') {
2180 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
2181 } else {
2182 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
2184 return method;
2188 * mono_class_setup_methods:
2189 * @class: a class
2191 * Initializes the 'methods' array in CLASS.
2192 * Calling this method should be avoided if possible since it allocates a lot
2193 * of long-living MonoMethod structures.
2194 * Methods belonging to an interface are assigned a sequential slot starting
2195 * from 0.
2197 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
2199 void
2200 mono_class_setup_methods (MonoClass *klass)
2202 int i, count;
2203 MonoMethod **methods;
2205 if (klass->methods)
2206 return;
2208 if (klass->generic_class) {
2209 MonoError error;
2210 MonoClass *gklass = klass->generic_class->container_class;
2212 mono_class_init (gklass);
2213 if (!mono_class_has_failure (gklass))
2214 mono_class_setup_methods (gklass);
2215 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2216 return;
2218 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
2219 count = gklass->method.count;
2220 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1));
2222 for (i = 0; i < count; i++) {
2223 methods [i] = mono_class_inflate_generic_method_full_checked (
2224 gklass->methods [i], klass, mono_class_get_context (klass), &error);
2225 if (!mono_error_ok (&error)) {
2226 char *method = mono_method_full_name (gklass->methods [i], TRUE);
2227 mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (&error));
2229 g_free (method);
2230 mono_error_cleanup (&error);
2231 return;
2234 } else if (klass->rank) {
2235 MonoError error;
2236 MonoMethod *amethod;
2237 MonoMethodSignature *sig;
2238 int count_generic = 0, first_generic = 0;
2239 int method_num = 0;
2240 gboolean jagged_ctor = FALSE;
2242 count = 3 + (klass->rank > 1? 2: 1);
2244 mono_class_setup_interfaces (klass, &error);
2245 g_assert (mono_error_ok (&error)); /*FIXME can this fail for array types?*/
2247 if (klass->rank == 1 && klass->element_class->rank) {
2248 jagged_ctor = TRUE;
2249 klass->method.count ++;
2252 if (klass->interface_count) {
2253 count_generic = generic_array_methods (klass);
2254 first_generic = count;
2255 count += klass->interface_count * count_generic;
2258 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * count);
2260 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2261 sig->ret = &mono_defaults.void_class->byval_arg;
2262 sig->pinvoke = TRUE;
2263 sig->hasthis = TRUE;
2264 for (i = 0; i < klass->rank; ++i)
2265 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2267 amethod = create_array_method (klass, ".ctor", sig);
2268 methods [method_num++] = amethod;
2269 if (klass->rank > 1) {
2270 sig = mono_metadata_signature_alloc (klass->image, klass->rank * 2);
2271 sig->ret = &mono_defaults.void_class->byval_arg;
2272 sig->pinvoke = TRUE;
2273 sig->hasthis = TRUE;
2274 for (i = 0; i < klass->rank * 2; ++i)
2275 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2277 amethod = create_array_method (klass, ".ctor", sig);
2278 methods [method_num++] = amethod;
2281 if (jagged_ctor) {
2282 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
2283 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
2284 sig->ret = &mono_defaults.void_class->byval_arg;
2285 sig->pinvoke = TRUE;
2286 sig->hasthis = TRUE;
2287 for (i = 0; i < klass->rank + 1; ++i)
2288 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2289 amethod = create_array_method (klass, ".ctor", sig);
2290 methods [method_num++] = amethod;
2293 /* element Get (idx11, [idx2, ...]) */
2294 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2295 sig->ret = &klass->element_class->byval_arg;
2296 sig->pinvoke = TRUE;
2297 sig->hasthis = TRUE;
2298 for (i = 0; i < klass->rank; ++i)
2299 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2300 amethod = create_array_method (klass, "Get", sig);
2301 methods [method_num++] = amethod;
2302 /* element& Address (idx11, [idx2, ...]) */
2303 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2304 sig->ret = &klass->element_class->this_arg;
2305 sig->pinvoke = TRUE;
2306 sig->hasthis = TRUE;
2307 for (i = 0; i < klass->rank; ++i)
2308 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2309 amethod = create_array_method (klass, "Address", sig);
2310 methods [method_num++] = amethod;
2311 /* void Set (idx11, [idx2, ...], element) */
2312 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
2313 sig->ret = &mono_defaults.void_class->byval_arg;
2314 sig->pinvoke = TRUE;
2315 sig->hasthis = TRUE;
2316 for (i = 0; i < klass->rank; ++i)
2317 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2318 sig->params [i] = &klass->element_class->byval_arg;
2319 amethod = create_array_method (klass, "Set", sig);
2320 methods [method_num++] = amethod;
2322 for (i = 0; i < klass->interface_count; i++)
2323 setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic);
2324 } else {
2325 MonoError error;
2327 count = klass->method.count;
2328 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
2329 for (i = 0; i < count; ++i) {
2330 int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, klass->method.first + i + 1);
2331 methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, &error);
2332 if (!methods [i]) {
2333 mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (&error));
2334 mono_error_cleanup (&error);
2339 if (MONO_CLASS_IS_INTERFACE (klass)) {
2340 int slot = 0;
2341 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
2342 for (i = 0; i < count; ++i) {
2343 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
2344 methods [i]->slot = slot++;
2348 mono_image_lock (klass->image);
2350 if (!klass->methods) {
2351 klass->method.count = count;
2353 /* Needed because of the double-checking locking pattern */
2354 mono_memory_barrier ();
2356 klass->methods = methods;
2359 mono_image_unlock (klass->image);
2363 * mono_class_get_method_by_index:
2365 * Returns klass->methods [index], initializing klass->methods if neccesary.
2367 * LOCKING: Acquires the loader lock.
2369 MonoMethod*
2370 mono_class_get_method_by_index (MonoClass *klass, int index)
2372 MonoError error;
2373 /* Avoid calling setup_methods () if possible */
2374 if (klass->generic_class && !klass->methods) {
2375 MonoClass *gklass = klass->generic_class->container_class;
2376 MonoMethod *m;
2378 m = mono_class_inflate_generic_method_full_checked (
2379 gklass->methods [index], klass, mono_class_get_context (klass), &error);
2380 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2382 * If setup_methods () is called later for this class, no duplicates are created,
2383 * since inflate_generic_method guarantees that only one instance of a method
2384 * is created for each context.
2387 mono_class_setup_methods (klass);
2388 g_assert (m == klass->methods [index]);
2390 return m;
2391 } else {
2392 mono_class_setup_methods (klass);
2393 if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
2394 return NULL;
2395 g_assert (index >= 0 && index < klass->method.count);
2396 return klass->methods [index];
2401 * mono_class_get_inflated_method:
2403 * Given an inflated class CLASS and a method METHOD which should be a method of
2404 * CLASS's generic definition, return the inflated method corresponding to METHOD.
2406 MonoMethod*
2407 mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method)
2409 MonoClass *gklass = klass->generic_class->container_class;
2410 int i;
2412 g_assert (method->klass == gklass);
2414 mono_class_setup_methods (gklass);
2415 g_assert (!mono_class_has_failure (gklass)); /*FIXME do proper error handling*/
2417 for (i = 0; i < gklass->method.count; ++i) {
2418 if (gklass->methods [i] == method) {
2419 if (klass->methods) {
2420 return klass->methods [i];
2421 } else {
2422 MonoError error;
2423 MonoMethod *result = mono_class_inflate_generic_method_full_checked (gklass->methods [i], klass, mono_class_get_context (klass), &error);
2424 g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
2425 return result;
2430 return NULL;
2434 * mono_class_get_vtable_entry:
2436 * Returns klass->vtable [offset], computing it if neccesary. Returns NULL on failure.
2437 * LOCKING: Acquires the loader lock.
2439 MonoMethod*
2440 mono_class_get_vtable_entry (MonoClass *klass, int offset)
2442 MonoMethod *m;
2444 if (klass->rank == 1) {
2446 * szarrays do not overwrite any methods of Array, so we can avoid
2447 * initializing their vtables in some cases.
2449 mono_class_setup_vtable (klass->parent);
2450 if (offset < klass->parent->vtable_size)
2451 return klass->parent->vtable [offset];
2454 if (klass->generic_class) {
2455 MonoError error;
2456 MonoClass *gklass = klass->generic_class->container_class;
2457 mono_class_setup_vtable (gklass);
2458 m = gklass->vtable [offset];
2460 m = mono_class_inflate_generic_method_full_checked (m, klass, mono_class_get_context (klass), &error);
2461 g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
2462 } else {
2463 mono_class_setup_vtable (klass);
2464 if (mono_class_has_failure (klass))
2465 return NULL;
2466 m = klass->vtable [offset];
2469 return m;
2473 * mono_class_get_vtable_size:
2475 * Return the vtable size for KLASS.
2478 mono_class_get_vtable_size (MonoClass *klass)
2480 mono_class_setup_vtable (klass);
2482 return klass->vtable_size;
2486 * mono_class_setup_properties:
2488 * Initialize klass->ext.property and klass->ext.properties.
2490 * This method can fail the class.
2492 static void
2493 mono_class_setup_properties (MonoClass *klass)
2495 guint startm, endm, i, j;
2496 guint32 cols [MONO_PROPERTY_SIZE];
2497 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
2498 MonoProperty *properties;
2499 guint32 last;
2500 int first, count;
2502 if (klass->ext && klass->ext->properties)
2503 return;
2505 if (klass->generic_class) {
2506 MonoClass *gklass = klass->generic_class->container_class;
2508 mono_class_init (gklass);
2509 mono_class_setup_properties (gklass);
2510 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2511 return;
2513 properties = mono_class_new0 (klass, MonoProperty, gklass->ext->property.count + 1);
2515 for (i = 0; i < gklass->ext->property.count; i++) {
2516 MonoError error;
2517 MonoProperty *prop = &properties [i];
2519 *prop = gklass->ext->properties [i];
2521 if (prop->get)
2522 prop->get = mono_class_inflate_generic_method_full_checked (
2523 prop->get, klass, mono_class_get_context (klass), &error);
2524 if (prop->set)
2525 prop->set = mono_class_inflate_generic_method_full_checked (
2526 prop->set, klass, mono_class_get_context (klass), &error);
2528 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2529 prop->parent = klass;
2532 first = gklass->ext->property.first;
2533 count = gklass->ext->property.count;
2534 } else {
2535 first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
2536 count = last - first;
2538 if (count) {
2539 mono_class_setup_methods (klass);
2540 if (mono_class_has_failure (klass))
2541 return;
2544 properties = (MonoProperty *)mono_class_alloc0 (klass, sizeof (MonoProperty) * count);
2545 for (i = first; i < last; ++i) {
2546 mono_metadata_decode_table_row (klass->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
2547 properties [i - first].parent = klass;
2548 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
2549 properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
2551 startm = mono_metadata_methods_from_property (klass->image, i, &endm);
2552 for (j = startm; j < endm; ++j) {
2553 MonoMethod *method;
2555 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2557 if (klass->image->uncompressed_metadata) {
2558 MonoError error;
2559 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2560 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
2561 mono_error_cleanup (&error); /* FIXME don't swallow this error */
2562 } else {
2563 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first];
2566 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2567 case METHOD_SEMANTIC_SETTER:
2568 properties [i - first].set = method;
2569 break;
2570 case METHOD_SEMANTIC_GETTER:
2571 properties [i - first].get = method;
2572 break;
2573 default:
2574 break;
2580 mono_class_alloc_ext (klass);
2582 mono_image_lock (klass->image);
2584 if (klass->ext->properties) {
2585 /* We leak 'properties' which was allocated from the image mempool */
2586 mono_image_unlock (klass->image);
2587 return;
2590 klass->ext->property.first = first;
2591 klass->ext->property.count = count;
2593 /* Flush any pending writes as we do double checked locking on klass->ext->properties */
2594 mono_memory_barrier ();
2596 /* Leave this assignment as the last op in the function */
2597 klass->ext->properties = properties;
2599 mono_image_unlock (klass->image);
2602 static MonoMethod**
2603 inflate_method_listz (MonoMethod **methods, MonoClass *klass, MonoGenericContext *context)
2605 MonoMethod **om, **retval;
2606 int count;
2608 for (om = methods, count = 0; *om; ++om, ++count)
2611 retval = g_new0 (MonoMethod*, count + 1);
2612 count = 0;
2613 for (om = methods, count = 0; *om; ++om, ++count) {
2614 MonoError error;
2615 retval [count] = mono_class_inflate_generic_method_full_checked (*om, klass, context, &error);
2616 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2619 return retval;
2622 /*This method can fail the class.*/
2623 static void
2624 mono_class_setup_events (MonoClass *klass)
2626 int first, count;
2627 guint startm, endm, i, j;
2628 guint32 cols [MONO_EVENT_SIZE];
2629 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
2630 guint32 last;
2631 MonoEvent *events;
2633 if (klass->ext && klass->ext->events)
2634 return;
2636 if (klass->generic_class) {
2637 MonoClass *gklass = klass->generic_class->container_class;
2638 MonoGenericContext *context = NULL;
2640 mono_class_setup_events (gklass);
2641 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2642 return;
2644 first = gklass->ext->event.first;
2645 count = gklass->ext->event.count;
2647 events = mono_class_new0 (klass, MonoEvent, count);
2649 if (count)
2650 context = mono_class_get_context (klass);
2652 for (i = 0; i < count; i++) {
2653 MonoError error;
2654 MonoEvent *event = &events [i];
2655 MonoEvent *gevent = &gklass->ext->events [i];
2657 mono_error_init (&error); //since we do conditional calls, we must ensure the default value is ok
2659 event->parent = klass;
2660 event->name = gevent->name;
2661 event->add = gevent->add ? mono_class_inflate_generic_method_full_checked (gevent->add, klass, context, &error) : NULL;
2662 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2663 event->remove = gevent->remove ? mono_class_inflate_generic_method_full_checked (gevent->remove, klass, context, &error) : NULL;
2664 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2665 event->raise = gevent->raise ? mono_class_inflate_generic_method_full_checked (gevent->raise, klass, context, &error) : NULL;
2666 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2668 #ifndef MONO_SMALL_CONFIG
2669 event->other = gevent->other ? inflate_method_listz (gevent->other, klass, context) : NULL;
2670 #endif
2671 event->attrs = gevent->attrs;
2673 } else {
2674 first = mono_metadata_events_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
2675 count = last - first;
2677 if (count) {
2678 mono_class_setup_methods (klass);
2679 if (mono_class_has_failure (klass)) {
2680 return;
2684 events = (MonoEvent *)mono_class_alloc0 (klass, sizeof (MonoEvent) * count);
2685 for (i = first; i < last; ++i) {
2686 MonoEvent *event = &events [i - first];
2688 mono_metadata_decode_table_row (klass->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
2689 event->parent = klass;
2690 event->attrs = cols [MONO_EVENT_FLAGS];
2691 event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
2693 startm = mono_metadata_methods_from_event (klass->image, i, &endm);
2694 for (j = startm; j < endm; ++j) {
2695 MonoMethod *method;
2697 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2699 if (klass->image->uncompressed_metadata) {
2700 MonoError error;
2701 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2702 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
2703 mono_error_cleanup (&error); /* FIXME don't swallow this error */
2704 } else {
2705 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first];
2708 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2709 case METHOD_SEMANTIC_ADD_ON:
2710 event->add = method;
2711 break;
2712 case METHOD_SEMANTIC_REMOVE_ON:
2713 event->remove = method;
2714 break;
2715 case METHOD_SEMANTIC_FIRE:
2716 event->raise = method;
2717 break;
2718 case METHOD_SEMANTIC_OTHER: {
2719 #ifndef MONO_SMALL_CONFIG
2720 int n = 0;
2722 if (event->other == NULL) {
2723 event->other = g_new0 (MonoMethod*, 2);
2724 } else {
2725 while (event->other [n])
2726 n++;
2727 event->other = (MonoMethod **)g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
2729 event->other [n] = method;
2730 /* NULL terminated */
2731 event->other [n + 1] = NULL;
2732 #endif
2733 break;
2735 default:
2736 break;
2742 mono_class_alloc_ext (klass);
2744 mono_image_lock (klass->image);
2746 if (klass->ext->events) {
2747 mono_image_unlock (klass->image);
2748 return;
2751 klass->ext->event.first = first;
2752 klass->ext->event.count = count;
2754 /* Flush any pending writes as we do double checked locking on klass->ext.events */
2755 mono_memory_barrier ();
2757 /* Leave this assignment as the last op in the function */
2758 klass->ext->events = events;
2760 mono_image_unlock (klass->image);
2764 * Global pool of interface IDs, represented as a bitset.
2765 * LOCKING: Protected by the classes lock.
2767 static MonoBitSet *global_interface_bitset = NULL;
2770 * mono_unload_interface_ids:
2771 * @bitset: bit set of interface IDs
2773 * When an image is unloaded, the interface IDs associated with
2774 * the image are put back in the global pool of IDs so the numbers
2775 * can be reused.
2777 void
2778 mono_unload_interface_ids (MonoBitSet *bitset)
2780 classes_lock ();
2781 mono_bitset_sub (global_interface_bitset, bitset);
2782 classes_unlock ();
2785 void
2786 mono_unload_interface_id (MonoClass *klass)
2788 if (global_interface_bitset && klass->interface_id) {
2789 classes_lock ();
2790 mono_bitset_clear (global_interface_bitset, klass->interface_id);
2791 classes_unlock ();
2796 * mono_get_unique_iid:
2797 * @class: interface
2799 * Assign a unique integer ID to the interface represented by @class.
2800 * The ID will positive and as small as possible.
2801 * LOCKING: Acquires the classes lock.
2802 * Returns: The new ID.
2804 static guint
2805 mono_get_unique_iid (MonoClass *klass)
2807 int iid;
2809 g_assert (MONO_CLASS_IS_INTERFACE (klass));
2811 classes_lock ();
2813 if (!global_interface_bitset) {
2814 global_interface_bitset = mono_bitset_new (128, 0);
2817 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
2818 if (iid < 0) {
2819 int old_size = mono_bitset_size (global_interface_bitset);
2820 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
2821 mono_bitset_free (global_interface_bitset);
2822 global_interface_bitset = new_set;
2823 iid = old_size;
2825 mono_bitset_set (global_interface_bitset, iid);
2826 /* set the bit also in the per-image set */
2827 if (!klass->generic_class) {
2828 if (klass->image->interface_bitset) {
2829 if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
2830 MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
2831 mono_bitset_free (klass->image->interface_bitset);
2832 klass->image->interface_bitset = new_set;
2834 } else {
2835 klass->image->interface_bitset = mono_bitset_new (iid + 1, 0);
2837 mono_bitset_set (klass->image->interface_bitset, iid);
2840 classes_unlock ();
2842 #ifndef MONO_SMALL_CONFIG
2843 if (mono_print_vtable) {
2844 int generic_id;
2845 char *type_name = mono_type_full_name (&klass->byval_arg);
2846 if (klass->generic_class && !klass->generic_class->context.class_inst->is_open) {
2847 generic_id = klass->generic_class->context.class_inst->id;
2848 g_assert (generic_id != 0);
2849 } else {
2850 generic_id = 0;
2852 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->name, type_name, generic_id);
2853 g_free (type_name);
2855 #endif
2857 g_assert (iid <= 65535);
2858 return iid;
2861 static void
2862 collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, MonoError *error)
2864 int i;
2865 MonoClass *ic;
2867 mono_class_setup_interfaces (klass, error);
2868 return_if_nok (error);
2870 for (i = 0; i < klass->interface_count; i++) {
2871 ic = klass->interfaces [i];
2873 if (*res == NULL)
2874 *res = g_ptr_array_new ();
2875 g_ptr_array_add (*res, ic);
2876 mono_class_init (ic);
2877 if (mono_class_has_failure (ic)) {
2878 mono_error_set_type_load_class (error, ic, "Error Loading class");
2879 return;
2882 collect_implemented_interfaces_aux (ic, res, error);
2883 return_if_nok (error);
2887 GPtrArray*
2888 mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error)
2890 GPtrArray *res = NULL;
2892 collect_implemented_interfaces_aux (klass, &res, error);
2893 if (!mono_error_ok (error)) {
2894 if (res)
2895 g_ptr_array_free (res, TRUE);
2896 return NULL;
2898 return res;
2901 static int
2902 compare_interface_ids (const void *p_key, const void *p_element) {
2903 const MonoClass *key = (const MonoClass *)p_key;
2904 const MonoClass *element = *(const MonoClass **)p_element;
2906 return (key->interface_id - element->interface_id);
2909 /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/
2911 mono_class_interface_offset (MonoClass *klass, MonoClass *itf) {
2912 MonoClass **result = (MonoClass **)mono_binary_search (
2913 itf,
2914 klass->interfaces_packed,
2915 klass->interface_offsets_count,
2916 sizeof (MonoClass *),
2917 compare_interface_ids);
2918 if (result) {
2919 return klass->interface_offsets_packed [result - (klass->interfaces_packed)];
2920 } else {
2921 return -1;
2926 * mono_class_interface_offset_with_variance:
2928 * Return the interface offset of @itf in @klass. Sets @non_exact_match to TRUE if the match required variance check
2929 * If @itf is an interface with generic variant arguments, try to find the compatible one.
2931 * Note that this function is responsible for resolving ambiguities. Right now we use whatever ordering interfaces_packed gives us.
2933 * FIXME figure out MS disambiguation rules and fix this function.
2936 mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match) {
2937 int i = mono_class_interface_offset (klass, itf);
2938 *non_exact_match = FALSE;
2939 if (i >= 0)
2940 return i;
2942 if (!mono_class_has_variant_generic_params (itf))
2943 return -1;
2945 for (i = 0; i < klass->interface_offsets_count; i++) {
2946 if (mono_class_is_variant_compatible (itf, klass->interfaces_packed [i], FALSE)) {
2947 *non_exact_match = TRUE;
2948 return klass->interface_offsets_packed [i];
2952 return -1;
2955 static void
2956 print_implemented_interfaces (MonoClass *klass) {
2957 char *name;
2958 MonoError error;
2959 GPtrArray *ifaces = NULL;
2960 int i;
2961 int ancestor_level = 0;
2963 name = mono_type_get_full_name (klass);
2964 printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
2965 g_free (name);
2967 for (i = 0; i < klass->interface_offsets_count; i++)
2968 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
2969 klass->interfaces_packed [i]->interface_id,
2970 klass->interface_offsets_packed [i],
2971 klass->interfaces_packed [i]->method.count,
2972 klass->interfaces_packed [i]->name_space,
2973 klass->interfaces_packed [i]->name );
2974 printf ("Interface flags: ");
2975 for (i = 0; i <= klass->max_interface_id; i++)
2976 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
2977 printf ("(%d,T)", i);
2978 else
2979 printf ("(%d,F)", i);
2980 printf ("\n");
2981 printf ("Dump interface flags:");
2982 #ifdef COMPRESSED_INTERFACE_BITMAP
2984 const uint8_t* p = klass->interface_bitmap;
2985 i = klass->max_interface_id;
2986 while (i > 0) {
2987 printf (" %d x 00 %02X", p [0], p [1]);
2988 i -= p [0] * 8;
2989 i -= 8;
2992 #else
2993 for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
2994 printf (" %02X", klass->interface_bitmap [i]);
2995 #endif
2996 printf ("\n");
2997 while (klass != NULL) {
2998 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
2999 ifaces = mono_class_get_implemented_interfaces (klass, &error);
3000 if (!mono_error_ok (&error)) {
3001 printf (" Type failed due to %s\n", mono_error_get_message (&error));
3002 mono_error_cleanup (&error);
3003 } else if (ifaces) {
3004 for (i = 0; i < ifaces->len; i++) {
3005 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3006 printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
3007 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
3008 ic->interface_id,
3009 mono_class_interface_offset (klass, ic),
3010 ic->method.count,
3011 ic->name_space,
3012 ic->name );
3014 g_ptr_array_free (ifaces, TRUE);
3016 ancestor_level ++;
3017 klass = klass->parent;
3021 static MonoClass*
3022 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
3024 MonoType *args [1];
3025 args [0] = &arg0->byval_arg;
3027 return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
3030 static MonoClass*
3031 array_class_get_if_rank (MonoClass *klass, guint rank)
3033 return rank ? mono_array_class_get (klass, rank) : klass;
3036 static void
3037 fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *eclass, int rank)
3039 valuetype_types [0] = eclass;
3040 if (eclass == mono_defaults.int16_class)
3041 valuetype_types [1] = mono_defaults.uint16_class;
3042 else if (eclass == mono_defaults.uint16_class)
3043 valuetype_types [1] = mono_defaults.int16_class;
3044 else if (eclass == mono_defaults.int32_class)
3045 valuetype_types [1] = mono_defaults.uint32_class;
3046 else if (eclass == mono_defaults.uint32_class)
3047 valuetype_types [1] = mono_defaults.int32_class;
3048 else if (eclass == mono_defaults.int64_class)
3049 valuetype_types [1] = mono_defaults.uint64_class;
3050 else if (eclass == mono_defaults.uint64_class)
3051 valuetype_types [1] = mono_defaults.int64_class;
3052 else if (eclass == mono_defaults.byte_class)
3053 valuetype_types [1] = mono_defaults.sbyte_class;
3054 else if (eclass == mono_defaults.sbyte_class)
3055 valuetype_types [1] = mono_defaults.byte_class;
3056 else if (eclass->enumtype && mono_class_enum_basetype (eclass))
3057 valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass));
3060 /* this won't be needed once bug #325495 is completely fixed
3061 * though we'll need something similar to know which interfaces to allow
3062 * in arrays when they'll be lazyly created
3064 * FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
3065 * MS returns diferrent types based on which instance is called. For example:
3066 * object obj = new byte[10][];
3067 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
3068 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
3069 * a != b ==> true
3071 * Fixing this should kill quite some code, save some bits and improve compatibility.
3073 static MonoClass**
3074 get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enumerator)
3076 MonoClass *eclass = klass->element_class;
3077 static MonoClass* generic_icollection_class = NULL;
3078 static MonoClass* generic_ienumerable_class = NULL;
3079 static MonoClass* generic_ienumerator_class = NULL;
3080 static MonoClass* generic_ireadonlylist_class = NULL;
3081 static MonoClass* generic_ireadonlycollection_class = NULL;
3082 MonoClass *valuetype_types[2] = { NULL, NULL };
3083 MonoClass **interfaces = NULL;
3084 int i, nifaces, interface_count, real_count, original_rank;
3085 int all_interfaces;
3086 gboolean internal_enumerator;
3087 gboolean eclass_is_valuetype;
3089 if (!mono_defaults.generic_ilist_class) {
3090 *num = 0;
3091 return NULL;
3093 internal_enumerator = FALSE;
3094 eclass_is_valuetype = FALSE;
3095 original_rank = eclass->rank;
3096 if (klass->byval_arg.type != MONO_TYPE_SZARRAY) {
3097 if (klass->generic_class && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0) {
3099 * For a Enumerator<T[]> we need to get the list of interfaces for T.
3101 eclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
3102 original_rank = eclass->rank;
3103 if (!eclass->rank)
3104 eclass = eclass->element_class;
3105 internal_enumerator = TRUE;
3106 *is_enumerator = TRUE;
3107 } else {
3108 *num = 0;
3109 return NULL;
3114 * with this non-lazy impl we can't implement all the interfaces so we do just the minimal stuff
3115 * for deep levels of arrays of arrays (string[][] has all the interfaces, string[][][] doesn't)
3117 all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
3119 if (!generic_icollection_class) {
3120 generic_icollection_class = mono_class_load_from_name (mono_defaults.corlib,
3121 "System.Collections.Generic", "ICollection`1");
3122 generic_ienumerable_class = mono_class_load_from_name (mono_defaults.corlib,
3123 "System.Collections.Generic", "IEnumerable`1");
3124 generic_ienumerator_class = mono_class_load_from_name (mono_defaults.corlib,
3125 "System.Collections.Generic", "IEnumerator`1");
3126 generic_ireadonlylist_class = mono_class_load_from_name (mono_defaults.corlib,
3127 "System.Collections.Generic", "IReadOnlyList`1");
3128 generic_ireadonlycollection_class = mono_class_load_from_name (mono_defaults.corlib,
3129 "System.Collections.Generic", "IReadOnlyCollection`1");
3132 mono_class_init (eclass);
3135 * Arrays in 2.0 need to implement a number of generic interfaces
3136 * (IList`1, ICollection`1, IEnumerable`1 for a number of types depending
3137 * on the element class). For net 4.5, we also need to implement IReadOnlyList`1/IReadOnlyCollection`1.
3138 * We collect the types needed to build the
3139 * instantiations in interfaces at intervals of 3/5, because 3/5 are
3140 * the generic interfaces needed to implement.
3142 * On 4.5, as an optimization, we don't expand ref classes for the variant generic interfaces
3143 * (IEnumerator, IReadOnlyList and IReadOnlyColleciton). The regular dispatch code can handle those cases.
3145 if (eclass->valuetype) {
3146 nifaces = generic_ireadonlylist_class ? 5 : 3;
3147 fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank);
3149 /* IList, ICollection, IEnumerable, IReadOnlyList`1 */
3150 real_count = interface_count = valuetype_types [1] ? (nifaces * 2) : nifaces;
3151 if (internal_enumerator) {
3152 ++real_count;
3153 if (valuetype_types [1])
3154 ++real_count;
3157 interfaces = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * real_count);
3158 interfaces [0] = valuetype_types [0];
3159 if (valuetype_types [1])
3160 interfaces [nifaces] = valuetype_types [1];
3162 eclass_is_valuetype = TRUE;
3163 } else {
3164 int j;
3165 int idepth = eclass->idepth;
3166 if (!internal_enumerator)
3167 idepth--;
3168 nifaces = generic_ireadonlylist_class ? 2 : 3;
3170 // FIXME: This doesn't seem to work/required for generic params
3171 if (!(eclass->this_arg.type == MONO_TYPE_VAR || eclass->this_arg.type == MONO_TYPE_MVAR || (image_is_dynamic (eclass->image) && !eclass->wastypebuilder)))
3172 mono_class_setup_interface_offsets (eclass);
3174 interface_count = all_interfaces? eclass->interface_offsets_count: eclass->interface_count;
3175 /* we add object for interfaces and the supertypes for the other
3176 * types. The last of the supertypes is the element class itself which we
3177 * already created the explicit interfaces for (so we include it for IEnumerator
3178 * and exclude it for arrays).
3180 if (MONO_CLASS_IS_INTERFACE (eclass))
3181 interface_count++;
3182 else
3183 interface_count += idepth;
3184 if (eclass->rank && eclass->element_class->valuetype) {
3185 fill_valuetype_array_derived_types (valuetype_types, eclass->element_class, original_rank);
3186 if (valuetype_types [1])
3187 ++interface_count;
3189 /* IList, ICollection, IEnumerable, IReadOnlyList */
3190 interface_count *= nifaces;
3191 real_count = interface_count;
3192 if (internal_enumerator) {
3193 real_count += (MONO_CLASS_IS_INTERFACE (eclass) ? 1 : idepth) + eclass->interface_offsets_count;
3194 if (valuetype_types [1])
3195 ++real_count;
3197 interfaces = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * real_count);
3198 if (MONO_CLASS_IS_INTERFACE (eclass)) {
3199 interfaces [0] = mono_defaults.object_class;
3200 j = nifaces;
3201 } else {
3202 j = 0;
3203 for (i = 0; i < idepth; i++) {
3204 mono_class_init (eclass->supertypes [i]);
3205 interfaces [j] = eclass->supertypes [i];
3206 j += nifaces;
3209 if (all_interfaces) {
3210 for (i = 0; i < eclass->interface_offsets_count; i++) {
3211 interfaces [j] = eclass->interfaces_packed [i];
3212 j += nifaces;
3214 } else {
3215 for (i = 0; i < eclass->interface_count; i++) {
3216 interfaces [j] = eclass->interfaces [i];
3217 j += nifaces;
3220 if (valuetype_types [1]) {
3221 interfaces [j] = array_class_get_if_rank (valuetype_types [1], original_rank);
3222 j += nifaces;
3226 /* instantiate the generic interfaces */
3227 for (i = 0; i < interface_count; i += nifaces) {
3228 MonoClass *iface = interfaces [i];
3230 interfaces [i + 0] = inflate_class_one_arg (mono_defaults.generic_ilist_class, iface);
3231 interfaces [i + 1] = inflate_class_one_arg (generic_icollection_class, iface);
3233 if (eclass->valuetype) {
3234 interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
3235 if (generic_ireadonlylist_class) {
3236 interfaces [i + 3] = inflate_class_one_arg (generic_ireadonlylist_class, iface);
3237 interfaces [i + 4] = inflate_class_one_arg (generic_ireadonlycollection_class, iface);
3239 } else {
3240 if (!generic_ireadonlylist_class)
3241 interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
3244 if (internal_enumerator) {
3245 int j;
3246 /* instantiate IEnumerator<iface> */
3247 for (i = 0; i < interface_count; i++) {
3248 interfaces [i] = inflate_class_one_arg (generic_ienumerator_class, interfaces [i]);
3250 j = interface_count;
3251 if (!eclass_is_valuetype) {
3252 if (MONO_CLASS_IS_INTERFACE (eclass)) {
3253 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, mono_defaults.object_class);
3254 j ++;
3255 } else {
3256 for (i = 0; i < eclass->idepth; i++) {
3257 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->supertypes [i]);
3258 j ++;
3261 for (i = 0; i < eclass->interface_offsets_count; i++) {
3262 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->interfaces_packed [i]);
3263 j ++;
3265 } else {
3266 interfaces [j++] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [0], original_rank));
3268 if (valuetype_types [1])
3269 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [1], original_rank));
3271 #if 0
3273 char *type_name = mono_type_get_name_full (&klass->byval_arg, 0);
3274 for (i = 0; i < real_count; ++i) {
3275 char *name = mono_type_get_name_full (&interfaces [i]->byval_arg, 0);
3276 g_print ("%s implements %s\n", type_name, name);
3277 g_free (name);
3279 g_free (type_name);
3281 #endif
3282 *num = real_count;
3283 return interfaces;
3286 static int
3287 find_array_interface (MonoClass *klass, const char *name)
3289 int i;
3290 for (i = 0; i < klass->interface_count; ++i) {
3291 if (strcmp (klass->interfaces [i]->name, name) == 0)
3292 return i;
3294 return -1;
3298 * Return the number of virtual methods.
3299 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
3300 * Return -1 on failure.
3301 * FIXME It would be nice if this information could be cached somewhere.
3303 static int
3304 count_virtual_methods (MonoClass *klass)
3306 int i, count = 0;
3307 guint32 flags;
3308 klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/
3310 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
3311 mono_class_setup_methods (klass);
3312 if (mono_class_has_failure (klass))
3313 return -1;
3315 for (i = 0; i < klass->method.count; ++i) {
3316 flags = klass->methods [i]->flags;
3317 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3318 ++count;
3320 } else {
3321 for (i = 0; i < klass->method.count; ++i) {
3322 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
3324 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3325 ++count;
3328 return count;
3331 static int
3332 find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic)
3334 int m, l = 0;
3335 if (!num_ifaces)
3336 return -1;
3337 while (1) {
3338 if (l > num_ifaces)
3339 return -1;
3340 m = (l + num_ifaces) / 2;
3341 if (interfaces_full [m] == ic)
3342 return m;
3343 if (l == num_ifaces)
3344 return -1;
3345 if (!interfaces_full [m] || interfaces_full [m]->interface_id > ic->interface_id) {
3346 num_ifaces = m - 1;
3347 } else {
3348 l = m + 1;
3353 static int
3354 find_interface_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic)
3356 int i = find_interface (num_ifaces, interfaces_full, ic);
3357 if (i >= 0)
3358 return interface_offsets_full [i];
3359 return -1;
3362 static mono_bool
3363 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
3365 int i = find_interface (num_ifaces, interfaces_full, ic);
3366 if (i >= 0) {
3367 if (!force_set)
3368 return TRUE;
3369 interface_offsets_full [i] = offset;
3370 return FALSE;
3372 for (i = 0; i < num_ifaces; ++i) {
3373 if (interfaces_full [i]) {
3374 int end;
3375 if (interfaces_full [i]->interface_id < ic->interface_id)
3376 continue;
3377 end = i + 1;
3378 while (end < num_ifaces && interfaces_full [end]) end++;
3379 memmove (interfaces_full + i + 1, interfaces_full + i, sizeof (MonoClass*) * (end - i));
3380 memmove (interface_offsets_full + i + 1, interface_offsets_full + i, sizeof (int) * (end - i));
3382 interfaces_full [i] = ic;
3383 interface_offsets_full [i] = offset;
3384 break;
3386 return FALSE;
3389 #ifdef COMPRESSED_INTERFACE_BITMAP
3392 * Compressed interface bitmap design.
3394 * Interface bitmaps take a large amount of memory, because their size is
3395 * linear with the maximum interface id assigned in the process (each interface
3396 * is assigned a unique id as it is loaded). The number of interface classes
3397 * is high because of the many implicit interfaces implemented by arrays (we'll
3398 * need to lazy-load them in the future).
3399 * Most classes implement a very small number of interfaces, so the bitmap is
3400 * sparse. This bitmap needs to be checked by interface casts, so access to the
3401 * needed bit must be fast and doable with few jit instructions.
3403 * The current compression format is as follows:
3404 * *) it is a sequence of one or more two-byte elements
3405 * *) the first byte in the element is the count of empty bitmap bytes
3406 * at the current bitmap position
3407 * *) the second byte in the element is an actual bitmap byte at the current
3408 * bitmap position
3410 * As an example, the following compressed bitmap bytes:
3411 * 0x07 0x01 0x00 0x7
3412 * correspond to the following bitmap:
3413 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
3415 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
3416 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
3417 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
3421 * mono_compress_bitmap:
3422 * @dest: destination buffer
3423 * @bitmap: bitmap buffer
3424 * @size: size of @bitmap in bytes
3426 * This is a mono internal function.
3427 * The @bitmap data is compressed into a format that is small but
3428 * still searchable in few instructions by the JIT and runtime.
3429 * The compressed data is stored in the buffer pointed to by the
3430 * @dest array. Passing a #NULL value for @dest allows to just compute
3431 * the size of the buffer.
3432 * This compression algorithm assumes the bits set in the bitmap are
3433 * few and far between, like in interface bitmaps.
3434 * Returns: The size of the compressed bitmap in bytes.
3437 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
3439 int numz = 0;
3440 int res = 0;
3441 const uint8_t *end = bitmap + size;
3442 while (bitmap < end) {
3443 if (*bitmap || numz == 255) {
3444 if (dest) {
3445 *dest++ = numz;
3446 *dest++ = *bitmap;
3448 res += 2;
3449 numz = 0;
3450 bitmap++;
3451 continue;
3453 bitmap++;
3454 numz++;
3456 if (numz) {
3457 res += 2;
3458 if (dest) {
3459 *dest++ = numz;
3460 *dest++ = 0;
3463 return res;
3467 * mono_class_interface_match:
3468 * @bitmap: a compressed bitmap buffer
3469 * @id: the index to check in the bitmap
3471 * This is a mono internal function.
3472 * Checks if a bit is set in a compressed interface bitmap. @id must
3473 * be already checked for being smaller than the maximum id encoded in the
3474 * bitmap.
3476 * Returns: A non-zero value if bit @id is set in the bitmap @bitmap,
3477 * #FALSE otherwise.
3480 mono_class_interface_match (const uint8_t *bitmap, int id)
3482 while (TRUE) {
3483 id -= bitmap [0] * 8;
3484 if (id < 8) {
3485 if (id < 0)
3486 return 0;
3487 return bitmap [1] & (1 << id);
3489 bitmap += 2;
3490 id -= 8;
3493 #endif
3496 * LOCKING: this is supposed to be called with the loader lock held.
3497 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
3499 static int
3500 setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
3502 MonoError error;
3503 MonoClass *k, *ic;
3504 int i, j, max_iid, num_ifaces;
3505 MonoClass **interfaces_full = NULL;
3506 int *interface_offsets_full = NULL;
3507 GPtrArray *ifaces;
3508 GPtrArray **ifaces_array = NULL;
3509 int interface_offsets_count;
3510 MonoClass **array_interfaces = NULL;
3511 int num_array_interfaces;
3512 int is_enumerator = FALSE;
3514 mono_class_setup_supertypes (klass);
3516 * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator<T>
3517 * implicit interfaces have the property that they are assigned the same slot in the
3518 * vtables for compatible interfaces
3520 array_interfaces = get_implicit_generic_array_interfaces (klass, &num_array_interfaces, &is_enumerator);
3522 /* compute maximum number of slots and maximum interface id */
3523 max_iid = 0;
3524 num_ifaces = num_array_interfaces; /* this can include duplicated ones */
3525 ifaces_array = g_new0 (GPtrArray *, klass->idepth);
3526 for (j = 0; j < klass->idepth; j++) {
3527 k = klass->supertypes [j];
3528 num_ifaces += k->interface_count;
3529 for (i = 0; i < k->interface_count; i++) {
3530 ic = k->interfaces [i];
3532 if (!ic->inited)
3533 mono_class_init (ic);
3535 if (max_iid < ic->interface_id)
3536 max_iid = ic->interface_id;
3538 ifaces = mono_class_get_implemented_interfaces (k, &error);
3539 if (!mono_error_ok (&error)) {
3540 char *name = mono_type_get_full_name (k);
3541 mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error));
3542 g_free (name);
3543 mono_error_cleanup (&error);
3544 cur_slot = -1;
3545 goto end;
3547 if (ifaces) {
3548 num_ifaces += ifaces->len;
3549 for (i = 0; i < ifaces->len; ++i) {
3550 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3551 if (max_iid < ic->interface_id)
3552 max_iid = ic->interface_id;
3554 ifaces_array [j] = ifaces;
3558 for (i = 0; i < num_array_interfaces; ++i) {
3559 ic = array_interfaces [i];
3560 mono_class_init (ic);
3561 if (max_iid < ic->interface_id)
3562 max_iid = ic->interface_id;
3565 if (MONO_CLASS_IS_INTERFACE (klass)) {
3566 num_ifaces++;
3567 if (max_iid < klass->interface_id)
3568 max_iid = klass->interface_id;
3570 klass->max_interface_id = max_iid;
3571 /* compute vtable offset for interfaces */
3572 interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
3573 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
3575 for (i = 0; i < num_ifaces; i++) {
3576 interface_offsets_full [i] = -1;
3579 /* skip the current class */
3580 for (j = 0; j < klass->idepth - 1; j++) {
3581 k = klass->supertypes [j];
3582 ifaces = ifaces_array [j];
3584 if (ifaces) {
3585 for (i = 0; i < ifaces->len; ++i) {
3586 int io;
3587 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3589 /*Force the sharing of interface offsets between parent and subtypes.*/
3590 io = mono_class_interface_offset (k, ic);
3591 g_assert (io >= 0);
3592 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
3597 g_assert (klass == klass->supertypes [klass->idepth - 1]);
3598 ifaces = ifaces_array [klass->idepth - 1];
3599 if (ifaces) {
3600 for (i = 0; i < ifaces->len; ++i) {
3601 int count;
3602 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3603 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
3604 continue;
3605 count = count_virtual_methods (ic);
3606 if (count == -1) {
3607 char *name = mono_type_get_full_name (ic);
3608 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
3609 g_free (name);
3610 cur_slot = -1;
3611 goto end;
3613 cur_slot += count;
3617 if (MONO_CLASS_IS_INTERFACE (klass))
3618 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE);
3620 if (num_array_interfaces) {
3621 if (is_enumerator) {
3622 int ienumerator_idx = find_array_interface (klass, "IEnumerator`1");
3623 int ienumerator_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ienumerator_idx]);
3624 g_assert (ienumerator_offset >= 0);
3625 for (i = 0; i < num_array_interfaces; ++i) {
3626 ic = array_interfaces [i];
3627 if (strcmp (ic->name, "IEnumerator`1") == 0)
3628 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, ienumerator_offset, TRUE);
3629 else
3630 g_assert_not_reached ();
3631 /*g_print ("type %s has %s offset at %d (%s)\n", klass->name, ic->name, interface_offsets_full [ic->interface_id], klass->interfaces [0]->name);*/
3633 } else {
3634 int ilist_offset, icollection_offset, ienumerable_offset, ireadonlylist_offset, ireadonlycollection_offset;
3635 int ilist_iface_idx = find_array_interface (klass, "IList`1");
3636 MonoClass* ilist_class = klass->interfaces [ilist_iface_idx];
3637 int ireadonlylist_iface_idx = find_array_interface (klass, "IReadOnlyList`1");
3638 MonoClass* ireadonlylist_class = ireadonlylist_iface_idx != -1 ? klass->interfaces [ireadonlylist_iface_idx] : NULL;
3639 int icollection_iface_idx = find_array_interface (ilist_class, "ICollection`1");
3640 int ienumerable_iface_idx = find_array_interface (ilist_class, "IEnumerable`1");
3641 int ireadonlycollection_iface_idx = ireadonlylist_iface_idx != -1 ? find_array_interface (ireadonlylist_class, "IReadOnlyCollection`1") : -1;
3642 ilist_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ilist_iface_idx]);
3643 icollection_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [icollection_iface_idx]);
3644 ienumerable_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [ienumerable_iface_idx]);
3645 ireadonlylist_offset = ireadonlylist_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ireadonlylist_iface_idx]) : -1;
3646 ireadonlycollection_offset = ireadonlycollection_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ireadonlylist_class->interfaces [ireadonlycollection_iface_idx]) : -1;
3647 g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0);
3648 for (i = 0; i < num_array_interfaces; ++i) {
3649 int offset;
3650 ic = array_interfaces [i];
3651 if (ic->generic_class->container_class == mono_defaults.generic_ilist_class)
3652 offset = ilist_offset;
3653 else if (strcmp (ic->name, "ICollection`1") == 0)
3654 offset = icollection_offset;
3655 else if (strcmp (ic->name, "IEnumerable`1") == 0)
3656 offset = ienumerable_offset;
3657 else if (strcmp (ic->name, "IReadOnlyList`1") == 0)
3658 offset = ireadonlylist_offset;
3659 else if (strcmp (ic->name, "IReadOnlyCollection`1") == 0)
3660 offset = ireadonlycollection_offset;
3661 else
3662 g_assert_not_reached ();
3663 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, offset, TRUE);
3664 /*g_print ("type %s has %s offset at %d (%s)\n", klass->name, ic->name, offset, klass->interfaces [0]->name);*/
3669 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
3670 if (interface_offsets_full [i] != -1) {
3671 interface_offsets_count ++;
3676 * We might get called multiple times:
3677 * - mono_class_init ()
3678 * - mono_class_setup_vtable ().
3679 * - mono_class_setup_interface_offsets ().
3680 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
3681 * means we have to overwrite those when called from other places (#4440).
3683 if (klass->interfaces_packed) {
3684 if (!overwrite)
3685 g_assert (klass->interface_offsets_count == interface_offsets_count);
3686 } else {
3687 uint8_t *bitmap;
3688 int bsize;
3689 klass->interface_offsets_count = interface_offsets_count;
3690 klass->interfaces_packed = (MonoClass **)mono_class_alloc (klass, sizeof (MonoClass*) * interface_offsets_count);
3691 klass->interface_offsets_packed = (guint16 *)mono_class_alloc (klass, sizeof (guint16) * interface_offsets_count);
3692 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
3693 #ifdef COMPRESSED_INTERFACE_BITMAP
3694 bitmap = g_malloc0 (bsize);
3695 #else
3696 bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
3697 #endif
3698 for (i = 0; i < interface_offsets_count; i++) {
3699 int id = interfaces_full [i]->interface_id;
3700 bitmap [id >> 3] |= (1 << (id & 7));
3701 klass->interfaces_packed [i] = interfaces_full [i];
3702 klass->interface_offsets_packed [i] = interface_offsets_full [i];
3703 /*if (num_array_interfaces)
3704 g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&klass->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/
3706 #ifdef COMPRESSED_INTERFACE_BITMAP
3707 i = mono_compress_bitmap (NULL, bitmap, bsize);
3708 klass->interface_bitmap = mono_class_alloc0 (klass, i);
3709 mono_compress_bitmap (klass->interface_bitmap, bitmap, bsize);
3710 g_free (bitmap);
3711 #else
3712 klass->interface_bitmap = bitmap;
3713 #endif
3716 end:
3717 g_free (interfaces_full);
3718 g_free (interface_offsets_full);
3719 g_free (array_interfaces);
3720 for (i = 0; i < klass->idepth; i++) {
3721 ifaces = ifaces_array [i];
3722 if (ifaces)
3723 g_ptr_array_free (ifaces, TRUE);
3725 g_free (ifaces_array);
3727 //printf ("JUST DONE: ");
3728 //print_implemented_interfaces (klass);
3730 return cur_slot;
3734 * Setup interface offsets for interfaces.
3735 * Initializes:
3736 * - klass->max_interface_id
3737 * - klass->interface_offsets_count
3738 * - klass->interfaces_packed
3739 * - klass->interface_offsets_packed
3740 * - klass->interface_bitmap
3742 * This function can fail @class.
3744 void
3745 mono_class_setup_interface_offsets (MonoClass *klass)
3747 mono_loader_lock ();
3749 setup_interface_offsets (klass, 0, FALSE);
3751 mono_loader_unlock ();
3754 /*Checks if @klass has @parent as one of it's parents type gtd
3756 * For example:
3757 * Foo<T>
3758 * Bar<T> : Foo<Bar<Bar<T>>>
3761 static gboolean
3762 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
3764 klass = mono_class_get_generic_type_definition (klass);
3765 parent = mono_class_get_generic_type_definition (parent);
3766 mono_class_setup_supertypes (klass);
3767 mono_class_setup_supertypes (parent);
3769 return klass->idepth >= parent->idepth &&
3770 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
3773 gboolean
3774 mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
3776 MonoGenericInst *ginst;
3777 int i;
3778 if (!klass->generic_class) {
3779 mono_class_setup_vtable_full (klass, in_setup);
3780 return !mono_class_has_failure (klass);
3783 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
3784 if (mono_class_set_type_load_failure_causedby_class (klass, klass->generic_class->container_class, "Failed to load generic definition vtable"))
3785 return FALSE;
3787 ginst = klass->generic_class->context.class_inst;
3788 for (i = 0; i < ginst->type_argc; ++i) {
3789 MonoClass *arg;
3790 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
3791 continue;
3792 arg = mono_class_from_mono_type (ginst->type_argv [i]);
3793 /*Those 2 will be checked by mono_class_setup_vtable itself*/
3794 if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
3795 continue;
3796 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
3797 mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
3798 return FALSE;
3801 return TRUE;
3805 * mono_class_setup_vtable:
3807 * Creates the generic vtable of CLASS.
3808 * Initializes the following fields in MonoClass:
3809 * - vtable
3810 * - vtable_size
3811 * Plus all the fields initialized by setup_interface_offsets ().
3812 * If there is an error during vtable construction, klass->has_failure
3813 * is set and details are stored in a MonoErrorBoxed.
3815 * LOCKING: Acquires the loader lock.
3817 void
3818 mono_class_setup_vtable (MonoClass *klass)
3820 mono_class_setup_vtable_full (klass, NULL);
3823 static void
3824 mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
3826 MonoError error;
3827 MonoMethod **overrides;
3828 MonoGenericContext *context;
3829 guint32 type_token;
3830 int onum = 0;
3831 gboolean ok = TRUE;
3833 if (klass->vtable)
3834 return;
3836 if (MONO_CLASS_IS_INTERFACE (klass)) {
3837 /* This sets method->slot for all methods if this is an interface */
3838 mono_class_setup_methods (klass);
3839 return;
3842 if (mono_class_has_failure (klass))
3843 return;
3845 if (g_list_find (in_setup, klass))
3846 return;
3848 mono_loader_lock ();
3850 if (klass->vtable) {
3851 mono_loader_unlock ();
3852 return;
3855 mono_stats.generic_vtable_count ++;
3856 in_setup = g_list_prepend (in_setup, klass);
3858 if (klass->generic_class) {
3859 if (!mono_class_check_vtable_constraints (klass, in_setup)) {
3860 mono_loader_unlock ();
3861 g_list_remove (in_setup, klass);
3862 return;
3865 context = mono_class_get_context (klass);
3866 type_token = klass->generic_class->container_class->type_token;
3867 } else {
3868 context = (MonoGenericContext *) klass->generic_container;
3869 type_token = klass->type_token;
3872 if (image_is_dynamic (klass->image)) {
3873 /* Generic instances can have zero method overrides without causing any harm.
3874 * This is true since we don't do layout all over again for them, we simply inflate
3875 * the layout of the parent.
3877 mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, &error);
3878 if (!is_ok (&error)) {
3879 mono_loader_unlock ();
3880 g_list_remove (in_setup, klass);
3881 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (&error));
3882 mono_error_cleanup (&error);
3883 return;
3885 } else {
3886 /* The following call fails if there are missing methods in the type */
3887 /* FIXME it's probably a good idea to avoid this for generic instances. */
3888 ok = mono_class_get_overrides_full (klass->image, type_token, &overrides, &onum, context);
3891 if (ok)
3892 mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
3893 else
3894 mono_class_set_type_load_failure (klass, "Could not load list of method overrides");
3896 g_free (overrides);
3898 mono_loader_unlock ();
3899 g_list_remove (in_setup, klass);
3901 return;
3904 #define DEBUG_INTERFACE_VTABLE_CODE 0
3905 #define TRACE_INTERFACE_VTABLE_CODE 0
3906 #define VERIFY_INTERFACE_VTABLE_CODE 0
3907 #define VTABLE_SELECTOR (1)
3909 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3910 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
3911 if (!(VTABLE_SELECTOR)) break; \
3912 stmt;\
3913 } while (0)
3914 #else
3915 #define DEBUG_INTERFACE_VTABLE(stmt)
3916 #endif
3918 #if TRACE_INTERFACE_VTABLE_CODE
3919 #define TRACE_INTERFACE_VTABLE(stmt) do {\
3920 if (!(VTABLE_SELECTOR)) break; \
3921 stmt;\
3922 } while (0)
3923 #else
3924 #define TRACE_INTERFACE_VTABLE(stmt)
3925 #endif
3927 #if VERIFY_INTERFACE_VTABLE_CODE
3928 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
3929 if (!(VTABLE_SELECTOR)) break; \
3930 stmt;\
3931 } while (0)
3932 #else
3933 #define VERIFY_INTERFACE_VTABLE(stmt)
3934 #endif
3937 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3938 static char*
3939 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
3941 int i;
3942 char *result;
3943 GString *res = g_string_new ("");
3945 g_string_append_c (res, '(');
3946 for (i = 0; i < sig->param_count; ++i) {
3947 if (i > 0)
3948 g_string_append_c (res, ',');
3949 mono_type_get_desc (res, sig->params [i], include_namespace);
3951 g_string_append (res, ")=>");
3952 if (sig->ret != NULL) {
3953 mono_type_get_desc (res, sig->ret, include_namespace);
3954 } else {
3955 g_string_append (res, "NULL");
3957 result = res->str;
3958 g_string_free (res, FALSE);
3959 return result;
3961 static void
3962 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
3963 char *im_sig = mono_signature_get_full_desc (mono_method_signature (im), TRUE);
3964 char *cm_sig = mono_signature_get_full_desc (mono_method_signature (cm), TRUE);
3965 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
3966 g_free (im_sig);
3967 g_free (cm_sig);
3971 #endif
3972 static gboolean
3973 is_wcf_hack_disabled (void)
3975 static gboolean disabled;
3976 static gboolean inited = FALSE;
3977 if (!inited) {
3978 disabled = g_getenv ("MONO_DISABLE_WCF_HACK") != NULL;
3979 inited = TRUE;
3981 return disabled;
3984 static gboolean
3985 check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty)
3987 MonoMethodSignature *cmsig, *imsig;
3988 if (strcmp (im->name, cm->name) == 0) {
3989 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
3990 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
3991 return FALSE;
3993 if (! slot_is_empty) {
3994 if (require_newslot) {
3995 if (! interface_is_explicitly_implemented_by_class) {
3996 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
3997 return FALSE;
3999 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
4000 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
4001 return FALSE;
4003 } else {
4004 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
4007 cmsig = mono_method_signature (cm);
4008 imsig = mono_method_signature (im);
4009 if (!cmsig || !imsig) {
4010 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
4011 return FALSE;
4014 if (! mono_metadata_signature_equal (cmsig, imsig)) {
4015 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
4016 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
4017 TRACE_INTERFACE_VTABLE (printf ("]"));
4018 return FALSE;
4020 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
4021 if (mono_security_core_clr_enabled ())
4022 mono_security_core_clr_check_override (klass, cm, im);
4024 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
4025 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
4026 char *body_name = mono_method_full_name (cm, TRUE);
4027 char *decl_name = mono_method_full_name (im, TRUE);
4028 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4029 g_free (body_name);
4030 g_free (decl_name);
4031 return FALSE;
4034 return TRUE;
4035 } else {
4036 MonoClass *ic = im->klass;
4037 const char *ic_name_space = ic->name_space;
4038 const char *ic_name = ic->name;
4039 char *subname;
4041 if (! require_newslot) {
4042 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
4043 return FALSE;
4045 if (cm->klass->rank == 0) {
4046 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
4047 return FALSE;
4049 cmsig = mono_method_signature (cm);
4050 imsig = mono_method_signature (im);
4051 if (!cmsig || !imsig) {
4052 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
4053 return FALSE;
4056 if (! mono_metadata_signature_equal (cmsig, imsig)) {
4057 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
4058 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
4059 TRACE_INTERFACE_VTABLE (printf ("]"));
4060 return FALSE;
4062 if (mono_class_get_image (ic) != mono_defaults.corlib) {
4063 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
4064 return FALSE;
4066 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
4067 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
4068 return FALSE;
4070 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))) {
4071 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
4072 return FALSE;
4075 subname = strstr (cm->name, ic_name_space);
4076 if (subname != cm->name) {
4077 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
4078 return FALSE;
4080 subname += strlen (ic_name_space);
4081 if (subname [0] != '.') {
4082 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
4083 return FALSE;
4085 subname ++;
4086 if (strstr (subname, ic_name) != subname) {
4087 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
4088 return FALSE;
4090 subname += strlen (ic_name);
4091 if (subname [0] != '.') {
4092 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
4093 return FALSE;
4095 subname ++;
4096 if (strcmp (subname, im->name) != 0) {
4097 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
4098 return FALSE;
4101 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
4102 if (mono_security_core_clr_enabled ())
4103 mono_security_core_clr_check_override (klass, cm, im);
4105 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
4106 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
4107 char *body_name = mono_method_full_name (cm, TRUE);
4108 char *decl_name = mono_method_full_name (im, TRUE);
4109 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4110 g_free (body_name);
4111 g_free (decl_name);
4112 return FALSE;
4115 return TRUE;
4119 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
4120 static void
4121 foreach_override (gpointer key, gpointer value, gpointer user_data) {
4122 MonoMethod *method = key;
4123 MonoMethod *override = value;
4124 MonoClass *method_class = mono_method_get_class (method);
4125 MonoClass *override_class = mono_method_get_class (override);
4127 printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
4128 mono_class_get_namespace (method_class), mono_class_get_name (method_class), mono_method_get_name (method),
4129 mono_class_get_namespace (override_class), mono_class_get_name (override_class), mono_method_get_name (override));
4131 static void
4132 print_overrides (GHashTable *override_map, const char *message) {
4133 if (override_map) {
4134 printf ("Override map \"%s\" START:\n", message);
4135 g_hash_table_foreach (override_map, foreach_override, NULL);
4136 printf ("Override map \"%s\" END.\n", message);
4137 } else {
4138 printf ("Override map \"%s\" EMPTY.\n", message);
4141 static void
4142 print_vtable_full (MonoClass *klass, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
4143 char *full_name = mono_type_full_name (&klass->byval_arg);
4144 int i;
4145 int parent_size;
4147 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
4149 if (print_interfaces) {
4150 print_implemented_interfaces (klass);
4151 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
4154 if (klass->parent) {
4155 parent_size = klass->parent->vtable_size;
4156 } else {
4157 parent_size = 0;
4159 for (i = 0; i < size; ++i) {
4160 MonoMethod *cm = vtable [i];
4161 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
4162 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
4164 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
4165 g_free (cm_name);
4168 g_free (full_name);
4170 #endif
4172 #if VERIFY_INTERFACE_VTABLE_CODE
4173 static int
4174 mono_method_try_get_vtable_index (MonoMethod *method)
4176 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
4177 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
4178 if (imethod->declaring->is_generic)
4179 return imethod->declaring->slot;
4181 return method->slot;
4184 static void
4185 mono_class_verify_vtable (MonoClass *klass)
4187 int i;
4188 char *full_name = mono_type_full_name (&klass->byval_arg);
4190 printf ("*** Verifying VTable of class '%s' \n", full_name);
4191 g_free (full_name);
4192 full_name = NULL;
4194 if (!klass->methods)
4195 return;
4197 for (i = 0; i < klass->method.count; ++i) {
4198 MonoMethod *cm = klass->methods [i];
4199 int slot;
4201 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
4202 continue;
4204 g_free (full_name);
4205 full_name = mono_method_full_name (cm, TRUE);
4207 slot = mono_method_try_get_vtable_index (cm);
4208 if (slot >= 0) {
4209 if (slot >= klass->vtable_size) {
4210 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, klass->vtable_size);
4211 continue;
4214 if (slot >= 0 && klass->vtable [slot] != cm && (klass->vtable [slot])) {
4215 char *other_name = klass->vtable [slot] ? mono_method_full_name (klass->vtable [slot], TRUE) : g_strdup ("[null value]");
4216 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
4217 g_free (other_name);
4219 } else
4220 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
4222 g_free (full_name);
4224 #endif
4226 static void
4227 print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) {
4228 int index;
4229 char *method_signature;
4230 char *type_name;
4232 for (index = 0; index < onum; ++index) {
4233 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name,
4234 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
4236 method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
4237 type_name = mono_type_full_name (&klass->byval_arg);
4238 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s\n",
4239 mono_type_get_name (&ic->byval_arg), im->name, method_signature, type_name);
4240 g_free (method_signature);
4241 g_free (type_name);
4242 mono_class_setup_methods (klass);
4243 if (mono_class_has_failure (klass)) {
4244 char *name = mono_type_get_full_name (klass);
4245 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods\n", name);
4246 g_free (name);
4247 return;
4249 for (index = 0; index < klass->method.count; ++index) {
4250 MonoMethod *cm = klass->methods [index];
4251 method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
4253 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)\n", cm->name, method_signature);
4254 g_free (method_signature);
4258 static MonoMethod*
4259 mono_method_get_method_definition (MonoMethod *method)
4261 while (method->is_inflated)
4262 method = ((MonoMethodInflated*)method)->declaring;
4263 return method;
4266 static gboolean
4267 verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
4269 int i;
4271 for (i = 0; i < onum; ++i) {
4272 MonoMethod *decl = overrides [i * 2];
4273 MonoMethod *body = overrides [i * 2 + 1];
4275 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
4276 mono_class_set_type_load_failure (klass, "Method belongs to a different class than the declared one");
4277 return FALSE;
4280 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
4281 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4282 mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
4283 else
4284 mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
4285 return FALSE;
4288 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
4289 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4290 mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
4291 else
4292 mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
4293 return FALSE;
4296 if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
4297 mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
4298 return FALSE;
4301 body = mono_method_get_method_definition (body);
4302 decl = mono_method_get_method_definition (decl);
4304 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
4305 char *body_name = mono_method_full_name (body, TRUE);
4306 char *decl_name = mono_method_full_name (decl, TRUE);
4307 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4308 g_free (body_name);
4309 g_free (decl_name);
4310 return FALSE;
4313 return TRUE;
4316 static gboolean
4317 mono_class_need_stelemref_method (MonoClass *klass)
4319 return klass->rank == 1 && MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg);
4323 * LOCKING: this is supposed to be called with the loader lock held.
4325 void
4326 mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup)
4328 MonoError error;
4329 MonoClass *k, *ic;
4330 MonoMethod **vtable;
4331 int i, max_vtsize = 0, max_iid, cur_slot = 0;
4332 GPtrArray *ifaces = NULL;
4333 GHashTable *override_map = NULL;
4334 MonoMethod *cm;
4335 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
4336 int first_non_interface_slot;
4337 #endif
4338 GSList *virt_methods = NULL, *l;
4339 int stelemref_slot = 0;
4341 if (klass->vtable)
4342 return;
4344 if (overrides && !verify_class_overrides (klass, overrides, onum))
4345 return;
4347 ifaces = mono_class_get_implemented_interfaces (klass, &error);
4348 if (!mono_error_ok (&error)) {
4349 char *name = mono_type_get_full_name (klass);
4350 mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error));
4351 g_free (name);
4352 mono_error_cleanup (&error);
4353 return;
4354 } else if (ifaces) {
4355 for (i = 0; i < ifaces->len; i++) {
4356 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
4357 max_vtsize += ic->method.count;
4359 g_ptr_array_free (ifaces, TRUE);
4360 ifaces = NULL;
4363 if (klass->parent) {
4364 mono_class_init (klass->parent);
4365 mono_class_setup_vtable_full (klass->parent, in_setup);
4367 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
4368 return;
4370 max_vtsize += klass->parent->vtable_size;
4371 cur_slot = klass->parent->vtable_size;
4374 max_vtsize += klass->method.count;
4376 /*Array have a slot for stelemref*/
4377 if (mono_class_need_stelemref_method (klass)) {
4378 stelemref_slot = cur_slot;
4379 ++max_vtsize;
4380 ++cur_slot;
4383 vtable = (MonoMethod **)alloca (sizeof (gpointer) * max_vtsize);
4384 memset (vtable, 0, sizeof (gpointer) * max_vtsize);
4386 /* printf ("METAINIT %s.%s\n", klass->name_space, klass->name); */
4388 cur_slot = setup_interface_offsets (klass, cur_slot, TRUE);
4389 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
4390 return;
4392 max_iid = klass->max_interface_id;
4393 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
4395 /* Optimized version for generic instances */
4396 if (klass->generic_class) {
4397 MonoError error;
4398 MonoClass *gklass = klass->generic_class->container_class;
4399 MonoMethod **tmp;
4401 mono_class_setup_vtable_full (gklass, in_setup);
4402 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
4403 return;
4405 tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
4406 klass->vtable_size = gklass->vtable_size;
4407 for (i = 0; i < gklass->vtable_size; ++i)
4408 if (gklass->vtable [i]) {
4409 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), &error);
4410 if (!mono_error_ok (&error)) {
4411 mono_class_set_type_load_failure (klass, "Could not inflate method due to %s", mono_error_get_message (&error));
4412 mono_error_cleanup (&error);
4413 return;
4415 tmp [i] = inflated;
4416 tmp [i]->slot = gklass->vtable [i]->slot;
4418 mono_memory_barrier ();
4419 klass->vtable = tmp;
4421 /* Have to set method->slot for abstract virtual methods */
4422 if (klass->methods && gklass->methods) {
4423 for (i = 0; i < klass->method.count; ++i)
4424 if (klass->methods [i]->slot == -1)
4425 klass->methods [i]->slot = gklass->methods [i]->slot;
4428 return;
4431 if (klass->parent && klass->parent->vtable_size) {
4432 MonoClass *parent = klass->parent;
4433 int i;
4435 memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
4437 // Also inherit parent interface vtables, just as a starting point.
4438 // This is needed otherwise bug-77127.exe fails when the property methods
4439 // have different names in the iterface and the class, because for child
4440 // classes the ".override" information is not used anymore.
4441 for (i = 0; i < parent->interface_offsets_count; i++) {
4442 MonoClass *parent_interface = parent->interfaces_packed [i];
4443 int interface_offset = mono_class_interface_offset (klass, parent_interface);
4444 /*FIXME this is now dead code as this condition will never hold true.
4445 Since interface offsets are inherited then the offset of an interface implemented
4446 by a parent will never be the out of it's vtable boundary.
4448 if (interface_offset >= parent->vtable_size) {
4449 int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
4450 int j;
4452 mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
4453 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
4454 for (j = 0; j < parent_interface->method.count && !mono_class_has_failure (klass); j++) {
4455 vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
4456 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
4457 parent_interface_offset + j, parent_interface_offset, j,
4458 interface_offset + j, interface_offset, j));
4465 /*Array have a slot for stelemref*/
4466 if (mono_class_need_stelemref_method (klass)) {
4467 MonoMethod *method = mono_marshal_get_virtual_stelemref (klass);
4468 if (!method->slot)
4469 method->slot = stelemref_slot;
4470 else
4471 g_assert (method->slot == stelemref_slot);
4473 vtable [stelemref_slot] = method;
4476 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
4477 /* override interface methods */
4478 for (i = 0; i < onum; i++) {
4479 MonoMethod *decl = overrides [i*2];
4480 if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
4481 int dslot;
4482 dslot = mono_method_get_vtable_slot (decl);
4483 if (dslot == -1) {
4484 mono_class_set_type_load_failure (klass, "");
4485 return;
4488 dslot += mono_class_interface_offset (klass, decl->klass);
4489 vtable [dslot] = overrides [i*2 + 1];
4490 vtable [dslot]->slot = dslot;
4491 if (!override_map)
4492 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4494 g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
4496 if (mono_security_core_clr_enabled ())
4497 mono_security_core_clr_check_override (klass, vtable [dslot], decl);
4500 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
4501 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
4504 * Create a list of virtual methods to avoid calling
4505 * mono_class_get_virtual_methods () which is slow because of the metadata
4506 * optimization.
4509 gpointer iter = NULL;
4510 MonoMethod *cm;
4512 virt_methods = NULL;
4513 while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
4514 virt_methods = g_slist_prepend (virt_methods, cm);
4516 if (mono_class_has_failure (klass))
4517 goto fail;
4520 // Loop on all implemented interfaces...
4521 for (i = 0; i < klass->interface_offsets_count; i++) {
4522 MonoClass *parent = klass->parent;
4523 int ic_offset;
4524 gboolean interface_is_explicitly_implemented_by_class;
4525 int im_index;
4527 ic = klass->interfaces_packed [i];
4528 ic_offset = mono_class_interface_offset (klass, ic);
4530 mono_class_setup_methods (ic);
4531 if (mono_class_has_failure (ic))
4532 goto fail;
4534 // Check if this interface is explicitly implemented (instead of just inherited)
4535 if (parent != NULL) {
4536 int implemented_interfaces_index;
4537 interface_is_explicitly_implemented_by_class = FALSE;
4538 for (implemented_interfaces_index = 0; implemented_interfaces_index < klass->interface_count; implemented_interfaces_index++) {
4539 if (ic == klass->interfaces [implemented_interfaces_index]) {
4540 interface_is_explicitly_implemented_by_class = TRUE;
4541 break;
4544 } else {
4545 interface_is_explicitly_implemented_by_class = TRUE;
4548 // Loop on all interface methods...
4549 for (im_index = 0; im_index < ic->method.count; im_index++) {
4550 MonoMethod *im = ic->methods [im_index];
4551 int im_slot = ic_offset + im->slot;
4552 MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL;
4554 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4555 continue;
4557 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
4559 // If there is an explicit implementation, just use it right away,
4560 // otherwise look for a matching method
4561 if (override_im == NULL) {
4562 int cm_index;
4563 MonoMethod *cm;
4565 // First look for a suitable method among the class methods
4566 for (l = virt_methods; l; l = l->next) {
4567 cm = (MonoMethod *)l->data;
4568 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)));
4569 if (check_interface_method_override (klass, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
4570 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
4571 vtable [im_slot] = cm;
4572 /* Why do we need this? */
4573 if (cm->slot < 0) {
4574 cm->slot = im_slot;
4577 TRACE_INTERFACE_VTABLE (printf ("\n"));
4578 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
4579 goto fail;
4582 // If the slot is still empty, look in all the inherited virtual methods...
4583 if ((vtable [im_slot] == NULL) && klass->parent != NULL) {
4584 MonoClass *parent = klass->parent;
4585 // Reverse order, so that last added methods are preferred
4586 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
4587 MonoMethod *cm = parent->vtable [cm_index];
4589 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));
4590 if ((cm != NULL) && check_interface_method_override (klass, im, cm, FALSE, FALSE, TRUE)) {
4591 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
4592 vtable [im_slot] = cm;
4593 /* Why do we need this? */
4594 if (cm->slot < 0) {
4595 cm->slot = im_slot;
4597 break;
4599 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
4600 goto fail;
4601 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
4604 } else {
4605 g_assert (vtable [im_slot] == override_im);
4610 // If the class is not abstract, check that all its interface slots are full.
4611 // The check is done here and not directly at the end of the loop above because
4612 // it can happen (for injected generic array interfaces) that the same slot is
4613 // processed multiple times (those interfaces have overlapping slots), and it
4614 // will not always be the first pass the one that fills the slot.
4615 if (! (klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
4616 for (i = 0; i < klass->interface_offsets_count; i++) {
4617 int ic_offset;
4618 int im_index;
4620 ic = klass->interfaces_packed [i];
4621 ic_offset = mono_class_interface_offset (klass, ic);
4623 for (im_index = 0; im_index < ic->method.count; im_index++) {
4624 MonoMethod *im = ic->methods [im_index];
4625 int im_slot = ic_offset + im->slot;
4627 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4628 continue;
4630 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
4631 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
4632 if (vtable [im_slot] == NULL) {
4633 print_unimplemented_interface_method_info (klass, ic, im, im_slot, overrides, onum);
4634 goto fail;
4640 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
4641 for (l = virt_methods; l; l = l->next) {
4642 cm = (MonoMethod *)l->data;
4644 * If the method is REUSE_SLOT, we must check in the
4645 * base class for a method to override.
4647 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
4648 int slot = -1;
4649 for (k = klass->parent; k ; k = k->parent) {
4650 gpointer k_iter;
4651 MonoMethod *m1;
4653 k_iter = NULL;
4654 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
4655 MonoMethodSignature *cmsig, *m1sig;
4657 cmsig = mono_method_signature (cm);
4658 m1sig = mono_method_signature (m1);
4660 if (!cmsig || !m1sig) {
4661 /* FIXME proper error message */
4662 mono_class_set_type_load_failure (klass, "");
4663 return;
4666 if (!strcmp(cm->name, m1->name) &&
4667 mono_metadata_signature_equal (cmsig, m1sig)) {
4669 if (mono_security_core_clr_enabled ())
4670 mono_security_core_clr_check_override (klass, cm, m1);
4672 slot = mono_method_get_vtable_slot (m1);
4673 if (slot == -1)
4674 goto fail;
4676 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
4677 char *body_name = mono_method_full_name (cm, TRUE);
4678 char *decl_name = mono_method_full_name (m1, TRUE);
4679 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4680 g_free (body_name);
4681 g_free (decl_name);
4682 goto fail;
4685 g_assert (cm->slot < max_vtsize);
4686 if (!override_map)
4687 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4688 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
4689 mono_method_full_name (m1, 1), m1,
4690 mono_method_full_name (cm, 1), cm));
4691 g_hash_table_insert (override_map, m1, cm);
4692 break;
4695 if (mono_class_has_failure (k))
4696 goto fail;
4698 if (slot >= 0)
4699 break;
4701 if (slot >= 0)
4702 cm->slot = slot;
4705 /*Non final newslot methods must be given a non-interface vtable slot*/
4706 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
4707 cm->slot = -1;
4709 if (cm->slot < 0)
4710 cm->slot = cur_slot++;
4712 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
4713 vtable [cm->slot] = cm;
4716 /* override non interface methods */
4717 for (i = 0; i < onum; i++) {
4718 MonoMethod *decl = overrides [i*2];
4719 if (!MONO_CLASS_IS_INTERFACE (decl->klass)) {
4720 g_assert (decl->slot != -1);
4721 vtable [decl->slot] = overrides [i*2 + 1];
4722 overrides [i * 2 + 1]->slot = decl->slot;
4723 if (!override_map)
4724 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4725 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
4726 mono_method_full_name (decl, 1), decl,
4727 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
4728 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
4730 if (mono_security_core_clr_enabled ())
4731 mono_security_core_clr_check_override (klass, vtable [decl->slot], decl);
4736 * If a method occupies more than one place in the vtable, and it is
4737 * overriden, then change the other occurances too.
4739 if (override_map) {
4740 MonoMethod *cm;
4742 for (i = 0; i < max_vtsize; ++i)
4743 if (vtable [i]) {
4744 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
4746 cm = (MonoMethod *)g_hash_table_lookup (override_map, vtable [i]);
4747 if (cm)
4748 vtable [i] = cm;
4751 g_hash_table_destroy (override_map);
4752 override_map = NULL;
4755 g_slist_free (virt_methods);
4756 virt_methods = NULL;
4758 /* Ensure that all vtable slots are filled with concrete instance methods */
4759 if (!(klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
4760 for (i = 0; i < cur_slot; ++i) {
4761 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
4762 char *type_name = mono_type_get_full_name (klass);
4763 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
4764 mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
4765 g_free (type_name);
4766 g_free (method_name);
4767 return;
4772 if (klass->generic_class) {
4773 MonoClass *gklass = klass->generic_class->container_class;
4775 mono_class_init (gklass);
4777 klass->vtable_size = MAX (gklass->vtable_size, cur_slot);
4778 } else {
4779 /* Check that the vtable_size value computed in mono_class_init () is correct */
4780 if (klass->vtable_size)
4781 g_assert (cur_slot == klass->vtable_size);
4782 klass->vtable_size = cur_slot;
4785 /* Try to share the vtable with our parent. */
4786 if (klass->parent && (klass->parent->vtable_size == klass->vtable_size) && (memcmp (klass->parent->vtable, vtable, sizeof (gpointer) * klass->vtable_size) == 0)) {
4787 mono_memory_barrier ();
4788 klass->vtable = klass->parent->vtable;
4789 } else {
4790 MonoMethod **tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * klass->vtable_size);
4791 memcpy (tmp, vtable, sizeof (gpointer) * klass->vtable_size);
4792 mono_memory_barrier ();
4793 klass->vtable = tmp;
4796 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass, klass->vtable, klass->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
4797 if (mono_print_vtable) {
4798 int icount = 0;
4800 print_implemented_interfaces (klass);
4802 for (i = 0; i <= max_iid; i++)
4803 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
4804 icount++;
4806 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&klass->byval_arg),
4807 klass->vtable_size, icount);
4809 for (i = 0; i < cur_slot; ++i) {
4810 MonoMethod *cm;
4812 cm = vtable [i];
4813 if (cm) {
4814 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
4815 mono_method_full_name (cm, TRUE));
4820 if (icount) {
4821 printf ("Interfaces %s.%s (max_iid = %d)\n", klass->name_space,
4822 klass->name, max_iid);
4824 for (i = 0; i < klass->interface_count; i++) {
4825 ic = klass->interfaces [i];
4826 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
4827 mono_class_interface_offset (klass, ic),
4828 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4831 for (k = klass->parent; k ; k = k->parent) {
4832 for (i = 0; i < k->interface_count; i++) {
4833 ic = k->interfaces [i];
4834 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
4835 mono_class_interface_offset (klass, ic),
4836 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4842 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass));
4843 return;
4845 fail:
4847 char *name = mono_type_get_full_name (klass);
4848 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
4849 g_free (name);
4850 if (override_map)
4851 g_hash_table_destroy (override_map);
4852 if (virt_methods)
4853 g_slist_free (virt_methods);
4858 * mono_method_get_vtable_slot:
4860 * Returns method->slot, computing it if neccesary. Return -1 on failure.
4861 * LOCKING: Acquires the loader lock.
4863 * FIXME Use proper MonoError machinery here.
4866 mono_method_get_vtable_slot (MonoMethod *method)
4868 if (method->slot == -1) {
4869 mono_class_setup_vtable (method->klass);
4870 if (mono_class_has_failure (method->klass))
4871 return -1;
4872 if (method->slot == -1) {
4873 MonoClass *gklass;
4874 int i;
4876 if (!method->klass->generic_class) {
4877 g_assert (method->is_inflated);
4878 return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
4881 /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
4882 g_assert (method->klass->generic_class);
4883 gklass = method->klass->generic_class->container_class;
4884 mono_class_setup_methods (method->klass);
4885 g_assert (method->klass->methods);
4886 for (i = 0; i < method->klass->method.count; ++i) {
4887 if (method->klass->methods [i] == method)
4888 break;
4890 g_assert (i < method->klass->method.count);
4891 g_assert (gklass->methods);
4892 method->slot = gklass->methods [i]->slot;
4894 g_assert (method->slot != -1);
4896 return method->slot;
4900 * mono_method_get_vtable_index:
4901 * @method: a method
4903 * Returns the index into the runtime vtable to access the method or,
4904 * in the case of a virtual generic method, the virtual generic method
4905 * thunk. Returns -1 on failure.
4907 * FIXME Use proper MonoError machinery here.
4910 mono_method_get_vtable_index (MonoMethod *method)
4912 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
4913 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
4914 if (imethod->declaring->is_generic)
4915 return mono_method_get_vtable_slot (imethod->declaring);
4917 return mono_method_get_vtable_slot (method);
4920 static MonoMethod *default_ghc = NULL;
4921 static MonoMethod *default_finalize = NULL;
4922 static int finalize_slot = -1;
4923 static int ghc_slot = -1;
4925 static void
4926 initialize_object_slots (MonoClass *klass)
4928 int i;
4929 if (default_ghc)
4930 return;
4931 if (klass == mono_defaults.object_class) {
4932 mono_class_setup_vtable (klass);
4933 for (i = 0; i < klass->vtable_size; ++i) {
4934 MonoMethod *cm = klass->vtable [i];
4936 if (!strcmp (cm->name, "GetHashCode"))
4937 ghc_slot = i;
4938 else if (!strcmp (cm->name, "Finalize"))
4939 finalize_slot = i;
4942 g_assert (ghc_slot > 0);
4943 default_ghc = klass->vtable [ghc_slot];
4945 g_assert (finalize_slot > 0);
4946 default_finalize = klass->vtable [finalize_slot];
4950 typedef struct {
4951 MonoMethod *array_method;
4952 char *name;
4953 } GenericArrayMethodInfo;
4955 static int generic_array_method_num = 0;
4956 static GenericArrayMethodInfo *generic_array_method_info = NULL;
4958 static int
4959 generic_array_methods (MonoClass *klass)
4961 int i, count_generic = 0;
4962 GList *list = NULL, *tmp;
4963 if (generic_array_method_num)
4964 return generic_array_method_num;
4965 mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
4966 g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
4967 for (i = 0; i < klass->parent->method.count; i++) {
4968 MonoMethod *m = klass->parent->methods [i];
4969 if (!strncmp (m->name, "InternalArray__", 15)) {
4970 count_generic++;
4971 list = g_list_prepend (list, m);
4974 list = g_list_reverse (list);
4975 generic_array_method_info = (GenericArrayMethodInfo *)mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
4976 i = 0;
4977 for (tmp = list; tmp; tmp = tmp->next) {
4978 const char *mname, *iname;
4979 gchar *name;
4980 MonoMethod *m = (MonoMethod *)tmp->data;
4981 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
4982 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
4984 generic_array_method_info [i].array_method = m;
4985 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
4986 iname = "System.Collections.Generic.ICollection`1.";
4987 mname = m->name + 27;
4988 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
4989 iname = "System.Collections.Generic.IEnumerable`1.";
4990 mname = m->name + 27;
4991 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
4992 iname = "System.Collections.Generic.IReadOnlyList`1.";
4993 mname = m->name + strlen (ireadonlylist_prefix);
4994 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
4995 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
4996 mname = m->name + strlen (ireadonlycollection_prefix);
4997 } else if (!strncmp (m->name, "InternalArray__", 15)) {
4998 iname = "System.Collections.Generic.IList`1.";
4999 mname = m->name + 15;
5000 } else {
5001 g_assert_not_reached ();
5004 name = (gchar *)mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
5005 strcpy (name, iname);
5006 strcpy (name + strlen (iname), mname);
5007 generic_array_method_info [i].name = name;
5008 i++;
5010 /*g_print ("array generic methods: %d\n", count_generic);*/
5012 generic_array_method_num = count_generic;
5013 g_list_free (list);
5014 return generic_array_method_num;
5017 static void
5018 setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos)
5020 MonoGenericContext tmp_context;
5021 int i;
5023 tmp_context.class_inst = NULL;
5024 tmp_context.method_inst = iface->generic_class->context.class_inst;
5025 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
5027 for (i = 0; i < generic_array_method_num; i++) {
5028 MonoError error;
5029 MonoMethod *m = generic_array_method_info [i].array_method;
5030 MonoMethod *inflated;
5032 inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, &error);
5033 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
5034 methods [pos++] = mono_marshal_get_generic_array_helper (klass, iface, generic_array_method_info [i].name, inflated);
5038 static char*
5039 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
5041 int null_length = strlen ("(null)");
5042 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
5043 char *s = (char *)mono_image_alloc (image, len);
5044 int result;
5046 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
5047 g_assert (result == len - 1);
5049 return s;
5053 * mono_class_init:
5054 * @class: the class to initialize
5056 * Compute the instance_size, class_size and other infos that cannot be
5057 * computed at mono_class_get() time. Also compute vtable_size if possible.
5058 * Returns TRUE on success or FALSE if there was a problem in loading
5059 * the type (incorrect assemblies, missing assemblies, methods, etc).
5061 * LOCKING: Acquires the loader lock.
5063 gboolean
5064 mono_class_init (MonoClass *klass)
5066 int i;
5067 MonoCachedClassInfo cached_info;
5068 gboolean has_cached_info;
5070 g_assert (klass);
5072 /* Double-checking locking pattern */
5073 if (klass->inited || mono_class_has_failure (klass))
5074 return !mono_class_has_failure (klass);
5076 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
5078 /* We do everything inside the lock to prevent races */
5079 mono_loader_lock ();
5081 if (klass->inited || mono_class_has_failure (klass)) {
5082 mono_loader_unlock ();
5083 /* Somebody might have gotten in before us */
5084 return !mono_class_has_failure (klass);
5087 if (klass->init_pending) {
5088 mono_class_set_type_load_failure (klass, "Recursive type definition detected");
5089 goto leave;
5092 klass->init_pending = 1;
5094 if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
5095 mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
5096 goto leave;
5100 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
5101 MonoClass *element_class = klass->element_class;
5102 if (!element_class->inited)
5103 mono_class_init (element_class);
5104 if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
5105 goto leave;
5108 mono_stats.initialized_class_count++;
5110 if (klass->generic_class && !klass->generic_class->is_dynamic) {
5111 MonoClass *gklass = klass->generic_class->container_class;
5113 mono_stats.generic_class_count++;
5115 klass->method = gklass->method;
5116 klass->field = gklass->field;
5118 mono_class_init (gklass);
5119 // FIXME: Why is this needed ?
5120 if (!mono_class_has_failure (gklass))
5121 mono_class_setup_methods (gklass);
5122 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
5123 goto leave;
5125 if (MONO_CLASS_IS_INTERFACE (klass))
5126 klass->interface_id = mono_get_unique_iid (klass);
5129 if (klass->parent && !klass->parent->inited)
5130 mono_class_init (klass->parent);
5132 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
5134 if (klass->generic_class || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
5135 klass->nested_classes_inited = TRUE;
5138 * Computes the size used by the fields, and their locations
5140 if (has_cached_info) {
5141 klass->instance_size = cached_info.instance_size;
5142 klass->sizes.class_size = cached_info.class_size;
5143 klass->packing_size = cached_info.packing_size;
5144 klass->min_align = cached_info.min_align;
5145 klass->blittable = cached_info.blittable;
5146 klass->has_references = cached_info.has_references;
5147 klass->has_static_refs = cached_info.has_static_refs;
5148 klass->no_special_static_fields = cached_info.no_special_static_fields;
5150 else
5151 if (!klass->size_inited){
5152 mono_class_setup_fields (klass);
5153 if (mono_class_has_failure (klass))
5154 goto leave;
5157 /* Initialize arrays */
5158 if (klass->rank) {
5159 klass->method.count = 3 + (klass->rank > 1? 2: 1);
5161 if (klass->interface_count) {
5162 int count_generic = generic_array_methods (klass);
5163 klass->method.count += klass->interface_count * count_generic;
5167 mono_class_setup_supertypes (klass);
5169 if (!default_ghc)
5170 initialize_object_slots (klass);
5173 * Initialize the rest of the data without creating a generic vtable if possible.
5174 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
5175 * also avoid computing a generic vtable.
5177 if (has_cached_info) {
5178 /* AOT case */
5179 klass->vtable_size = cached_info.vtable_size;
5180 klass->has_finalize = cached_info.has_finalize;
5181 klass->has_finalize_inited = TRUE;
5182 klass->ghcimpl = cached_info.ghcimpl;
5183 klass->has_cctor = cached_info.has_cctor;
5184 } else if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
5185 /* SZARRAY can have 2 vtable layouts, with and without the stelemref method.
5186 * The first slot if for array with.
5188 static int szarray_vtable_size[2] = { 0 };
5190 int slot = MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg) ? 0 : 1;
5192 /* SZARRAY case */
5193 if (!szarray_vtable_size [slot]) {
5194 mono_class_setup_vtable (klass);
5195 szarray_vtable_size [slot] = klass->vtable_size;
5196 } else {
5197 klass->vtable_size = szarray_vtable_size[slot];
5199 } else if (klass->generic_class && !MONO_CLASS_IS_INTERFACE (klass)) {
5200 MonoClass *gklass = klass->generic_class->container_class;
5202 /* Generic instance case */
5203 klass->ghcimpl = gklass->ghcimpl;
5204 klass->has_cctor = gklass->has_cctor;
5206 mono_class_setup_vtable (gklass);
5207 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
5208 goto leave;
5210 klass->vtable_size = gklass->vtable_size;
5211 } else {
5212 /* General case */
5214 /* ghcimpl is not currently used
5215 klass->ghcimpl = 1;
5216 if (klass->parent) {
5217 MonoMethod *cmethod = klass->vtable [ghc_slot];
5218 if (cmethod->is_inflated)
5219 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5220 if (cmethod == default_ghc) {
5221 klass->ghcimpl = 0;
5226 /* C# doesn't allow interfaces to have cctors */
5227 if (!MONO_CLASS_IS_INTERFACE (klass) || klass->image != mono_defaults.corlib) {
5228 MonoMethod *cmethod = NULL;
5230 if (klass->type_token && !image_is_dynamic(klass->image)) {
5231 cmethod = find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
5232 /* The find_method function ignores the 'flags' argument */
5233 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
5234 klass->has_cctor = 1;
5235 } else {
5236 mono_class_setup_methods (klass);
5237 if (mono_class_has_failure (klass))
5238 goto leave;
5240 for (i = 0; i < klass->method.count; ++i) {
5241 MonoMethod *method = klass->methods [i];
5242 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
5243 (strcmp (".cctor", method->name) == 0)) {
5244 klass->has_cctor = 1;
5245 break;
5252 if (klass->parent) {
5253 MonoError parent_error;
5254 mono_error_init (&parent_error);
5255 int first_iface_slot;
5256 /* This will compute klass->parent->vtable_size for some classes */
5257 mono_class_init (klass->parent);
5258 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to initialize")) {
5259 goto leave;
5261 if (!klass->parent->vtable_size) {
5262 /* FIXME: Get rid of this somehow */
5263 mono_class_setup_vtable (klass->parent);
5264 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize")) {
5265 goto leave;
5268 first_iface_slot = klass->parent->vtable_size;
5269 if (mono_class_need_stelemref_method (klass))
5270 ++first_iface_slot;
5271 setup_interface_offsets (klass, first_iface_slot, TRUE);
5272 } else {
5273 setup_interface_offsets (klass, 0, TRUE);
5276 if (mono_security_core_clr_enabled ())
5277 mono_security_core_clr_check_inheritance (klass);
5279 if (klass->generic_class && !mono_verifier_class_is_valid_generic_instantiation (klass))
5280 mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
5282 goto leave;
5284 leave:
5285 /* Because of the double-checking locking pattern */
5286 mono_memory_barrier ();
5287 klass->inited = 1;
5288 klass->init_pending = 0;
5290 mono_loader_unlock ();
5292 return !mono_class_has_failure (klass);
5296 * mono_class_has_finalizer:
5298 * Return whenever KLASS has a finalizer, initializing klass->has_finalizer in the
5299 * process.
5301 gboolean
5302 mono_class_has_finalizer (MonoClass *klass)
5304 gboolean has_finalize = FALSE;
5306 if (klass->has_finalize_inited)
5307 return klass->has_finalize;
5309 /* Interfaces and valuetypes are not supposed to have finalizers */
5310 if (!(MONO_CLASS_IS_INTERFACE (klass) || klass->valuetype)) {
5311 MonoMethod *cmethod = NULL;
5313 if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
5314 } else if (klass->generic_class) {
5315 MonoClass *gklass = klass->generic_class->container_class;
5317 has_finalize = mono_class_has_finalizer (gklass);
5318 } else if (klass->parent && klass->parent->has_finalize) {
5319 has_finalize = TRUE;
5320 } else {
5321 if (klass->parent) {
5323 * Can't search in metadata for a method named Finalize, because that
5324 * ignores overrides.
5326 mono_class_setup_vtable (klass);
5327 if (mono_class_has_failure (klass))
5328 cmethod = NULL;
5329 else
5330 cmethod = klass->vtable [finalize_slot];
5333 if (cmethod) {
5334 g_assert (klass->vtable_size > finalize_slot);
5336 if (klass->parent) {
5337 if (cmethod->is_inflated)
5338 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5339 if (cmethod != default_finalize)
5340 has_finalize = TRUE;
5346 mono_image_lock (klass->image);
5348 if (!klass->has_finalize_inited) {
5349 klass->has_finalize = has_finalize ? 1 : 0;
5351 mono_memory_barrier ();
5352 klass->has_finalize_inited = TRUE;
5355 mono_image_unlock (klass->image);
5357 return klass->has_finalize;
5360 gboolean
5361 mono_is_corlib_image (MonoImage *image)
5363 return image == mono_defaults.corlib;
5367 * LOCKING: this assumes the loader lock is held
5369 void
5370 mono_class_setup_mono_type (MonoClass *klass)
5372 const char *name = klass->name;
5373 const char *nspace = klass->name_space;
5374 gboolean is_corlib = mono_is_corlib_image (klass->image);
5376 klass->this_arg.byref = 1;
5377 klass->this_arg.data.klass = klass;
5378 klass->this_arg.type = MONO_TYPE_CLASS;
5379 klass->byval_arg.data.klass = klass;
5380 klass->byval_arg.type = MONO_TYPE_CLASS;
5382 if (is_corlib && !strcmp (nspace, "System")) {
5383 if (!strcmp (name, "ValueType")) {
5385 * do not set the valuetype bit for System.ValueType.
5386 * klass->valuetype = 1;
5388 klass->blittable = TRUE;
5389 } else if (!strcmp (name, "Enum")) {
5391 * do not set the valuetype bit for System.Enum.
5392 * klass->valuetype = 1;
5394 klass->valuetype = 0;
5395 klass->enumtype = 0;
5396 } else if (!strcmp (name, "Object")) {
5397 klass->byval_arg.type = MONO_TYPE_OBJECT;
5398 klass->this_arg.type = MONO_TYPE_OBJECT;
5399 } else if (!strcmp (name, "String")) {
5400 klass->byval_arg.type = MONO_TYPE_STRING;
5401 klass->this_arg.type = MONO_TYPE_STRING;
5402 } else if (!strcmp (name, "TypedReference")) {
5403 klass->byval_arg.type = MONO_TYPE_TYPEDBYREF;
5404 klass->this_arg.type = MONO_TYPE_TYPEDBYREF;
5408 if (klass->valuetype) {
5409 int t = MONO_TYPE_VALUETYPE;
5411 if (is_corlib && !strcmp (nspace, "System")) {
5412 switch (*name) {
5413 case 'B':
5414 if (!strcmp (name, "Boolean")) {
5415 t = MONO_TYPE_BOOLEAN;
5416 } else if (!strcmp(name, "Byte")) {
5417 t = MONO_TYPE_U1;
5418 klass->blittable = TRUE;
5420 break;
5421 case 'C':
5422 if (!strcmp (name, "Char")) {
5423 t = MONO_TYPE_CHAR;
5425 break;
5426 case 'D':
5427 if (!strcmp (name, "Double")) {
5428 t = MONO_TYPE_R8;
5429 klass->blittable = TRUE;
5431 break;
5432 case 'I':
5433 if (!strcmp (name, "Int32")) {
5434 t = MONO_TYPE_I4;
5435 klass->blittable = TRUE;
5436 } else if (!strcmp(name, "Int16")) {
5437 t = MONO_TYPE_I2;
5438 klass->blittable = TRUE;
5439 } else if (!strcmp(name, "Int64")) {
5440 t = MONO_TYPE_I8;
5441 klass->blittable = TRUE;
5442 } else if (!strcmp(name, "IntPtr")) {
5443 t = MONO_TYPE_I;
5444 klass->blittable = TRUE;
5446 break;
5447 case 'S':
5448 if (!strcmp (name, "Single")) {
5449 t = MONO_TYPE_R4;
5450 klass->blittable = TRUE;
5451 } else if (!strcmp(name, "SByte")) {
5452 t = MONO_TYPE_I1;
5453 klass->blittable = TRUE;
5455 break;
5456 case 'U':
5457 if (!strcmp (name, "UInt32")) {
5458 t = MONO_TYPE_U4;
5459 klass->blittable = TRUE;
5460 } else if (!strcmp(name, "UInt16")) {
5461 t = MONO_TYPE_U2;
5462 klass->blittable = TRUE;
5463 } else if (!strcmp(name, "UInt64")) {
5464 t = MONO_TYPE_U8;
5465 klass->blittable = TRUE;
5466 } else if (!strcmp(name, "UIntPtr")) {
5467 t = MONO_TYPE_U;
5468 klass->blittable = TRUE;
5470 break;
5471 case 'T':
5472 if (!strcmp (name, "TypedReference")) {
5473 t = MONO_TYPE_TYPEDBYREF;
5474 klass->blittable = TRUE;
5476 break;
5477 case 'V':
5478 if (!strcmp (name, "Void")) {
5479 t = MONO_TYPE_VOID;
5481 break;
5482 default:
5483 break;
5486 klass->byval_arg.type = (MonoTypeEnum)t;
5487 klass->this_arg.type = (MonoTypeEnum)t;
5490 if (MONO_CLASS_IS_INTERFACE (klass))
5491 klass->interface_id = mono_get_unique_iid (klass);
5495 #ifndef DISABLE_COM
5497 * COM initialization is delayed until needed.
5498 * However when a [ComImport] attribute is present on a type it will trigger
5499 * the initialization. This is not a problem unless the BCL being executed
5500 * lacks the types that COM depends on (e.g. Variant on Silverlight).
5502 static void
5503 init_com_from_comimport (MonoClass *klass)
5505 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
5506 if (mono_security_core_clr_enabled ()) {
5507 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
5508 if (!mono_security_core_clr_determine_platform_image (klass->image)) {
5509 /* but it can not be made available for application (i.e. user code) since all COM calls
5510 * are considered native calls. In this case we fail with a TypeLoadException (just like
5511 * Silverlight 2 does */
5512 mono_class_set_type_load_failure (klass, "");
5513 return;
5517 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
5519 #endif /*DISABLE_COM*/
5522 * LOCKING: this assumes the loader lock is held
5524 void
5525 mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
5527 gboolean system_namespace;
5528 gboolean is_corlib = mono_is_corlib_image (klass->image);
5530 system_namespace = !strcmp (klass->name_space, "System") && is_corlib;
5532 /* if root of the hierarchy */
5533 if (system_namespace && !strcmp (klass->name, "Object")) {
5534 klass->parent = NULL;
5535 klass->instance_size = sizeof (MonoObject);
5536 return;
5538 if (!strcmp (klass->name, "<Module>")) {
5539 klass->parent = NULL;
5540 klass->instance_size = 0;
5541 return;
5544 if (!MONO_CLASS_IS_INTERFACE (klass)) {
5545 /* Imported COM Objects always derive from __ComObject. */
5546 #ifndef DISABLE_COM
5547 if (MONO_CLASS_IS_IMPORT (klass)) {
5548 init_com_from_comimport (klass);
5549 if (parent == mono_defaults.object_class)
5550 parent = mono_class_get_com_object_class ();
5552 #endif
5553 if (!parent) {
5554 /* set the parent to something useful and safe, but mark the type as broken */
5555 parent = mono_defaults.object_class;
5556 mono_class_set_type_load_failure (klass, "");
5559 klass->parent = parent;
5561 if (parent->generic_class && !parent->name) {
5563 * If the parent is a generic instance, we may get
5564 * called before it is fully initialized, especially
5565 * before it has its name.
5567 return;
5570 #ifndef DISABLE_REMOTING
5571 klass->marshalbyref = parent->marshalbyref;
5572 klass->contextbound = parent->contextbound;
5573 #endif
5575 klass->delegate = parent->delegate;
5577 if (MONO_CLASS_IS_IMPORT (klass) || mono_class_is_com_object (parent))
5578 mono_class_set_is_com_object (klass);
5580 if (system_namespace) {
5581 #ifndef DISABLE_REMOTING
5582 if (klass->name [0] == 'M' && !strcmp (klass->name, "MarshalByRefObject"))
5583 klass->marshalbyref = 1;
5585 if (klass->name [0] == 'C' && !strcmp (klass->name, "ContextBoundObject"))
5586 klass->contextbound = 1;
5587 #endif
5588 if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate"))
5589 klass->delegate = 1;
5592 if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) &&
5593 (strcmp (klass->parent->name_space, "System") == 0)))
5594 klass->valuetype = 1;
5595 if (mono_is_corlib_image (klass->parent->image) && ((strcmp (klass->parent->name, "Enum") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) {
5596 klass->valuetype = klass->enumtype = 1;
5598 /*klass->enumtype = klass->parent->enumtype; */
5599 } else {
5600 /* initialize com types if COM interfaces are present */
5601 #ifndef DISABLE_COM
5602 if (MONO_CLASS_IS_IMPORT (klass))
5603 init_com_from_comimport (klass);
5604 #endif
5605 klass->parent = NULL;
5611 * mono_class_setup_supertypes:
5612 * @class: a class
5614 * Build the data structure needed to make fast type checks work.
5615 * This currently sets two fields in @class:
5616 * - idepth: distance between @class and System.Object in the type
5617 * hierarchy + 1
5618 * - supertypes: array of classes: each element has a class in the hierarchy
5619 * starting from @class up to System.Object
5621 * LOCKING: This function is atomic, in case of contention we waste memory.
5623 void
5624 mono_class_setup_supertypes (MonoClass *klass)
5626 int ms;
5627 MonoClass **supertypes;
5629 mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes);
5630 if (supertypes)
5631 return;
5633 if (klass->parent && !klass->parent->supertypes)
5634 mono_class_setup_supertypes (klass->parent);
5635 if (klass->parent)
5636 klass->idepth = klass->parent->idepth + 1;
5637 else
5638 klass->idepth = 1;
5640 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, klass->idepth);
5641 supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
5643 if (klass->parent) {
5644 CHECKED_METADATA_WRITE_PTR ( supertypes [klass->idepth - 1] , klass );
5646 int supertype_idx;
5647 for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
5648 CHECKED_METADATA_WRITE_PTR ( supertypes [supertype_idx] , klass->parent->supertypes [supertype_idx] );
5649 } else {
5650 CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
5653 CHECKED_METADATA_WRITE_PTR_ATOMIC ( klass->supertypes , supertypes );
5656 static gboolean
5657 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
5659 MonoClass *gtd = (MonoClass*)user_data;
5660 /* Only try to fix generic instances of @gtd */
5661 if (gclass->generic_class->container_class != gtd)
5662 return FALSE;
5664 /* Check if the generic instance has no parent. */
5665 if (gtd->parent && !gclass->parent)
5666 mono_generic_class_setup_parent (gclass, gtd);
5668 return TRUE;
5671 static void
5672 mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
5674 mono_class_set_type_load_failure (klass, "%s", msg);
5675 mono_error_set_type_load_class (error, klass, "%s", msg);
5679 * mono_class_create_from_typedef:
5680 * @image: image where the token is valid
5681 * @type_token: typedef token
5682 * @error: used to return any error found while creating the type
5684 * Create the MonoClass* representing the specified type token.
5685 * @type_token must be a TypeDef token.
5687 * FIXME: don't return NULL on failure, just the the caller figure it out.
5689 static MonoClass *
5690 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
5692 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
5693 MonoClass *klass, *parent = NULL;
5694 guint32 cols [MONO_TYPEDEF_SIZE];
5695 guint32 cols_next [MONO_TYPEDEF_SIZE];
5696 guint tidx = mono_metadata_token_index (type_token);
5697 MonoGenericContext *context = NULL;
5698 const char *name, *nspace;
5699 guint icount = 0;
5700 MonoClass **interfaces;
5701 guint32 field_last, method_last;
5702 guint32 nesting_tokeen;
5704 mono_error_init (error);
5706 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
5707 mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
5708 return NULL;
5711 mono_loader_lock ();
5713 if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
5714 mono_loader_unlock ();
5715 return klass;
5718 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
5720 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
5721 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
5723 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
5725 klass->name = name;
5726 klass->name_space = nspace;
5728 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
5730 klass->image = image;
5731 klass->type_token = type_token;
5732 klass->flags = cols [MONO_TYPEDEF_FLAGS];
5734 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
5736 classes_size += sizeof (MonoClass);
5739 * Check whether we're a generic type definition.
5741 klass->generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
5742 if (klass->generic_container) {
5743 klass->is_generic = 1;
5744 klass->generic_container->owner.klass = klass;
5745 klass->generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
5746 context = &klass->generic_container->context;
5749 if (klass->generic_container)
5750 enable_gclass_recording ();
5752 if (cols [MONO_TYPEDEF_EXTENDS]) {
5753 MonoClass *tmp;
5754 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
5756 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
5757 /*WARNING: this must satisfy mono_metadata_type_hash*/
5758 klass->this_arg.byref = 1;
5759 klass->this_arg.data.klass = klass;
5760 klass->this_arg.type = MONO_TYPE_CLASS;
5761 klass->byval_arg.data.klass = klass;
5762 klass->byval_arg.type = MONO_TYPE_CLASS;
5764 parent = mono_class_get_checked (image, parent_token, error);
5765 if (parent && context) /* Always inflate */
5766 parent = mono_class_inflate_generic_class_checked (parent, context, error);
5768 if (parent == NULL) {
5769 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5770 goto parent_failure;
5773 for (tmp = parent; tmp; tmp = tmp->parent) {
5774 if (tmp == klass) {
5775 mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
5776 goto parent_failure;
5778 if (klass->generic_container && tmp->generic_class && tmp->generic_class->container_class == klass) {
5779 mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
5780 goto parent_failure;
5785 mono_class_setup_parent (klass, parent);
5787 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
5788 mono_class_setup_mono_type (klass);
5790 if (klass->generic_container)
5791 disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
5794 * This might access klass->byval_arg for recursion generated by generic constraints,
5795 * so it has to come after setup_mono_type ().
5797 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
5798 klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
5799 if (!mono_error_ok (error)) {
5800 /*FIXME implement a mono_class_set_failure_from_mono_error */
5801 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5802 mono_loader_unlock ();
5803 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5804 return NULL;
5808 if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
5809 klass->unicode = 1;
5811 #ifdef HOST_WIN32
5812 if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
5813 klass->unicode = 1;
5814 #endif
5816 klass->cast_class = klass->element_class = klass;
5818 if (!klass->enumtype) {
5819 if (!mono_metadata_interfaces_from_typedef_full (
5820 image, type_token, &interfaces, &icount, FALSE, context, error)){
5822 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5823 mono_loader_unlock ();
5824 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5825 return NULL;
5828 klass->interfaces = interfaces;
5829 klass->interface_count = icount;
5830 klass->interfaces_inited = 1;
5833 /*g_print ("Load class %s\n", name);*/
5836 * Compute the field and method lists
5838 klass->field.first = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
5839 klass->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
5841 if (tt->rows > tidx){
5842 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
5843 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
5844 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
5845 } else {
5846 field_last = image->tables [MONO_TABLE_FIELD].rows;
5847 method_last = image->tables [MONO_TABLE_METHOD].rows;
5850 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
5851 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
5852 klass->field.count = field_last - klass->field.first;
5853 else
5854 klass->field.count = 0;
5856 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
5857 klass->method.count = method_last - klass->method.first;
5858 else
5859 klass->method.count = 0;
5861 /* reserve space to store vector pointer in arrays */
5862 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
5863 klass->instance_size += 2 * sizeof (gpointer);
5864 g_assert (klass->field.count == 0);
5867 if (klass->enumtype) {
5868 MonoType *enum_basetype = mono_class_find_enum_basetype (klass, error);
5869 if (!enum_basetype) {
5870 /*set it to a default value as the whole runtime can't handle this to be null*/
5871 klass->cast_class = klass->element_class = mono_defaults.int32_class;
5872 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5873 mono_loader_unlock ();
5874 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5875 return NULL;
5877 klass->cast_class = klass->element_class = mono_class_from_mono_type (enum_basetype);
5881 * If we're a generic type definition, load the constraints.
5882 * We must do this after the class has been constructed to make certain recursive scenarios
5883 * work.
5885 if (klass->generic_container && !mono_metadata_load_generic_param_constraints_checked (image, type_token, klass->generic_container, error)) {
5886 mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
5887 mono_loader_unlock ();
5888 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5889 return NULL;
5892 if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
5893 if (!strncmp (name, "Vector", 6))
5894 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");
5897 mono_loader_unlock ();
5899 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
5901 return klass;
5903 parent_failure:
5904 mono_class_setup_mono_type (klass);
5905 mono_loader_unlock ();
5906 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5907 return NULL;
5910 /** Is klass a Nullable<T> ginst? */
5911 gboolean
5912 mono_class_is_nullable (MonoClass *klass)
5914 return klass->generic_class != NULL &&
5915 klass->generic_class->container_class == mono_defaults.generic_nullable_class;
5919 /** if klass is T? return T */
5920 MonoClass*
5921 mono_class_get_nullable_param (MonoClass *klass)
5923 g_assert (mono_class_is_nullable (klass));
5924 return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
5927 static void
5928 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
5930 if (gtd->parent) {
5931 MonoError error;
5932 MonoGenericClass *gclass = klass->generic_class;
5934 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
5935 if (!mono_error_ok (&error)) {
5936 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
5937 klass->parent = mono_defaults.object_class;
5938 mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (&error));
5939 mono_error_cleanup (&error);
5942 if (klass->parent)
5943 mono_class_setup_parent (klass, klass->parent);
5945 if (klass->enumtype) {
5946 klass->cast_class = gtd->cast_class;
5947 klass->element_class = gtd->element_class;
5953 * Create the `MonoClass' for an instantiation of a generic type.
5954 * We only do this if we actually need it.
5956 MonoClass*
5957 mono_generic_class_get_class (MonoGenericClass *gclass)
5959 MonoClass *klass, *gklass;
5961 if (gclass->cached_class)
5962 return gclass->cached_class;
5964 mono_loader_lock ();
5965 if (gclass->cached_class) {
5966 mono_loader_unlock ();
5967 return gclass->cached_class;
5970 klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
5972 gklass = gclass->container_class;
5974 if (record_gclass_instantiation > 0)
5975 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
5977 if (gklass->nested_in) {
5978 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
5979 klass->nested_in = gklass->nested_in;
5982 klass->name = gklass->name;
5983 klass->name_space = gklass->name_space;
5985 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
5987 klass->image = gklass->image;
5988 klass->flags = gklass->flags;
5989 klass->type_token = gklass->type_token;
5990 klass->field.count = gklass->field.count;
5992 klass->is_inflated = 1;
5993 klass->generic_class = gclass;
5995 klass->byval_arg.type = MONO_TYPE_GENERICINST;
5996 klass->this_arg.type = klass->byval_arg.type;
5997 klass->this_arg.data.generic_class = klass->byval_arg.data.generic_class = gclass;
5998 klass->this_arg.byref = TRUE;
5999 klass->enumtype = gklass->enumtype;
6000 klass->valuetype = gklass->valuetype;
6002 klass->cast_class = klass->element_class = klass;
6004 if (mono_class_is_nullable (klass))
6005 klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
6008 * We're not interested in the nested classes of a generic instance.
6009 * We use the generic type definition to look for nested classes.
6012 mono_generic_class_setup_parent (klass, gklass);
6014 if (gclass->is_dynamic) {
6016 * 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.
6017 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
6018 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
6020 if (!gklass->wastypebuilder)
6021 klass->inited = 1;
6023 mono_class_setup_supertypes (klass);
6025 if (klass->enumtype) {
6027 * For enums, gklass->fields might not been set, but instance_size etc. is
6028 * already set in mono_reflection_create_internal_class (). For non-enums,
6029 * these will be computed normally in mono_class_layout_fields ().
6031 klass->instance_size = gklass->instance_size;
6032 klass->sizes.class_size = gklass->sizes.class_size;
6033 mono_memory_barrier ();
6034 klass->size_inited = 1;
6038 mono_memory_barrier ();
6039 gclass->cached_class = klass;
6041 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6043 inflated_classes ++;
6044 inflated_classes_size += sizeof (MonoClass);
6046 mono_loader_unlock ();
6048 return klass;
6051 static MonoImage *
6052 get_image_for_container (MonoGenericContainer *container)
6054 MonoImage *result;
6055 if (container->is_anonymous) {
6056 result = container->owner.image;
6057 } else {
6058 MonoClass *klass;
6059 if (container->is_method) {
6060 MonoMethod *method = container->owner.method;
6061 g_assert_checked (method);
6062 klass = method->klass;
6063 } else {
6064 klass = container->owner.klass;
6066 g_assert_checked (klass);
6067 result = klass->image;
6069 g_assert (result);
6070 return result;
6073 MonoImage *
6074 get_image_for_generic_param (MonoGenericParam *param)
6076 MonoGenericContainer *container = mono_generic_param_owner (param);
6077 g_assert_checked (container);
6078 return get_image_for_container (container);
6081 // Make a string in the designated image consisting of a single integer.
6082 #define INT_STRING_SIZE 16
6083 char *
6084 make_generic_name_string (MonoImage *image, int num)
6086 char *name = (char *)mono_image_alloc0 (image, INT_STRING_SIZE);
6087 g_snprintf (name, INT_STRING_SIZE, "%d", num);
6088 return name;
6091 // This is called by mono_class_from_generic_parameter_internal when a new class must be created.
6092 // pinfo is derived from param by the caller for us.
6093 static MonoClass*
6094 make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
6096 MonoClass *klass, **ptr;
6097 int count, pos, i;
6098 MonoGenericContainer *container = mono_generic_param_owner (param);
6099 g_assert_checked (container);
6101 MonoImage *image = get_image_for_container (container);
6102 gboolean is_mvar = container->is_method;
6103 gboolean is_anonymous = container->is_anonymous;
6105 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
6106 classes_size += sizeof (MonoClass);
6108 if (pinfo) {
6109 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
6110 } else {
6111 int n = mono_generic_param_num (param);
6112 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->name , make_generic_name_string (image, n) );
6115 if (is_anonymous) {
6116 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , "" );
6117 } else if (is_mvar) {
6118 MonoMethod *omethod = container->owner.method;
6119 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , (omethod && omethod->klass) ? omethod->klass->name_space : "" );
6120 } else {
6121 MonoClass *oklass = container->owner.klass;
6122 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
6125 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
6127 // Count non-NULL items in pinfo->constraints
6128 count = 0;
6129 if (pinfo)
6130 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
6133 pos = 0;
6134 if ((count > 0) && !MONO_CLASS_IS_INTERFACE (pinfo->constraints [0])) {
6135 CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
6136 pos++;
6137 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
6138 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
6139 } else {
6140 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
6143 if (count - pos > 0) {
6144 klass->interface_count = count - pos;
6145 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->interfaces , (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos)) );
6146 klass->interfaces_inited = TRUE;
6147 for (i = pos; i < count; i++)
6148 CHECKED_METADATA_WRITE_PTR ( klass->interfaces [i - pos] , pinfo->constraints [i] );
6151 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->image , image );
6153 klass->inited = TRUE;
6154 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
6155 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
6156 klass->flags = TYPE_ATTRIBUTE_PUBLIC;
6158 klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
6159 klass->this_arg.type = klass->byval_arg.type;
6160 CHECKED_METADATA_WRITE_PTR ( klass->this_arg.data.generic_param , param );
6161 CHECKED_METADATA_WRITE_PTR ( klass->byval_arg.data.generic_param , param );
6162 klass->this_arg.byref = TRUE;
6164 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
6165 klass->sizes.generic_param_token = pinfo ? pinfo->token : 0;
6167 /*Init these fields to sane values*/
6168 klass->min_align = 1;
6170 * This makes sure the the value size of this class is equal to the size of the types the gparam is
6171 * constrained to, the JIT depends on this.
6173 klass->instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
6174 mono_memory_barrier ();
6175 klass->size_inited = 1;
6177 mono_class_setup_supertypes (klass);
6179 if (count - pos > 0) {
6180 mono_class_setup_vtable (klass->parent);
6181 if (mono_class_has_failure (klass->parent))
6182 mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
6183 else
6184 setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
6187 return klass;
6190 #define FAST_CACHE_SIZE 16
6193 * get_anon_gparam_class and set_anon_gparam_class are helpers for mono_class_from_generic_parameter_internal.
6194 * The latter will sometimes create MonoClasses for anonymous generic params. To prevent this being wasteful,
6195 * we cache the MonoClasses.
6196 * FIXME: It would be better to instead cache anonymous MonoGenericParams, and allow anonymous params to point directly to classes using the pklass field.
6197 * LOCKING: Takes the image lock depending on @take_lock.
6199 static MonoClass *
6200 get_anon_gparam_class (MonoGenericParam *param, gboolean take_lock)
6202 int n = mono_generic_param_num (param);
6203 MonoImage *image = get_image_for_generic_param (param);
6204 gboolean is_mvar = mono_generic_param_owner (param)->is_method;
6205 MonoClass *klass = NULL;
6206 GHashTable *ht;
6208 g_assert (image);
6210 // For params with a small num and no constraints, we use a "fast" cache which does simple num lookup in an array.
6211 // For high numbers or constraints we have to use pointer hashes.
6212 if (param->gshared_constraint) {
6213 ht = is_mvar ? image->mvar_cache_constrained : image->var_cache_constrained;
6214 if (ht) {
6215 if (take_lock)
6216 mono_image_lock (image);
6217 klass = (MonoClass *)g_hash_table_lookup (ht, param);
6218 if (take_lock)
6219 mono_image_unlock (image);
6221 return klass;
6224 if (n < FAST_CACHE_SIZE) {
6225 if (is_mvar)
6226 return image->mvar_cache_fast ? image->mvar_cache_fast [n] : NULL;
6227 else
6228 return image->var_cache_fast ? image->var_cache_fast [n] : NULL;
6229 } else {
6230 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6231 if (ht) {
6232 if (take_lock)
6233 mono_image_lock (image);
6234 klass = (MonoClass *)g_hash_table_lookup (ht, GINT_TO_POINTER (n));
6235 if (take_lock)
6236 mono_image_unlock (image);
6238 return klass;
6243 * LOCKING: Image lock (param->image) must be held
6245 static void
6246 set_anon_gparam_class (MonoGenericParam *param, MonoClass *klass)
6248 int n = mono_generic_param_num (param);
6249 MonoImage *image = get_image_for_generic_param (param);
6250 gboolean is_mvar = mono_generic_param_owner (param)->is_method;
6252 g_assert (image);
6254 if (param->gshared_constraint) {
6255 GHashTable *ht = is_mvar ? image->mvar_cache_constrained : image->var_cache_constrained;
6256 if (!ht) {
6257 ht = g_hash_table_new ((GHashFunc)mono_metadata_generic_param_hash, (GEqualFunc)mono_metadata_generic_param_equal);
6258 mono_memory_barrier ();
6259 if (is_mvar)
6260 image->mvar_cache_constrained = ht;
6261 else
6262 image->var_cache_constrained = ht;
6264 g_hash_table_insert (ht, param, klass);
6265 } else if (n < FAST_CACHE_SIZE) {
6266 if (is_mvar) {
6267 /* Requires locking to avoid droping an already published class */
6268 if (!image->mvar_cache_fast)
6269 image->mvar_cache_fast = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6270 image->mvar_cache_fast [n] = klass;
6271 } else {
6272 if (!image->var_cache_fast)
6273 image->var_cache_fast = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6274 image->var_cache_fast [n] = klass;
6276 } else {
6277 GHashTable *ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6278 if (!ht) {
6279 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6280 if (!ht) {
6281 ht = g_hash_table_new (NULL, NULL);
6282 mono_memory_barrier ();
6283 if (is_mvar)
6284 image->mvar_cache_slow = ht;
6285 else
6286 image->var_cache_slow = ht;
6289 g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
6294 * LOCKING: Acquires the image lock (@image).
6296 MonoClass *
6297 mono_class_from_generic_parameter_internal (MonoGenericParam *param)
6299 MonoImage *image = get_image_for_generic_param (param);
6300 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
6301 MonoClass *klass, *klass2;
6303 // If a klass already exists for this object and is cached, return it.
6304 if (pinfo) // Non-anonymous
6305 klass = pinfo->pklass;
6306 else // Anonymous
6307 klass = get_anon_gparam_class (param, TRUE);
6309 if (klass)
6310 return klass;
6312 // Create a new klass
6313 klass = make_generic_param_class (param, pinfo);
6315 // Now we need to cache the klass we created.
6316 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
6317 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
6318 // and allow our newly-created klass object to just leak.
6319 mono_memory_barrier ();
6321 mono_image_lock (image);
6323 // Here "klass2" refers to the klass potentially created by the other thread.
6324 if (pinfo) // Repeat check from above
6325 klass2 = pinfo->pklass;
6326 else
6327 klass2 = get_anon_gparam_class (param, FALSE);
6329 if (klass2) {
6330 klass = klass2;
6331 } else {
6332 // Cache here
6333 if (pinfo)
6334 pinfo->pklass = klass;
6335 else
6336 set_anon_gparam_class (param, klass);
6338 mono_image_unlock (image);
6340 /* FIXME: Should this go inside 'make_generic_param_klass'? */
6341 if (klass2)
6342 mono_profiler_class_loaded (klass2, MONO_PROFILE_FAILED); // Alert profiler about botched class create
6343 else
6344 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6346 return klass;
6350 * mono_class_from_generic_parameter:
6351 * @param: Parameter to find/construct a class for.
6352 * @arg2: Is ignored.
6353 * @arg3: Is ignored.
6355 MonoClass *
6356 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GNUC_UNUSED, gboolean arg3 G_GNUC_UNUSED)
6358 return mono_class_from_generic_parameter_internal (param);
6362 MonoClass *
6363 mono_ptr_class_get (MonoType *type)
6365 MonoClass *result;
6366 MonoClass *el_class;
6367 MonoImage *image;
6368 char *name;
6370 el_class = mono_class_from_mono_type (type);
6371 image = el_class->image;
6373 mono_image_lock (image);
6374 if (image->ptr_cache) {
6375 if ((result = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
6376 mono_image_unlock (image);
6377 return result;
6380 mono_image_unlock (image);
6382 result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
6384 classes_size += sizeof (MonoClass);
6386 result->parent = NULL; /* no parent for PTR types */
6387 result->name_space = el_class->name_space;
6388 name = g_strdup_printf ("%s*", el_class->name);
6389 result->name = mono_image_strdup (image, name);
6390 g_free (name);
6392 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6394 result->image = el_class->image;
6395 result->inited = TRUE;
6396 result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
6397 result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
6398 result->cast_class = result->element_class = el_class;
6399 result->blittable = TRUE;
6401 result->byval_arg.type = MONO_TYPE_PTR;
6402 result->this_arg.type = result->byval_arg.type;
6403 result->this_arg.data.type = result->byval_arg.data.type = &result->element_class->byval_arg;
6404 result->this_arg.byref = TRUE;
6406 mono_class_setup_supertypes (result);
6408 mono_image_lock (image);
6409 if (image->ptr_cache) {
6410 MonoClass *result2;
6411 if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
6412 mono_image_unlock (image);
6413 mono_profiler_class_loaded (result, MONO_PROFILE_FAILED);
6414 return result2;
6416 } else {
6417 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6419 g_hash_table_insert (image->ptr_cache, el_class, result);
6420 mono_image_unlock (image);
6422 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6424 return result;
6427 static MonoClass *
6428 mono_fnptr_class_get (MonoMethodSignature *sig)
6430 MonoClass *result;
6431 static GHashTable *ptr_hash = NULL;
6433 /* FIXME: These should be allocate from a mempool as well, but which one ? */
6435 mono_loader_lock ();
6437 if (!ptr_hash)
6438 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
6440 if ((result = (MonoClass *)g_hash_table_lookup (ptr_hash, sig))) {
6441 mono_loader_unlock ();
6442 return result;
6444 result = g_new0 (MonoClass, 1);
6446 result->parent = NULL; /* no parent for PTR types */
6447 result->name_space = "System";
6448 result->name = "MonoFNPtrFakeClass";
6450 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6452 result->image = mono_defaults.corlib; /* need to fix... */
6453 result->inited = TRUE;
6454 result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */
6455 result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
6456 result->cast_class = result->element_class = result;
6457 result->blittable = TRUE;
6459 result->byval_arg.type = MONO_TYPE_FNPTR;
6460 result->this_arg.type = result->byval_arg.type;
6461 result->this_arg.data.method = result->byval_arg.data.method = sig;
6462 result->this_arg.byref = TRUE;
6463 result->blittable = TRUE;
6465 mono_class_setup_supertypes (result);
6467 g_hash_table_insert (ptr_hash, sig, result);
6469 mono_loader_unlock ();
6471 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6473 return result;
6477 * mono_class_from_mono_type:
6478 * @type: describes the type to return
6480 * This returns a MonoClass for the specified MonoType, the value is never NULL.
6482 MonoClass *
6483 mono_class_from_mono_type (MonoType *type)
6485 switch (type->type) {
6486 case MONO_TYPE_OBJECT:
6487 return type->data.klass? type->data.klass: mono_defaults.object_class;
6488 case MONO_TYPE_VOID:
6489 return type->data.klass? type->data.klass: mono_defaults.void_class;
6490 case MONO_TYPE_BOOLEAN:
6491 return type->data.klass? type->data.klass: mono_defaults.boolean_class;
6492 case MONO_TYPE_CHAR:
6493 return type->data.klass? type->data.klass: mono_defaults.char_class;
6494 case MONO_TYPE_I1:
6495 return type->data.klass? type->data.klass: mono_defaults.sbyte_class;
6496 case MONO_TYPE_U1:
6497 return type->data.klass? type->data.klass: mono_defaults.byte_class;
6498 case MONO_TYPE_I2:
6499 return type->data.klass? type->data.klass: mono_defaults.int16_class;
6500 case MONO_TYPE_U2:
6501 return type->data.klass? type->data.klass: mono_defaults.uint16_class;
6502 case MONO_TYPE_I4:
6503 return type->data.klass? type->data.klass: mono_defaults.int32_class;
6504 case MONO_TYPE_U4:
6505 return type->data.klass? type->data.klass: mono_defaults.uint32_class;
6506 case MONO_TYPE_I:
6507 return type->data.klass? type->data.klass: mono_defaults.int_class;
6508 case MONO_TYPE_U:
6509 return type->data.klass? type->data.klass: mono_defaults.uint_class;
6510 case MONO_TYPE_I8:
6511 return type->data.klass? type->data.klass: mono_defaults.int64_class;
6512 case MONO_TYPE_U8:
6513 return type->data.klass? type->data.klass: mono_defaults.uint64_class;
6514 case MONO_TYPE_R4:
6515 return type->data.klass? type->data.klass: mono_defaults.single_class;
6516 case MONO_TYPE_R8:
6517 return type->data.klass? type->data.klass: mono_defaults.double_class;
6518 case MONO_TYPE_STRING:
6519 return type->data.klass? type->data.klass: mono_defaults.string_class;
6520 case MONO_TYPE_TYPEDBYREF:
6521 return type->data.klass? type->data.klass: mono_defaults.typed_reference_class;
6522 case MONO_TYPE_ARRAY:
6523 return mono_bounded_array_class_get (type->data.array->eklass, type->data.array->rank, TRUE);
6524 case MONO_TYPE_PTR:
6525 return mono_ptr_class_get (type->data.type);
6526 case MONO_TYPE_FNPTR:
6527 return mono_fnptr_class_get (type->data.method);
6528 case MONO_TYPE_SZARRAY:
6529 return mono_array_class_get (type->data.klass, 1);
6530 case MONO_TYPE_CLASS:
6531 case MONO_TYPE_VALUETYPE:
6532 return type->data.klass;
6533 case MONO_TYPE_GENERICINST:
6534 return mono_generic_class_get_class (type->data.generic_class);
6535 case MONO_TYPE_MVAR:
6536 case MONO_TYPE_VAR:
6537 return mono_class_from_generic_parameter_internal (type->data.generic_param);
6538 default:
6539 g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
6540 g_assert_not_reached ();
6543 // Yes, this returns NULL, even if it is documented as not doing so, but there
6544 // is no way for the code to make it this far, due to the assert above.
6545 return NULL;
6549 * mono_type_retrieve_from_typespec
6550 * @image: context where the image is created
6551 * @type_spec: typespec token
6552 * @context: the generic context used to evaluate generic instantiations in
6554 static MonoType *
6555 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
6557 MonoType *t = mono_type_create_from_typespec_checked (image, type_spec, error);
6559 *did_inflate = FALSE;
6561 if (!t)
6562 return NULL;
6564 if (context && (context->class_inst || context->method_inst)) {
6565 MonoType *inflated = inflate_generic_type (NULL, t, context, error);
6567 if (!mono_error_ok (error)) {
6568 return NULL;
6571 if (inflated) {
6572 t = inflated;
6573 *did_inflate = TRUE;
6576 return t;
6580 * mono_class_create_from_typespec
6581 * @image: context where the image is created
6582 * @type_spec: typespec token
6583 * @context: the generic context used to evaluate generic instantiations in
6585 static MonoClass *
6586 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
6588 MonoClass *ret;
6589 gboolean inflated = FALSE;
6590 MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
6591 return_val_if_nok (error, NULL);
6592 ret = mono_class_from_mono_type (t);
6593 if (inflated)
6594 mono_metadata_free_type (t);
6595 return ret;
6599 * mono_bounded_array_class_get:
6600 * @element_class: element class
6601 * @rank: the dimension of the array class
6602 * @bounded: whenever the array has non-zero bounds
6604 * Returns: A class object describing the array with element type @element_type and
6605 * dimension @rank.
6607 MonoClass *
6608 mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
6610 MonoImage *image;
6611 MonoClass *klass;
6612 MonoClass *parent = NULL;
6613 GSList *list, *rootlist = NULL;
6614 int nsize;
6615 char *name;
6617 g_assert (rank <= 255);
6619 if (rank > 1)
6620 /* bounded only matters for one-dimensional arrays */
6621 bounded = FALSE;
6623 image = eclass->image;
6625 if (rank == 1 && !bounded) {
6627 * This case is very frequent not just during compilation because of calls
6628 * from mono_class_from_mono_type (), mono_array_new (),
6629 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
6631 mono_os_mutex_lock (&image->szarray_cache_lock);
6632 if (!image->szarray_cache)
6633 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6634 klass = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
6635 mono_os_mutex_unlock (&image->szarray_cache_lock);
6636 if (klass)
6637 return klass;
6639 mono_loader_lock ();
6640 } else {
6641 mono_loader_lock ();
6643 if (!image->array_cache)
6644 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6646 if ((rootlist = list = (GSList *)g_hash_table_lookup (image->array_cache, eclass))) {
6647 for (; list; list = list->next) {
6648 klass = (MonoClass *)list->data;
6649 if ((klass->rank == rank) && (klass->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
6650 mono_loader_unlock ();
6651 return klass;
6657 parent = mono_defaults.array_class;
6658 if (!parent->inited)
6659 mono_class_init (parent);
6661 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
6663 klass->image = image;
6664 klass->name_space = eclass->name_space;
6665 nsize = strlen (eclass->name);
6666 name = (char *)g_malloc (nsize + 2 + rank + 1);
6667 memcpy (name, eclass->name, nsize);
6668 name [nsize] = '[';
6669 if (rank > 1)
6670 memset (name + nsize + 1, ',', rank - 1);
6671 if (bounded)
6672 name [nsize + rank] = '*';
6673 name [nsize + rank + bounded] = ']';
6674 name [nsize + rank + bounded + 1] = 0;
6675 klass->name = mono_image_strdup (image, name);
6676 g_free (name);
6678 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
6680 classes_size += sizeof (MonoClass);
6682 klass->type_token = 0;
6683 /* all arrays are marked serializable and sealed, bug #42779 */
6684 klass->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC;
6685 klass->parent = parent;
6686 klass->instance_size = mono_class_instance_size (klass->parent);
6688 if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
6689 /*Arrays of those two types are invalid.*/
6690 MonoError prepared_error;
6691 mono_error_init (&prepared_error);
6692 mono_error_set_invalid_program (&prepared_error, "Arrays of void or System.TypedReference types are invalid.");
6693 mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
6694 mono_error_cleanup (&prepared_error);
6695 } else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
6696 if (!eclass->ref_info_handle || eclass->wastypebuilder) {
6697 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
6698 g_assert (eclass->ref_info_handle && !eclass->wastypebuilder);
6700 /* element_size -1 is ok as this is not an instantitable type*/
6701 klass->sizes.element_size = -1;
6702 } else
6703 klass->sizes.element_size = mono_class_array_element_size (eclass);
6705 mono_class_setup_supertypes (klass);
6707 if (eclass->generic_class)
6708 mono_class_init (eclass);
6709 if (!eclass->size_inited)
6710 mono_class_setup_fields (eclass);
6711 mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
6712 /*FIXME we fail the array type, but we have to let other fields be set.*/
6714 klass->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
6716 klass->rank = rank;
6718 if (eclass->enumtype)
6719 klass->cast_class = eclass->element_class;
6720 else
6721 klass->cast_class = eclass;
6723 switch (klass->cast_class->byval_arg.type) {
6724 case MONO_TYPE_I1:
6725 klass->cast_class = mono_defaults.byte_class;
6726 break;
6727 case MONO_TYPE_U2:
6728 klass->cast_class = mono_defaults.int16_class;
6729 break;
6730 case MONO_TYPE_U4:
6731 #if SIZEOF_VOID_P == 4
6732 case MONO_TYPE_I:
6733 case MONO_TYPE_U:
6734 #endif
6735 klass->cast_class = mono_defaults.int32_class;
6736 break;
6737 case MONO_TYPE_U8:
6738 #if SIZEOF_VOID_P == 8
6739 case MONO_TYPE_I:
6740 case MONO_TYPE_U:
6741 #endif
6742 klass->cast_class = mono_defaults.int64_class;
6743 break;
6744 default:
6745 break;
6748 klass->element_class = eclass;
6750 if ((rank > 1) || bounded) {
6751 MonoArrayType *at = (MonoArrayType *)mono_image_alloc0 (image, sizeof (MonoArrayType));
6752 klass->byval_arg.type = MONO_TYPE_ARRAY;
6753 klass->byval_arg.data.array = at;
6754 at->eklass = eclass;
6755 at->rank = rank;
6756 /* FIXME: complete.... */
6757 } else {
6758 klass->byval_arg.type = MONO_TYPE_SZARRAY;
6759 klass->byval_arg.data.klass = eclass;
6761 klass->this_arg = klass->byval_arg;
6762 klass->this_arg.byref = 1;
6764 klass->generic_container = eclass->generic_container;
6766 if (rank == 1 && !bounded) {
6767 MonoClass *prev_class;
6769 mono_os_mutex_lock (&image->szarray_cache_lock);
6770 prev_class = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
6771 if (prev_class)
6772 /* Someone got in before us */
6773 klass = prev_class;
6774 else
6775 g_hash_table_insert (image->szarray_cache, eclass, klass);
6776 mono_os_mutex_unlock (&image->szarray_cache_lock);
6777 } else {
6778 list = g_slist_append (rootlist, klass);
6779 g_hash_table_insert (image->array_cache, eclass, list);
6782 mono_loader_unlock ();
6784 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6786 return klass;
6790 * mono_array_class_get:
6791 * @element_class: element class
6792 * @rank: the dimension of the array class
6794 * Returns: A class object describing the array with element type @element_type and
6795 * dimension @rank.
6797 MonoClass *
6798 mono_array_class_get (MonoClass *eclass, guint32 rank)
6800 return mono_bounded_array_class_get (eclass, rank, FALSE);
6804 * mono_class_instance_size:
6805 * @klass: a class
6807 * Use to get the size of a class in bytes.
6809 * Returns: The size of an object instance
6811 gint32
6812 mono_class_instance_size (MonoClass *klass)
6814 if (!klass->size_inited)
6815 mono_class_init (klass);
6817 return klass->instance_size;
6821 * mono_class_min_align:
6822 * @klass: a class
6824 * Use to get the computed minimum alignment requirements for the specified class.
6826 * Returns: minimm alignment requirements
6828 gint32
6829 mono_class_min_align (MonoClass *klass)
6831 if (!klass->size_inited)
6832 mono_class_init (klass);
6834 return klass->min_align;
6838 * mono_class_value_size:
6839 * @klass: a class
6841 * This function is used for value types, and return the
6842 * space and the alignment to store that kind of value object.
6844 * Returns: the size of a value of kind @klass
6846 gint32
6847 mono_class_value_size (MonoClass *klass, guint32 *align)
6849 gint32 size;
6851 /* fixme: check disable, because we still have external revereces to
6852 * mscorlib and Dummy Objects
6854 /*g_assert (klass->valuetype);*/
6856 size = mono_class_instance_size (klass) - sizeof (MonoObject);
6858 if (align)
6859 *align = klass->min_align;
6861 return size;
6865 * mono_class_data_size:
6866 * @klass: a class
6868 * Returns: The size of the static class data
6870 gint32
6871 mono_class_data_size (MonoClass *klass)
6873 if (!klass->inited)
6874 mono_class_init (klass);
6875 /* This can happen with dynamically created types */
6876 if (!klass->fields_inited)
6877 mono_class_setup_fields (klass);
6879 /* in arrays, sizes.class_size is unioned with element_size
6880 * and arrays have no static fields
6882 if (klass->rank)
6883 return 0;
6884 return klass->sizes.class_size;
6888 * Auxiliary routine to mono_class_get_field
6890 * Takes a field index instead of a field token.
6892 static MonoClassField *
6893 mono_class_get_field_idx (MonoClass *klass, int idx)
6895 mono_class_setup_fields (klass);
6896 if (mono_class_has_failure (klass))
6897 return NULL;
6899 while (klass) {
6900 if (klass->image->uncompressed_metadata) {
6902 * klass->field.first points to the FieldPtr table, while idx points into the
6903 * Field table, so we have to do a search.
6905 /*FIXME this is broken for types with multiple fields with the same name.*/
6906 const char *name = mono_metadata_string_heap (klass->image, mono_metadata_decode_row_col (&klass->image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
6907 int i;
6909 for (i = 0; i < klass->field.count; ++i)
6910 if (mono_field_get_name (&klass->fields [i]) == name)
6911 return &klass->fields [i];
6912 g_assert_not_reached ();
6913 } else {
6914 if (klass->field.count) {
6915 if ((idx >= klass->field.first) && (idx < klass->field.first + klass->field.count)){
6916 return &klass->fields [idx - klass->field.first];
6920 klass = klass->parent;
6922 return NULL;
6926 * mono_class_get_field:
6927 * @class: the class to lookup the field.
6928 * @field_token: the field token
6930 * Returns: A MonoClassField representing the type and offset of
6931 * the field, or a NULL value if the field does not belong to this
6932 * class.
6934 MonoClassField *
6935 mono_class_get_field (MonoClass *klass, guint32 field_token)
6937 int idx = mono_metadata_token_index (field_token);
6939 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
6941 return mono_class_get_field_idx (klass, idx - 1);
6945 * mono_class_get_field_from_name:
6946 * @klass: the class to lookup the field.
6947 * @name: the field name
6949 * Search the class @klass and it's parents for a field with the name @name.
6951 * Returns: The MonoClassField pointer of the named field or NULL
6953 MonoClassField *
6954 mono_class_get_field_from_name (MonoClass *klass, const char *name)
6956 return mono_class_get_field_from_name_full (klass, name, NULL);
6960 * mono_class_get_field_from_name_full:
6961 * @klass: the class to lookup the field.
6962 * @name: the field name
6963 * @type: the type of the fields. This optional.
6965 * Search the class @klass and it's parents for a field with the name @name and type @type.
6967 * If @klass is an inflated generic type, the type comparison is done with the equivalent field
6968 * of its generic type definition.
6970 * Returns: The MonoClassField pointer of the named field or NULL
6972 MonoClassField *
6973 mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
6975 int i;
6977 mono_class_setup_fields (klass);
6978 if (mono_class_has_failure (klass))
6979 return NULL;
6981 while (klass) {
6982 for (i = 0; i < klass->field.count; ++i) {
6983 MonoClassField *field = &klass->fields [i];
6985 if (strcmp (name, mono_field_get_name (field)) != 0)
6986 continue;
6988 if (type) {
6989 MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
6990 if (!mono_metadata_type_equal_full (type, field_type, TRUE))
6991 continue;
6993 return field;
6995 klass = klass->parent;
6997 return NULL;
7001 * mono_class_get_field_token:
7002 * @field: the field we need the token of
7004 * Get the token of a field. Note that the tokesn is only valid for the image
7005 * the field was loaded from. Don't use this function for fields in dynamic types.
7007 * Returns: The token representing the field in the image it was loaded from.
7009 guint32
7010 mono_class_get_field_token (MonoClassField *field)
7012 MonoClass *klass = field->parent;
7013 int i;
7015 mono_class_setup_fields (klass);
7017 while (klass) {
7018 if (!klass->fields)
7019 return 0;
7020 for (i = 0; i < klass->field.count; ++i) {
7021 if (&klass->fields [i] == field) {
7022 int idx = klass->field.first + i + 1;
7024 if (klass->image->uncompressed_metadata)
7025 idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx);
7026 return mono_metadata_make_token (MONO_TABLE_FIELD, idx);
7029 klass = klass->parent;
7032 g_assert_not_reached ();
7033 return 0;
7036 static int
7037 mono_field_get_index (MonoClassField *field)
7039 int index = field - field->parent->fields;
7041 g_assert (index >= 0 && index < field->parent->field.count);
7043 return index;
7047 * mono_class_get_field_default_value:
7049 * Return the default value of the field as a pointer into the metadata blob.
7051 const char*
7052 mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
7054 guint32 cindex;
7055 guint32 constant_cols [MONO_CONSTANT_SIZE];
7056 int field_index;
7057 MonoClass *klass = field->parent;
7059 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
7061 if (!klass->ext || !klass->ext->field_def_values) {
7062 MonoFieldDefaultValue *def_values;
7064 mono_class_alloc_ext (klass);
7066 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
7068 mono_image_lock (klass->image);
7069 mono_memory_barrier ();
7070 if (!klass->ext->field_def_values)
7071 klass->ext->field_def_values = def_values;
7072 mono_image_unlock (klass->image);
7075 field_index = mono_field_get_index (field);
7077 if (!klass->ext->field_def_values [field_index].data) {
7078 cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
7079 if (!cindex)
7080 return NULL;
7082 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
7084 mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
7085 klass->ext->field_def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
7086 klass->ext->field_def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
7089 *def_type = klass->ext->field_def_values [field_index].def_type;
7090 return klass->ext->field_def_values [field_index].data;
7093 static int
7094 mono_property_get_index (MonoProperty *prop)
7096 int index = prop - prop->parent->ext->properties;
7098 g_assert (index >= 0 && index < prop->parent->ext->property.count);
7100 return index;
7104 * mono_class_get_property_default_value:
7106 * Return the default value of the field as a pointer into the metadata blob.
7108 const char*
7109 mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type)
7111 guint32 cindex;
7112 guint32 constant_cols [MONO_CONSTANT_SIZE];
7113 MonoClass *klass = property->parent;
7115 g_assert (property->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT);
7117 * We don't cache here because it is not used by C# so it's quite rare, but
7118 * we still do the lookup in klass->ext because that is where the data
7119 * is stored for dynamic assemblies.
7122 if (image_is_dynamic (klass->image)) {
7123 int prop_index = mono_property_get_index (property);
7124 if (klass->ext->prop_def_values && klass->ext->prop_def_values [prop_index].data) {
7125 *def_type = klass->ext->prop_def_values [prop_index].def_type;
7126 return klass->ext->prop_def_values [prop_index].data;
7128 return NULL;
7130 cindex = mono_metadata_get_constant_index (klass->image, mono_class_get_property_token (property), 0);
7131 if (!cindex)
7132 return NULL;
7134 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
7135 *def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
7136 return (const char *)mono_metadata_blob_heap (klass->image, constant_cols [MONO_CONSTANT_VALUE]);
7139 guint32
7140 mono_class_get_event_token (MonoEvent *event)
7142 MonoClass *klass = event->parent;
7143 int i;
7145 while (klass) {
7146 if (klass->ext) {
7147 for (i = 0; i < klass->ext->event.count; ++i) {
7148 if (&klass->ext->events [i] == event)
7149 return mono_metadata_make_token (MONO_TABLE_EVENT, klass->ext->event.first + i + 1);
7152 klass = klass->parent;
7155 g_assert_not_reached ();
7156 return 0;
7160 * mono_class_get_property_from_name:
7161 * @klass: a class
7162 * @name: name of the property to lookup in the specified class
7164 * Use this method to lookup a property in a class
7165 * Returns: the MonoProperty with the given name, or NULL if the property
7166 * does not exist on the @klass.
7168 MonoProperty*
7169 mono_class_get_property_from_name (MonoClass *klass, const char *name)
7171 while (klass) {
7172 MonoProperty* p;
7173 gpointer iter = NULL;
7174 while ((p = mono_class_get_properties (klass, &iter))) {
7175 if (! strcmp (name, p->name))
7176 return p;
7178 klass = klass->parent;
7180 return NULL;
7184 * mono_class_get_property_token:
7185 * @prop: MonoProperty to query
7187 * Returns: The ECMA token for the specified property.
7189 guint32
7190 mono_class_get_property_token (MonoProperty *prop)
7192 MonoClass *klass = prop->parent;
7193 while (klass) {
7194 MonoProperty* p;
7195 int i = 0;
7196 gpointer iter = NULL;
7197 while ((p = mono_class_get_properties (klass, &iter))) {
7198 if (&klass->ext->properties [i] == prop)
7199 return mono_metadata_make_token (MONO_TABLE_PROPERTY, klass->ext->property.first + i + 1);
7201 i ++;
7203 klass = klass->parent;
7206 g_assert_not_reached ();
7207 return 0;
7210 char *
7211 mono_class_name_from_token (MonoImage *image, guint32 type_token)
7213 const char *name, *nspace;
7214 if (image_is_dynamic (image))
7215 return g_strdup_printf ("DynamicType 0x%08x", type_token);
7217 switch (type_token & 0xff000000){
7218 case MONO_TOKEN_TYPE_DEF: {
7219 guint32 cols [MONO_TYPEDEF_SIZE];
7220 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
7221 guint tidx = mono_metadata_token_index (type_token);
7223 if (tidx > tt->rows)
7224 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7226 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
7227 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7228 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7229 if (strlen (nspace) == 0)
7230 return g_strdup_printf ("%s", name);
7231 else
7232 return g_strdup_printf ("%s.%s", nspace, name);
7235 case MONO_TOKEN_TYPE_REF: {
7236 MonoError error;
7237 guint32 cols [MONO_TYPEREF_SIZE];
7238 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
7239 guint tidx = mono_metadata_token_index (type_token);
7241 if (tidx > t->rows)
7242 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7244 if (!mono_verifier_verify_typeref_row (image, tidx - 1, &error)) {
7245 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7246 mono_error_cleanup (&error);
7247 return msg;
7250 mono_metadata_decode_row (t, tidx-1, cols, MONO_TYPEREF_SIZE);
7251 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
7252 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
7253 if (strlen (nspace) == 0)
7254 return g_strdup_printf ("%s", name);
7255 else
7256 return g_strdup_printf ("%s.%s", nspace, name);
7259 case MONO_TOKEN_TYPE_SPEC:
7260 return g_strdup_printf ("Typespec 0x%08x", type_token);
7261 default:
7262 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7266 static char *
7267 mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
7269 if (image_is_dynamic (image))
7270 return g_strdup_printf ("DynamicAssembly %s", image->name);
7272 switch (type_token & 0xff000000){
7273 case MONO_TOKEN_TYPE_DEF:
7274 if (image->assembly)
7275 return mono_stringify_assembly_name (&image->assembly->aname);
7276 else if (image->assembly_name)
7277 return g_strdup (image->assembly_name);
7278 return g_strdup_printf ("%s", image->name ? image->name : "[Could not resolve assembly name");
7279 case MONO_TOKEN_TYPE_REF: {
7280 MonoError error;
7281 MonoAssemblyName aname;
7282 guint32 cols [MONO_TYPEREF_SIZE];
7283 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
7284 guint32 idx = mono_metadata_token_index (type_token);
7286 if (idx > t->rows)
7287 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7289 if (!mono_verifier_verify_typeref_row (image, idx - 1, &error)) {
7290 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7291 mono_error_cleanup (&error);
7292 return msg;
7294 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
7296 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
7297 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
7298 case MONO_RESOLUTION_SCOPE_MODULE:
7299 /* FIXME: */
7300 return g_strdup ("");
7301 case MONO_RESOLUTION_SCOPE_MODULEREF:
7302 /* FIXME: */
7303 return g_strdup ("");
7304 case MONO_RESOLUTION_SCOPE_TYPEREF:
7305 /* FIXME: */
7306 return g_strdup ("");
7307 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
7308 mono_assembly_get_assemblyref (image, idx - 1, &aname);
7309 return mono_stringify_assembly_name (&aname);
7310 default:
7311 g_assert_not_reached ();
7313 break;
7315 case MONO_TOKEN_TYPE_SPEC:
7316 /* FIXME: */
7317 return g_strdup ("");
7318 default:
7319 g_assert_not_reached ();
7322 return NULL;
7326 * mono_class_get_full:
7327 * @image: the image where the class resides
7328 * @type_token: the token for the class
7329 * @context: the generic context used to evaluate generic instantiations in
7330 * @deprecated: Functions that expose MonoGenericContext are going away in mono 4.0
7332 * Returns: The MonoClass that represents @type_token in @image
7334 MonoClass *
7335 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
7337 MonoError error;
7338 MonoClass *klass;
7339 klass = mono_class_get_checked (image, type_token, &error);
7341 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
7342 klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7344 g_assert (mono_error_ok (&error)); /* FIXME deprecate this function and forbit the runtime from using it. */
7345 return klass;
7349 MonoClass *
7350 mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
7352 MonoClass *klass;
7354 mono_error_init (error);
7355 klass = mono_class_get_checked (image, type_token, error);
7357 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
7358 klass = mono_class_inflate_generic_class_checked (klass, context, error);
7360 return klass;
7363 * mono_class_get_checked:
7364 * @image: the image where the class resides
7365 * @type_token: the token for the class
7366 * @error: error object to return any error
7368 * Returns: The MonoClass that represents @type_token in @image, or NULL on error.
7370 MonoClass *
7371 mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
7373 MonoClass *klass = NULL;
7375 mono_error_init (error);
7377 if (image_is_dynamic (image)) {
7378 int table = mono_metadata_token_table (type_token);
7380 if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
7381 mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
7382 return NULL;
7384 klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
7385 goto done;
7388 switch (type_token & 0xff000000){
7389 case MONO_TOKEN_TYPE_DEF:
7390 klass = mono_class_create_from_typedef (image, type_token, error);
7391 break;
7392 case MONO_TOKEN_TYPE_REF:
7393 klass = mono_class_from_typeref_checked (image, type_token, error);
7394 break;
7395 case MONO_TOKEN_TYPE_SPEC:
7396 klass = mono_class_create_from_typespec (image, type_token, NULL, error);
7397 break;
7398 default:
7399 mono_error_set_bad_image (error, image, "Unknown type token %x", type_token & 0xff000000);
7402 done:
7403 /* Generic case, should be avoided for when a better error is possible. */
7404 if (!klass && mono_error_ok (error)) {
7405 char *name = mono_class_name_from_token (image, type_token);
7406 char *assembly = mono_assembly_name_from_token (image, type_token);
7407 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
7410 return klass;
7415 * mono_type_get_checked:
7416 * @image: the image where the type resides
7417 * @type_token: the token for the type
7418 * @context: the generic context used to evaluate generic instantiations in
7419 * @error: Error handling context
7421 * This functions exists to fullfill the fact that sometimes it's desirable to have access to the
7423 * Returns: The MonoType that represents @type_token in @image
7425 MonoType *
7426 mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
7428 MonoType *type = NULL;
7429 gboolean inflated = FALSE;
7431 mono_error_init (error);
7433 //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
7434 if (image_is_dynamic (image)) {
7435 MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
7436 return_val_if_nok (error, NULL);
7437 return mono_class_get_type (klass);
7440 if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
7441 MonoClass *klass = mono_class_get_checked (image, type_token, error);
7443 if (!klass) {
7444 return NULL;
7447 g_assert (klass);
7448 return mono_class_get_type (klass);
7451 type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
7453 if (!type) {
7454 return NULL;
7457 if (inflated) {
7458 MonoType *tmp = type;
7459 type = mono_class_get_type (mono_class_from_mono_type (type));
7460 /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
7461 * A MonoClass::byval_arg of a generic type definion has type CLASS.
7462 * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with byval_arg.
7464 * The long term solution is to chaise this places and make then set MonoType::type correctly.
7465 * */
7466 if (type->type != tmp->type)
7467 type = tmp;
7468 else
7469 mono_metadata_free_type (tmp);
7471 return type;
7475 * mono_class_get:
7476 * @image: image where the class token will be looked up.
7477 * @type_token: a type token from the image
7479 * Returns the MonoClass with the given @type_token on the @image
7481 MonoClass *
7482 mono_class_get (MonoImage *image, guint32 type_token)
7484 return mono_class_get_full (image, type_token, NULL);
7488 * mono_image_init_name_cache:
7490 * Initializes the class name cache stored in image->name_cache.
7492 * LOCKING: Acquires the corresponding image lock.
7494 void
7495 mono_image_init_name_cache (MonoImage *image)
7497 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7498 guint32 cols [MONO_TYPEDEF_SIZE];
7499 const char *name;
7500 const char *nspace;
7501 guint32 i, visib, nspace_index;
7502 GHashTable *name_cache2, *nspace_table, *the_name_cache;
7504 if (image->name_cache)
7505 return;
7507 the_name_cache = g_hash_table_new (g_str_hash, g_str_equal);
7509 if (image_is_dynamic (image)) {
7510 mono_image_lock (image);
7511 if (image->name_cache) {
7512 /* Somebody initialized it before us */
7513 g_hash_table_destroy (the_name_cache);
7514 } else {
7515 mono_atomic_store_release (&image->name_cache, the_name_cache);
7517 mono_image_unlock (image);
7518 return;
7521 /* Temporary hash table to avoid lookups in the nspace_table */
7522 name_cache2 = g_hash_table_new (NULL, NULL);
7524 for (i = 1; i <= t->rows; ++i) {
7525 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7526 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7528 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7529 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7531 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7532 continue;
7533 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7534 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7536 nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
7537 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7538 if (!nspace_table) {
7539 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7540 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
7541 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7542 nspace_table);
7544 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
7547 /* Load type names from EXPORTEDTYPES table */
7549 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7550 guint32 cols [MONO_EXP_TYPE_SIZE];
7551 int i;
7553 for (i = 0; i < t->rows; ++i) {
7554 mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
7556 guint32 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
7557 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_EXP_TYPE)
7558 /* Nested type */
7559 continue;
7561 name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
7562 nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
7564 nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
7565 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7566 if (!nspace_table) {
7567 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7568 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
7569 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7570 nspace_table);
7572 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
7576 g_hash_table_destroy (name_cache2);
7578 mono_image_lock (image);
7579 if (image->name_cache) {
7580 /* Somebody initialized it before us */
7581 g_hash_table_destroy (the_name_cache);
7582 } else {
7583 mono_atomic_store_release (&image->name_cache, the_name_cache);
7585 mono_image_unlock (image);
7588 /*FIXME Only dynamic assemblies should allow this operation.*/
7589 void
7590 mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
7591 const char *name, guint32 index)
7593 GHashTable *nspace_table;
7594 GHashTable *name_cache;
7595 guint32 old_index;
7597 mono_image_init_name_cache (image);
7598 mono_image_lock (image);
7600 name_cache = image->name_cache;
7601 if (!(nspace_table = (GHashTable *)g_hash_table_lookup (name_cache, nspace))) {
7602 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7603 g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
7606 if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
7607 g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
7609 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
7611 mono_image_unlock (image);
7614 typedef struct {
7615 gconstpointer key;
7616 gpointer value;
7617 } FindUserData;
7619 static void
7620 find_nocase (gpointer key, gpointer value, gpointer user_data)
7622 char *name = (char*)key;
7623 FindUserData *data = (FindUserData*)user_data;
7625 if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
7626 data->value = value;
7630 * mono_class_from_name_case:
7631 * @image: The MonoImage where the type is looked up in
7632 * @name_space: the type namespace
7633 * @name: the type short name.
7634 * @deprecated: use the mono_class_from_name_case_checked variant instead.
7636 * Obtains a MonoClass with a given namespace and a given name which
7637 * is located in the given MonoImage. The namespace and name
7638 * lookups are case insensitive.
7640 MonoClass *
7641 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
7643 MonoError error;
7644 MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error);
7645 mono_error_cleanup (&error);
7647 return res;
7651 * mono_class_from_name_case:
7652 * @image: The MonoImage where the type is looked up in
7653 * @name_space: the type namespace
7654 * @name: the type short name.
7655 * @error: if
7657 * Obtains a MonoClass with a given namespace and a given name which
7658 * is located in the given MonoImage. The namespace and name
7659 * lookups are case insensitive.
7661 * Returns: The MonoClass if the given namespace and name were found, or NULL if it
7662 * was not found. The @error object will contain information about the problem
7663 * in that case.
7665 MonoClass *
7666 mono_class_from_name_case_checked (MonoImage *image, const char *name_space, const char *name, MonoError *error)
7668 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7669 guint32 cols [MONO_TYPEDEF_SIZE];
7670 const char *n;
7671 const char *nspace;
7672 guint32 i, visib;
7674 mono_error_init (error);
7676 if (image_is_dynamic (image)) {
7677 guint32 token = 0;
7678 FindUserData user_data;
7680 mono_image_init_name_cache (image);
7681 mono_image_lock (image);
7683 user_data.key = name_space;
7684 user_data.value = NULL;
7685 g_hash_table_foreach (image->name_cache, find_nocase, &user_data);
7687 if (user_data.value) {
7688 GHashTable *nspace_table = (GHashTable*)user_data.value;
7690 user_data.key = name;
7691 user_data.value = NULL;
7693 g_hash_table_foreach (nspace_table, find_nocase, &user_data);
7695 if (user_data.value)
7696 token = GPOINTER_TO_UINT (user_data.value);
7699 mono_image_unlock (image);
7701 if (token)
7702 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | token, error);
7703 else
7704 return NULL;
7708 /* add a cache if needed */
7709 for (i = 1; i <= t->rows; ++i) {
7710 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7711 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7713 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7714 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7716 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7717 continue;
7718 n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7719 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7720 if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
7721 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | i, error);
7723 return NULL;
7726 static MonoClass*
7727 return_nested_in (MonoClass *klass, char *nested)
7729 MonoClass *found;
7730 char *s = strchr (nested, '/');
7731 gpointer iter = NULL;
7733 if (s) {
7734 *s = 0;
7735 s++;
7738 while ((found = mono_class_get_nested_types (klass, &iter))) {
7739 if (strcmp (found->name, nested) == 0) {
7740 if (s)
7741 return return_nested_in (found, s);
7742 return found;
7745 return NULL;
7748 static MonoClass*
7749 search_modules (MonoImage *image, const char *name_space, const char *name, MonoError *error)
7751 MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
7752 MonoImage *file_image;
7753 MonoClass *klass;
7754 int i;
7756 mono_error_init (error);
7759 * The EXPORTEDTYPES table only contains public types, so have to search the
7760 * modules as well.
7761 * Note: image->modules contains the contents of the MODULEREF table, while
7762 * the real module list is in the FILE table.
7764 for (i = 0; i < file_table->rows; i++) {
7765 guint32 cols [MONO_FILE_SIZE];
7766 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
7767 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
7768 continue;
7770 file_image = mono_image_load_file_for_image_checked (image, i + 1, error);
7771 if (file_image) {
7772 klass = mono_class_from_name_checked (file_image, name_space, name, error);
7773 if (klass || !is_ok (error))
7774 return klass;
7778 return NULL;
7781 static MonoClass *
7782 mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, MonoError *error)
7784 GHashTable *nspace_table;
7785 MonoImage *loaded_image;
7786 guint32 token = 0;
7787 int i;
7788 MonoClass *klass;
7789 char *nested;
7790 char buf [1024];
7792 mono_error_init (error);
7794 // Checking visited images avoids stack overflows when cyclic references exist.
7795 if (g_hash_table_lookup (visited_images, image))
7796 return NULL;
7798 g_hash_table_insert (visited_images, image, GUINT_TO_POINTER(1));
7800 if ((nested = strchr (name, '/'))) {
7801 int pos = nested - name;
7802 int len = strlen (name);
7803 if (len > 1023)
7804 return NULL;
7805 memcpy (buf, name, len + 1);
7806 buf [pos] = 0;
7807 nested = buf + pos + 1;
7808 name = buf;
7811 /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */
7812 if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
7813 gboolean res = get_class_from_name (image, name_space, name, &klass);
7814 if (res) {
7815 if (!klass) {
7816 klass = search_modules (image, name_space, name, error);
7817 if (!is_ok (error))
7818 return NULL;
7820 if (nested)
7821 return klass ? return_nested_in (klass, nested) : NULL;
7822 else
7823 return klass;
7827 mono_image_init_name_cache (image);
7828 mono_image_lock (image);
7830 nspace_table = (GHashTable *)g_hash_table_lookup (image->name_cache, name_space);
7832 if (nspace_table)
7833 token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
7835 mono_image_unlock (image);
7837 if (!token && image_is_dynamic (image) && image->modules) {
7838 /* Search modules as well */
7839 for (i = 0; i < image->module_count; ++i) {
7840 MonoImage *module = image->modules [i];
7842 klass = mono_class_from_name_checked (module, name_space, name, error);
7843 if (klass || !is_ok (error))
7844 return klass;
7848 if (!token) {
7849 klass = search_modules (image, name_space, name, error);
7850 if (klass || !is_ok (error))
7851 return klass;
7852 return NULL;
7855 if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
7856 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7857 guint32 cols [MONO_EXP_TYPE_SIZE];
7858 guint32 idx, impl;
7860 idx = mono_metadata_token_index (token);
7862 mono_metadata_decode_row (t, idx - 1, cols, MONO_EXP_TYPE_SIZE);
7864 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
7865 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
7866 loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error);
7867 if (!loaded_image)
7868 return NULL;
7869 klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, error);
7870 if (nested)
7871 return klass ? return_nested_in (klass, nested) : NULL;
7872 return klass;
7873 } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
7874 guint32 assembly_idx;
7876 assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
7878 mono_assembly_load_reference (image, assembly_idx - 1);
7879 g_assert (image->references [assembly_idx - 1]);
7880 if (image->references [assembly_idx - 1] == (gpointer)-1)
7881 return NULL;
7882 klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, error);
7883 if (nested)
7884 return klass ? return_nested_in (klass, nested) : NULL;
7885 return klass;
7886 } else {
7887 g_assert_not_reached ();
7891 token = MONO_TOKEN_TYPE_DEF | token;
7893 klass = mono_class_get_checked (image, token, error);
7894 if (nested)
7895 return return_nested_in (klass, nested);
7896 return klass;
7900 * mono_class_from_name_checked:
7901 * @image: The MonoImage where the type is looked up in
7902 * @name_space: the type namespace
7903 * @name: the type short name.
7905 * Obtains a MonoClass with a given namespace and a given name which
7906 * is located in the given MonoImage.
7908 * Works like mono_class_from_name, but error handling is tricky. It can return NULL and have no error
7909 * set if the class was not found or it will return NULL and set the error if there was a loading error.
7911 MonoClass *
7912 mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
7914 MonoClass *klass;
7915 GHashTable *visited_images;
7917 visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
7919 klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, error);
7921 g_hash_table_destroy (visited_images);
7923 return klass;
7927 * mono_class_from_name:
7928 * @image: The MonoImage where the type is looked up in
7929 * @name_space: the type namespace
7930 * @name: the type short name.
7932 * Obtains a MonoClass with a given namespace and a given name which
7933 * is located in the given MonoImage.
7935 * To reference nested classes, use the "/" character as a separator.
7936 * For example use "Foo/Bar" to reference the class Bar that is nested
7937 * inside Foo, like this: "class Foo { class Bar {} }".
7939 MonoClass *
7940 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
7942 MonoError error;
7943 MonoClass *klass;
7945 klass = mono_class_from_name_checked (image, name_space, name, &error);
7946 mono_error_cleanup (&error); /* FIXME Don't swallow the error */
7948 return klass;
7952 * mono_class_load_from_name:
7953 * @image: The MonoImage where the type is looked up in
7954 * @name_space: the type namespace
7955 * @name: the type short name.
7957 * This function works exactly like mono_class_from_name but it will abort if the class is not found.
7958 * This function should be used by the runtime for critical types to which there's no way to recover but crash
7959 * If they are missing. Thing of System.Object or System.String.
7961 MonoClass *
7962 mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
7964 MonoError error;
7965 MonoClass *klass;
7967 klass = mono_class_from_name_checked (image, name_space, name, &error);
7968 if (!klass)
7969 g_error ("Runtime critical type %s.%s not found", name_space, name);
7970 if (!mono_error_ok (&error))
7971 g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
7972 return klass;
7976 * mono_class_try_load_from_name:
7977 * @image: The MonoImage where the type is looked up in
7978 * @name_space: the type namespace
7979 * @name: the type short name.
7981 * This function tries to load a type, returning the class was found or NULL otherwise.
7982 * This function should be used by the runtime when probing for optional types, those that could have being linked out.
7984 * Big design consideration. This function aborts if there was an error loading the type. This prevents us from missing
7985 * a type that we would otherwise assume to be available but was not due some error.
7988 MonoClass*
7989 mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name)
7991 MonoError error;
7992 MonoClass *klass;
7994 klass = mono_class_from_name_checked (image, name_space, name, &error);
7995 if (!mono_error_ok (&error))
7996 g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
7997 return klass;
8002 * mono_class_is_subclass_of:
8003 * @klass: class to probe if it is a subclass of another one
8004 * @klassc: the class we suspect is the base class
8005 * @check_interfaces: whether we should perform interface checks
8007 * This method determines whether @klass is a subclass of @klassc.
8009 * If the @check_interfaces flag is set, then if @klassc is an interface
8010 * this method return TRUE if the @klass implements the interface or
8011 * if @klass is an interface, if one of its base classes is @klass.
8013 * If @check_interfaces is false then, then if @klass is not an interface
8014 * then it returns TRUE if the @klass is a subclass of @klassc.
8016 * if @klass is an interface and @klassc is System.Object, then this function
8017 * return true.
8020 gboolean
8021 mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
8022 gboolean check_interfaces)
8024 /* FIXME test for interfaces with variant generic arguments */
8025 mono_class_init (klass);
8026 mono_class_init (klassc);
8028 if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
8029 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
8030 return TRUE;
8031 } else if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && MONO_CLASS_IS_INTERFACE (klass)) {
8032 int i;
8034 for (i = 0; i < klass->interface_count; i ++) {
8035 MonoClass *ic = klass->interfaces [i];
8036 if (ic == klassc)
8037 return TRUE;
8039 } else {
8040 if (!MONO_CLASS_IS_INTERFACE (klass) && mono_class_has_parent (klass, klassc))
8041 return TRUE;
8045 * MS.NET thinks interfaces are a subclass of Object, so we think it as
8046 * well.
8048 if (klassc == mono_defaults.object_class)
8049 return TRUE;
8051 return FALSE;
8054 static gboolean
8055 mono_type_is_generic_argument (MonoType *type)
8057 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
8060 gboolean
8061 mono_class_has_variant_generic_params (MonoClass *klass)
8063 int i;
8064 MonoGenericContainer *container;
8066 if (!klass->generic_class)
8067 return FALSE;
8069 container = klass->generic_class->container_class->generic_container;
8071 for (i = 0; i < container->type_argc; ++i)
8072 if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
8073 return TRUE;
8075 return FALSE;
8078 static gboolean
8079 mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
8081 if (target == candidate)
8082 return TRUE;
8084 if (check_for_reference_conv &&
8085 mono_type_is_generic_argument (&target->byval_arg) &&
8086 mono_type_is_generic_argument (&candidate->byval_arg)) {
8087 MonoGenericParam *gparam = candidate->byval_arg.data.generic_param;
8088 MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
8090 if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
8091 return FALSE;
8093 if (!mono_class_is_assignable_from (target, candidate))
8094 return FALSE;
8095 return TRUE;
8099 * @container the generic container from the GTD
8100 * @klass: the class to be assigned to
8101 * @oklass: the source class
8103 * Both @klass and @oklass must be instances of the same generic interface.
8105 * Returns: TRUE if @klass can be assigned to a @klass variable
8107 gboolean
8108 mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
8110 int j;
8111 MonoType **klass_argv, **oklass_argv;
8112 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
8113 MonoGenericContainer *container = klass_gtd->generic_container;
8115 if (klass == oklass)
8116 return TRUE;
8118 /*Viable candidates are instances of the same generic interface*/
8119 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
8120 return FALSE;
8122 klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
8123 oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
8125 for (j = 0; j < container->type_argc; ++j) {
8126 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
8127 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
8129 if (param1_class->valuetype != param2_class->valuetype || (param1_class->valuetype && param1_class != param2_class))
8130 return FALSE;
8133 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
8134 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
8136 if (param1_class != param2_class) {
8137 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
8138 if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
8139 return FALSE;
8140 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
8141 if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
8142 return FALSE;
8143 } else
8144 return FALSE;
8147 return TRUE;
8150 static gboolean
8151 mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
8153 MonoGenericParam *gparam, *ogparam;
8154 MonoGenericParamInfo *tinfo, *cinfo;
8155 MonoClass **candidate_class;
8156 gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
8157 int tmask, cmask;
8159 if (target == candidate)
8160 return TRUE;
8161 if (target->byval_arg.type != candidate->byval_arg.type)
8162 return FALSE;
8164 gparam = target->byval_arg.data.generic_param;
8165 ogparam = candidate->byval_arg.data.generic_param;
8166 tinfo = mono_generic_param_info (gparam);
8167 cinfo = mono_generic_param_info (ogparam);
8169 class_constraint_satisfied = FALSE;
8170 valuetype_constraint_satisfied = FALSE;
8172 /*candidate must have a super set of target's special constraints*/
8173 tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
8174 cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
8176 if (cinfo->constraints) {
8177 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8178 MonoClass *cc = *candidate_class;
8180 if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
8181 class_constraint_satisfied = TRUE;
8182 else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
8183 valuetype_constraint_satisfied = TRUE;
8186 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
8187 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
8189 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
8190 return FALSE;
8191 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
8192 return FALSE;
8193 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
8194 valuetype_constraint_satisfied)) {
8195 return FALSE;
8199 /*candidate type constraints must be a superset of target's*/
8200 if (tinfo->constraints) {
8201 MonoClass **target_class;
8202 for (target_class = tinfo->constraints; *target_class; ++target_class) {
8203 MonoClass *tc = *target_class;
8206 * A constraint from @target might inflate into @candidate itself and in that case we don't need
8207 * check it's constraints since it satisfy the constraint by itself.
8209 if (mono_metadata_type_equal (&tc->byval_arg, &candidate->byval_arg))
8210 continue;
8212 if (!cinfo->constraints)
8213 return FALSE;
8215 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8216 MonoClass *cc = *candidate_class;
8218 if (mono_class_is_assignable_from (tc, cc))
8219 break;
8222 * This happens when we have the following:
8224 * Bar<K> where K : IFace
8225 * Foo<T, U> where T : U where U : IFace
8226 * ...
8227 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
8230 if (mono_type_is_generic_argument (&cc->byval_arg)) {
8231 if (mono_gparam_is_assignable_from (target, cc))
8232 break;
8235 if (!*candidate_class)
8236 return FALSE;
8240 /*candidate itself must have a constraint that satisfy target*/
8241 if (cinfo->constraints) {
8242 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8243 MonoClass *cc = *candidate_class;
8244 if (mono_class_is_assignable_from (target, cc))
8245 return TRUE;
8248 return FALSE;
8252 * mono_class_is_assignable_from:
8253 * @klass: the class to be assigned to
8254 * @oklass: the source class
8256 * Returns: TRUE if an instance of object oklass can be assigned to an
8257 * instance of object @klass
8259 gboolean
8260 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
8262 MonoError error;
8263 /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
8264 if (!klass->inited)
8265 mono_class_init (klass);
8267 if (!oklass->inited)
8268 mono_class_init (oklass);
8270 if (mono_class_has_failure (klass) || mono_class_has_failure (oklass))
8271 return FALSE;
8273 if (mono_type_is_generic_argument (&klass->byval_arg)) {
8274 if (!mono_type_is_generic_argument (&oklass->byval_arg))
8275 return FALSE;
8276 return mono_gparam_is_assignable_from (klass, oklass);
8279 if (MONO_CLASS_IS_INTERFACE (klass)) {
8280 if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
8281 MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
8282 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
8283 int i;
8285 if (constraints) {
8286 for (i = 0; constraints [i]; ++i) {
8287 if (mono_class_is_assignable_from (klass, constraints [i]))
8288 return TRUE;
8292 return FALSE;
8295 /* interface_offsets might not be set for dynamic classes */
8296 if (oklass->ref_info_handle && !oklass->interface_bitmap) {
8298 * oklass might be a generic type parameter but they have
8299 * interface_offsets set.
8301 gboolean result = mono_reflection_call_is_assignable_to (oklass, klass, &error);
8302 if (!is_ok (&error)) {
8303 mono_error_cleanup (&error);
8304 return FALSE;
8306 return result;
8308 if (!oklass->interface_bitmap)
8309 /* Happens with generic instances of not-yet created dynamic types */
8310 return FALSE;
8311 if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
8312 return TRUE;
8314 if (mono_class_has_variant_generic_params (klass)) {
8315 int i;
8316 mono_class_setup_interfaces (oklass, &error);
8317 if (!mono_error_ok (&error)) {
8318 mono_error_cleanup (&error);
8319 return FALSE;
8322 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
8323 for (i = 0; i < oklass->interface_offsets_count; ++i) {
8324 MonoClass *iface = oklass->interfaces_packed [i];
8326 if (mono_class_is_variant_compatible (klass, iface, FALSE))
8327 return TRUE;
8330 return FALSE;
8331 } else if (klass->delegate) {
8332 if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE))
8333 return TRUE;
8334 }else if (klass->rank) {
8335 MonoClass *eclass, *eoclass;
8337 if (oklass->rank != klass->rank)
8338 return FALSE;
8340 /* vectors vs. one dimensional arrays */
8341 if (oklass->byval_arg.type != klass->byval_arg.type)
8342 return FALSE;
8344 eclass = klass->cast_class;
8345 eoclass = oklass->cast_class;
8348 * a is b does not imply a[] is b[] when a is a valuetype, and
8349 * b is a reference type.
8352 if (eoclass->valuetype) {
8353 if ((eclass == mono_defaults.enum_class) ||
8354 (eclass == mono_defaults.enum_class->parent) ||
8355 (eclass == mono_defaults.object_class))
8356 return FALSE;
8359 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
8360 } else if (mono_class_is_nullable (klass)) {
8361 if (mono_class_is_nullable (oklass))
8362 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
8363 else
8364 return mono_class_is_assignable_from (klass->cast_class, oklass);
8365 } else if (klass == mono_defaults.object_class)
8366 return TRUE;
8368 return mono_class_has_parent (oklass, klass);
8371 /*Check if @oklass is variant compatible with @klass.*/
8372 static gboolean
8373 mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
8375 int j;
8376 MonoType **klass_argv, **oklass_argv;
8377 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
8378 MonoGenericContainer *container = klass_gtd->generic_container;
8380 /*Viable candidates are instances of the same generic interface*/
8381 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
8382 return FALSE;
8384 klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
8385 oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
8387 for (j = 0; j < container->type_argc; ++j) {
8388 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
8389 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
8391 if (param1_class->valuetype != param2_class->valuetype)
8392 return FALSE;
8395 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
8396 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
8398 if (param1_class != param2_class) {
8399 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
8400 if (!mono_class_is_assignable_from_slow (param1_class, param2_class))
8401 return FALSE;
8402 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
8403 if (!mono_class_is_assignable_from_slow (param2_class, param1_class))
8404 return FALSE;
8405 } else
8406 return FALSE;
8409 return TRUE;
8411 /*Check if @candidate implements the interface @target*/
8412 static gboolean
8413 mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
8415 MonoError error;
8416 int i;
8417 gboolean is_variant = mono_class_has_variant_generic_params (target);
8419 if (is_variant && MONO_CLASS_IS_INTERFACE (candidate)) {
8420 if (mono_class_is_variant_compatible_slow (target, candidate))
8421 return TRUE;
8424 do {
8425 if (candidate == target)
8426 return TRUE;
8428 /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
8429 if (image_is_dynamic (candidate->image) && !candidate->wastypebuilder) {
8430 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info (candidate);
8431 int j;
8432 if (tb && tb->interfaces) {
8433 for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
8434 MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
8435 MonoClass *iface_class;
8437 /* we can't realize the type here since it can do pretty much anything. */
8438 if (!iface->type)
8439 continue;
8440 iface_class = mono_class_from_mono_type (iface->type);
8441 if (iface_class == target)
8442 return TRUE;
8443 if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class))
8444 return TRUE;
8445 if (mono_class_implement_interface_slow (target, iface_class))
8446 return TRUE;
8449 } else {
8450 /*setup_interfaces don't mono_class_init anything*/
8451 /*FIXME this doesn't handle primitive type arrays.
8452 ICollection<sbyte> x byte [] won't work because candidate->interfaces, for byte[], won't have IList<sbyte>.
8453 A possible way to fix this would be to move that to setup_interfaces from setup_interface_offsets.
8455 mono_class_setup_interfaces (candidate, &error);
8456 if (!mono_error_ok (&error)) {
8457 mono_error_cleanup (&error);
8458 return FALSE;
8461 for (i = 0; i < candidate->interface_count; ++i) {
8462 if (candidate->interfaces [i] == target)
8463 return TRUE;
8465 if (is_variant && mono_class_is_variant_compatible_slow (target, candidate->interfaces [i]))
8466 return TRUE;
8468 if (mono_class_implement_interface_slow (target, candidate->interfaces [i]))
8469 return TRUE;
8472 candidate = candidate->parent;
8473 } while (candidate);
8475 return FALSE;
8479 * Check if @oklass can be assigned to @klass.
8480 * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context.
8482 gboolean
8483 mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
8485 if (candidate == target)
8486 return TRUE;
8487 if (target == mono_defaults.object_class)
8488 return TRUE;
8490 if (mono_class_has_parent (candidate, target))
8491 return TRUE;
8493 /*If target is not an interface there is no need to check them.*/
8494 if (MONO_CLASS_IS_INTERFACE (target))
8495 return mono_class_implement_interface_slow (target, candidate);
8497 if (target->delegate && mono_class_has_variant_generic_params (target))
8498 return mono_class_is_variant_compatible (target, candidate, FALSE);
8500 if (target->rank) {
8501 MonoClass *eclass, *eoclass;
8503 if (target->rank != candidate->rank)
8504 return FALSE;
8506 /* vectors vs. one dimensional arrays */
8507 if (target->byval_arg.type != candidate->byval_arg.type)
8508 return FALSE;
8510 eclass = target->cast_class;
8511 eoclass = candidate->cast_class;
8514 * a is b does not imply a[] is b[] when a is a valuetype, and
8515 * b is a reference type.
8518 if (eoclass->valuetype) {
8519 if ((eclass == mono_defaults.enum_class) ||
8520 (eclass == mono_defaults.enum_class->parent) ||
8521 (eclass == mono_defaults.object_class))
8522 return FALSE;
8525 return mono_class_is_assignable_from_slow (target->cast_class, candidate->cast_class);
8527 /*FIXME properly handle nullables */
8528 /*FIXME properly handle (M)VAR */
8529 return FALSE;
8533 * mono_class_get_cctor:
8534 * @klass: A MonoClass pointer
8536 * Returns: The static constructor of @klass if it exists, NULL otherwise.
8538 MonoMethod*
8539 mono_class_get_cctor (MonoClass *klass)
8541 MonoCachedClassInfo cached_info;
8543 if (image_is_dynamic (klass->image)) {
8545 * has_cctor is not set for these classes because mono_class_init () is
8546 * not run for them.
8548 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8551 if (!klass->has_cctor)
8552 return NULL;
8554 if (mono_class_get_cached_class_info (klass, &cached_info)) {
8555 MonoError error;
8556 MonoMethod *result = mono_get_method_checked (klass->image, cached_info.cctor_token, klass, NULL, &error);
8557 if (!mono_error_ok (&error))
8558 g_error ("Could not lookup class cctor from cached metadata due to %s", mono_error_get_message (&error));
8559 return result;
8562 if (klass->generic_class && !klass->methods)
8563 return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class));
8565 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8569 * mono_class_get_finalizer:
8570 * @klass: The MonoClass pointer
8572 * Returns: The finalizer method of @klass if it exists, NULL otherwise.
8574 MonoMethod*
8575 mono_class_get_finalizer (MonoClass *klass)
8577 MonoCachedClassInfo cached_info;
8579 if (!klass->inited)
8580 mono_class_init (klass);
8581 if (!mono_class_has_finalizer (klass))
8582 return NULL;
8584 if (mono_class_get_cached_class_info (klass, &cached_info)) {
8585 MonoError error;
8586 MonoMethod *result = mono_get_method_checked (cached_info.finalize_image, cached_info.finalize_token, NULL, NULL, &error);
8587 if (!mono_error_ok (&error))
8588 g_error ("Could not lookup finalizer from cached metadata due to %s", mono_error_get_message (&error));
8589 return result;
8590 }else {
8591 mono_class_setup_vtable (klass);
8592 return klass->vtable [finalize_slot];
8597 * mono_class_needs_cctor_run:
8598 * @klass: the MonoClass pointer
8599 * @caller: a MonoMethod describing the caller
8601 * Determines whenever the class has a static constructor and whenever it
8602 * needs to be called when executing CALLER.
8604 gboolean
8605 mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
8607 MonoMethod *method;
8609 method = mono_class_get_cctor (klass);
8610 if (method)
8611 return (method == caller) ? FALSE : TRUE;
8612 else
8613 return FALSE;
8617 * mono_class_array_element_size:
8618 * @klass:
8620 * Returns: The number of bytes an element of type @klass
8621 * uses when stored into an array.
8623 gint32
8624 mono_class_array_element_size (MonoClass *klass)
8626 MonoType *type = &klass->byval_arg;
8628 handle_enum:
8629 switch (type->type) {
8630 case MONO_TYPE_I1:
8631 case MONO_TYPE_U1:
8632 case MONO_TYPE_BOOLEAN:
8633 return 1;
8634 case MONO_TYPE_I2:
8635 case MONO_TYPE_U2:
8636 case MONO_TYPE_CHAR:
8637 return 2;
8638 case MONO_TYPE_I4:
8639 case MONO_TYPE_U4:
8640 case MONO_TYPE_R4:
8641 return 4;
8642 case MONO_TYPE_I:
8643 case MONO_TYPE_U:
8644 case MONO_TYPE_PTR:
8645 case MONO_TYPE_CLASS:
8646 case MONO_TYPE_STRING:
8647 case MONO_TYPE_OBJECT:
8648 case MONO_TYPE_SZARRAY:
8649 case MONO_TYPE_ARRAY:
8650 return sizeof (gpointer);
8651 case MONO_TYPE_I8:
8652 case MONO_TYPE_U8:
8653 case MONO_TYPE_R8:
8654 return 8;
8655 case MONO_TYPE_VALUETYPE:
8656 if (type->data.klass->enumtype) {
8657 type = mono_class_enum_basetype (type->data.klass);
8658 klass = klass->element_class;
8659 goto handle_enum;
8661 return mono_class_instance_size (klass) - sizeof (MonoObject);
8662 case MONO_TYPE_GENERICINST:
8663 type = &type->data.generic_class->container_class->byval_arg;
8664 goto handle_enum;
8665 case MONO_TYPE_VAR:
8666 case MONO_TYPE_MVAR: {
8667 int align;
8669 return mono_type_size (type, &align);
8671 case MONO_TYPE_VOID:
8672 return 0;
8674 default:
8675 g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
8677 return -1;
8681 * mono_array_element_size:
8682 * @ac: pointer to a #MonoArrayClass
8684 * Returns: The size of single array element.
8686 gint32
8687 mono_array_element_size (MonoClass *ac)
8689 g_assert (ac->rank);
8690 return ac->sizes.element_size;
8693 gpointer
8694 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
8695 MonoGenericContext *context)
8697 MonoError error;
8698 gpointer res = mono_ldtoken_checked (image, token, handle_class, context, &error);
8699 g_assert (mono_error_ok (&error));
8700 return res;
8703 gpointer
8704 mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
8705 MonoGenericContext *context, MonoError *error)
8707 mono_error_init (error);
8709 if (image_is_dynamic (image)) {
8710 MonoClass *tmp_handle_class;
8711 gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
8713 mono_error_assert_ok (error);
8714 g_assert (tmp_handle_class);
8715 if (handle_class)
8716 *handle_class = tmp_handle_class;
8718 if (tmp_handle_class == mono_defaults.typehandle_class)
8719 return &((MonoClass*)obj)->byval_arg;
8720 else
8721 return obj;
8724 switch (token & 0xff000000) {
8725 case MONO_TOKEN_TYPE_DEF:
8726 case MONO_TOKEN_TYPE_REF:
8727 case MONO_TOKEN_TYPE_SPEC: {
8728 MonoType *type;
8729 if (handle_class)
8730 *handle_class = mono_defaults.typehandle_class;
8731 type = mono_type_get_checked (image, token, context, error);
8732 if (!type)
8733 return NULL;
8735 mono_class_init (mono_class_from_mono_type (type));
8736 /* We return a MonoType* as handle */
8737 return type;
8739 case MONO_TOKEN_FIELD_DEF: {
8740 MonoClass *klass;
8741 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
8742 if (!type) {
8743 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
8744 return NULL;
8746 if (handle_class)
8747 *handle_class = mono_defaults.fieldhandle_class;
8748 klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_DEF | type, context, error);
8749 if (!klass)
8750 return NULL;
8752 mono_class_init (klass);
8753 return mono_class_get_field (klass, token);
8755 case MONO_TOKEN_METHOD_DEF:
8756 case MONO_TOKEN_METHOD_SPEC: {
8757 MonoMethod *meth;
8758 meth = mono_get_method_checked (image, token, NULL, context, error);
8759 if (handle_class)
8760 *handle_class = mono_defaults.methodhandle_class;
8761 if (!meth)
8762 return NULL;
8764 return meth;
8766 case MONO_TOKEN_MEMBER_REF: {
8767 guint32 cols [MONO_MEMBERREF_SIZE];
8768 const char *sig;
8769 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE);
8770 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
8771 mono_metadata_decode_blob_size (sig, &sig);
8772 if (*sig == 0x6) { /* it's a field */
8773 MonoClass *klass;
8774 MonoClassField *field;
8775 field = mono_field_from_token_checked (image, token, &klass, context, error);
8776 if (handle_class)
8777 *handle_class = mono_defaults.fieldhandle_class;
8778 return field;
8779 } else {
8780 MonoMethod *meth;
8781 meth = mono_get_method_checked (image, token, NULL, context, error);
8782 if (handle_class)
8783 *handle_class = mono_defaults.methodhandle_class;
8784 return meth;
8787 default:
8788 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
8790 return NULL;
8793 gpointer
8794 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
8796 MonoClass *handle_class;
8797 mono_error_init (error);
8798 return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
8801 gpointer
8802 mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
8804 return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
8807 static MonoGetCachedClassInfo get_cached_class_info = NULL;
8809 void
8810 mono_install_get_cached_class_info (MonoGetCachedClassInfo func)
8812 get_cached_class_info = func;
8815 static gboolean
8816 mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
8818 if (!get_cached_class_info)
8819 return FALSE;
8820 else
8821 return get_cached_class_info (klass, res);
8824 void
8825 mono_install_get_class_from_name (MonoGetClassFromName func)
8827 get_class_from_name = func;
8831 * mono_class_get_image:
8833 * Use this method to get the `MonoImage*` where this class came from.
8835 * Returns: The image where this class is defined.
8837 MonoImage*
8838 mono_class_get_image (MonoClass *klass)
8840 return klass->image;
8844 * mono_class_get_element_class:
8845 * @klass: the MonoClass to act on
8847 * Use this function to get the element class of an array.
8849 * Returns: The element class of an array.
8851 MonoClass*
8852 mono_class_get_element_class (MonoClass *klass)
8854 return klass->element_class;
8858 * mono_class_is_valuetype:
8859 * @klass: the MonoClass to act on
8861 * Use this method to determine if the provided `MonoClass*` represents a value type,
8862 * or a reference type.
8864 * Returns: TRUE if the MonoClass represents a ValueType, FALSE if it represents a reference type.
8866 gboolean
8867 mono_class_is_valuetype (MonoClass *klass)
8869 return klass->valuetype;
8873 * mono_class_is_enum:
8874 * @klass: the MonoClass to act on
8876 * Use this function to determine if the provided `MonoClass*` represents an enumeration.
8878 * Returns: TRUE if the MonoClass represents an enumeration.
8880 gboolean
8881 mono_class_is_enum (MonoClass *klass)
8883 return klass->enumtype;
8887 * mono_class_enum_basetype:
8888 * @klass: the MonoClass to act on
8890 * Use this function to get the underlying type for an enumeration value.
8892 * Returns: The underlying type representation for an enumeration.
8894 MonoType*
8895 mono_class_enum_basetype (MonoClass *klass)
8897 if (klass->element_class == klass)
8898 /* SRE or broken types */
8899 return NULL;
8900 else
8901 return &klass->element_class->byval_arg;
8905 * mono_class_get_parent
8906 * @klass: the MonoClass to act on
8908 * Returns: The parent class for this class.
8910 MonoClass*
8911 mono_class_get_parent (MonoClass *klass)
8913 return klass->parent;
8917 * mono_class_get_nesting_type:
8918 * @klass: the MonoClass to act on
8920 * Use this function to obtain the class that the provided `MonoClass*` is nested on.
8922 * If the return is NULL, this indicates that this class is not nested.
8924 * Returns: The container type where this type is nested or NULL if this type is not a nested type.
8926 MonoClass*
8927 mono_class_get_nesting_type (MonoClass *klass)
8929 return klass->nested_in;
8933 * mono_class_get_rank:
8934 * @klass: the MonoClass to act on
8936 * Returns: The rank for the array (the number of dimensions).
8939 mono_class_get_rank (MonoClass *klass)
8941 return klass->rank;
8945 * mono_class_get_flags:
8946 * @klass: the MonoClass to act on
8948 * The type flags from the TypeDef table from the metadata.
8949 * see the TYPE_ATTRIBUTE_* definitions on tabledefs.h for the
8950 * different values.
8952 * Returns: The flags from the TypeDef table.
8954 guint32
8955 mono_class_get_flags (MonoClass *klass)
8957 return klass->flags;
8961 * mono_class_get_name
8962 * @klass: the MonoClass to act on
8964 * Returns: The name of the class.
8966 const char*
8967 mono_class_get_name (MonoClass *klass)
8969 return klass->name;
8973 * mono_class_get_namespace:
8974 * @klass: the MonoClass to act on
8976 * Returns: The namespace of the class.
8978 const char*
8979 mono_class_get_namespace (MonoClass *klass)
8981 return klass->name_space;
8985 * mono_class_get_type:
8986 * @klass: the MonoClass to act on
8988 * This method returns the internal Type representation for the class.
8990 * Returns: The MonoType from the class.
8992 MonoType*
8993 mono_class_get_type (MonoClass *klass)
8995 return &klass->byval_arg;
8999 * mono_class_get_type_token:
9000 * @klass: the MonoClass to act on
9002 * This method returns type token for the class.
9004 * Returns: The type token for the class.
9006 guint32
9007 mono_class_get_type_token (MonoClass *klass)
9009 return klass->type_token;
9013 * mono_class_get_byref_type:
9014 * @klass: the MonoClass to act on
9018 MonoType*
9019 mono_class_get_byref_type (MonoClass *klass)
9021 return &klass->this_arg;
9025 * mono_class_num_fields:
9026 * @klass: the MonoClass to act on
9028 * Returns: The number of static and instance fields in the class.
9031 mono_class_num_fields (MonoClass *klass)
9033 return klass->field.count;
9037 * mono_class_num_methods:
9038 * @klass: the MonoClass to act on
9040 * Returns: The number of methods in the class.
9043 mono_class_num_methods (MonoClass *klass)
9045 return klass->method.count;
9049 * mono_class_num_properties
9050 * @klass: the MonoClass to act on
9052 * Returns: The number of properties in the class.
9055 mono_class_num_properties (MonoClass *klass)
9057 mono_class_setup_properties (klass);
9059 return klass->ext->property.count;
9063 * mono_class_num_events:
9064 * @klass: the MonoClass to act on
9066 * Returns: The number of events in the class.
9069 mono_class_num_events (MonoClass *klass)
9071 mono_class_setup_events (klass);
9073 return klass->ext->event.count;
9077 * mono_class_get_fields:
9078 * @klass: the MonoClass to act on
9080 * This routine is an iterator routine for retrieving the fields in a class.
9082 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9083 * iterate over all of the elements. When no more values are
9084 * available, the return value is NULL.
9086 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
9088 MonoClassField*
9089 mono_class_get_fields (MonoClass* klass, gpointer *iter)
9091 MonoClassField* field;
9092 if (!iter)
9093 return NULL;
9094 if (!*iter) {
9095 mono_class_setup_fields (klass);
9096 if (mono_class_has_failure (klass))
9097 return NULL;
9098 /* start from the first */
9099 if (klass->field.count) {
9100 *iter = &klass->fields [0];
9101 return &klass->fields [0];
9102 } else {
9103 /* no fields */
9104 return NULL;
9107 field = (MonoClassField *)*iter;
9108 field++;
9109 if (field < &klass->fields [klass->field.count]) {
9110 *iter = field;
9111 return field;
9113 return NULL;
9117 * mono_class_get_methods
9118 * @klass: the MonoClass to act on
9120 * This routine is an iterator routine for retrieving the fields in a class.
9122 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9123 * iterate over all of the elements. When no more values are
9124 * available, the return value is NULL.
9126 * Returns: a MonoMethod on each iteration or NULL when no more methods are available.
9128 MonoMethod*
9129 mono_class_get_methods (MonoClass* klass, gpointer *iter)
9131 MonoMethod** method;
9132 if (!iter)
9133 return NULL;
9134 if (!*iter) {
9135 mono_class_setup_methods (klass);
9138 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9139 * FIXME we should better report this error to the caller
9141 if (!klass->methods)
9142 return NULL;
9143 /* start from the first */
9144 if (klass->method.count) {
9145 *iter = &klass->methods [0];
9146 return klass->methods [0];
9147 } else {
9148 /* no method */
9149 return NULL;
9152 method = (MonoMethod **)*iter;
9153 method++;
9154 if (method < &klass->methods [klass->method.count]) {
9155 *iter = method;
9156 return *method;
9158 return NULL;
9162 * mono_class_get_virtual_methods:
9164 * Iterate over the virtual methods of KLASS.
9166 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
9168 static MonoMethod*
9169 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
9171 MonoMethod** method;
9172 if (!iter)
9173 return NULL;
9174 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
9175 if (!*iter) {
9176 mono_class_setup_methods (klass);
9178 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9179 * FIXME we should better report this error to the caller
9181 if (!klass->methods)
9182 return NULL;
9183 /* start from the first */
9184 method = &klass->methods [0];
9185 } else {
9186 method = (MonoMethod **)*iter;
9187 method++;
9189 while (method < &klass->methods [klass->method.count]) {
9190 if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
9191 break;
9192 method ++;
9194 if (method < &klass->methods [klass->method.count]) {
9195 *iter = method;
9196 return *method;
9197 } else {
9198 return NULL;
9200 } else {
9201 /* Search directly in metadata to avoid calling setup_methods () */
9202 MonoMethod *res = NULL;
9203 int i, start_index;
9205 if (!*iter) {
9206 start_index = 0;
9207 } else {
9208 start_index = GPOINTER_TO_UINT (*iter);
9211 for (i = start_index; i < klass->method.count; ++i) {
9212 guint32 flags;
9214 /* klass->method.first points into the methodptr table */
9215 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
9217 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
9218 break;
9221 if (i < klass->method.count) {
9222 MonoError error;
9223 res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
9224 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9226 /* Add 1 here so the if (*iter) check fails */
9227 *iter = GUINT_TO_POINTER (i + 1);
9228 return res;
9229 } else {
9230 return NULL;
9236 * mono_class_get_properties:
9237 * @klass: the MonoClass to act on
9239 * This routine is an iterator routine for retrieving the properties in a class.
9241 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9242 * iterate over all of the elements. When no more values are
9243 * available, the return value is NULL.
9245 * Returns: a @MonoProperty* on each invocation, or NULL when no more are available.
9247 MonoProperty*
9248 mono_class_get_properties (MonoClass* klass, gpointer *iter)
9250 MonoProperty* property;
9251 if (!iter)
9252 return NULL;
9253 if (!*iter) {
9254 mono_class_setup_properties (klass);
9255 /* start from the first */
9256 if (klass->ext->property.count) {
9257 *iter = &klass->ext->properties [0];
9258 return (MonoProperty *)*iter;
9259 } else {
9260 /* no fields */
9261 return NULL;
9264 property = (MonoProperty *)*iter;
9265 property++;
9266 if (property < &klass->ext->properties [klass->ext->property.count]) {
9267 *iter = property;
9268 return (MonoProperty *)*iter;
9270 return NULL;
9274 * mono_class_get_events:
9275 * @klass: the MonoClass to act on
9277 * This routine is an iterator routine for retrieving the properties in a class.
9279 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9280 * iterate over all of the elements. When no more values are
9281 * available, the return value is NULL.
9283 * Returns: a @MonoEvent* on each invocation, or NULL when no more are available.
9285 MonoEvent*
9286 mono_class_get_events (MonoClass* klass, gpointer *iter)
9288 MonoEvent* event;
9289 if (!iter)
9290 return NULL;
9291 if (!*iter) {
9292 mono_class_setup_events (klass);
9293 /* start from the first */
9294 if (klass->ext->event.count) {
9295 *iter = &klass->ext->events [0];
9296 return (MonoEvent *)*iter;
9297 } else {
9298 /* no fields */
9299 return NULL;
9302 event = (MonoEvent *)*iter;
9303 event++;
9304 if (event < &klass->ext->events [klass->ext->event.count]) {
9305 *iter = event;
9306 return (MonoEvent *)*iter;
9308 return NULL;
9312 * mono_class_get_interfaces
9313 * @klass: the MonoClass to act on
9315 * This routine is an iterator routine for retrieving the interfaces implemented by this class.
9317 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9318 * iterate over all of the elements. When no more values are
9319 * available, the return value is NULL.
9321 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
9323 MonoClass*
9324 mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
9326 MonoError error;
9327 MonoClass** iface;
9328 if (!iter)
9329 return NULL;
9330 if (!*iter) {
9331 if (!klass->inited)
9332 mono_class_init (klass);
9333 if (!klass->interfaces_inited) {
9334 mono_class_setup_interfaces (klass, &error);
9335 if (!mono_error_ok (&error)) {
9336 mono_error_cleanup (&error);
9337 return NULL;
9340 /* start from the first */
9341 if (klass->interface_count) {
9342 *iter = &klass->interfaces [0];
9343 return klass->interfaces [0];
9344 } else {
9345 /* no interface */
9346 return NULL;
9349 iface = (MonoClass **)*iter;
9350 iface++;
9351 if (iface < &klass->interfaces [klass->interface_count]) {
9352 *iter = iface;
9353 return *iface;
9355 return NULL;
9358 static void
9359 setup_nested_types (MonoClass *klass)
9361 MonoError error;
9362 GList *classes, *nested_classes, *l;
9363 int i;
9365 if (klass->nested_classes_inited)
9366 return;
9368 if (!klass->type_token)
9369 klass->nested_classes_inited = TRUE;
9371 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
9372 classes = NULL;
9373 while (i) {
9374 MonoClass* nclass;
9375 guint32 cols [MONO_NESTED_CLASS_SIZE];
9376 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
9377 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error);
9378 if (!mono_error_ok (&error)) {
9379 /*FIXME don't swallow the error message*/
9380 mono_error_cleanup (&error);
9382 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
9383 continue;
9386 classes = g_list_prepend (classes, nclass);
9388 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
9391 mono_class_alloc_ext (klass);
9393 nested_classes = NULL;
9394 for (l = classes; l; l = l->next)
9395 nested_classes = g_list_prepend_image (klass->image, nested_classes, l->data);
9396 g_list_free (classes);
9398 mono_image_lock (klass->image);
9400 mono_memory_barrier ();
9401 if (!klass->nested_classes_inited) {
9402 klass->ext->nested_classes = nested_classes;
9403 mono_memory_barrier ();
9404 klass->nested_classes_inited = TRUE;
9407 mono_image_unlock (klass->image);
9411 * mono_class_get_nested_types
9412 * @klass: the MonoClass to act on
9414 * This routine is an iterator routine for retrieving the nested types of a class.
9415 * This works only if @klass is non-generic, or a generic type definition.
9417 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9418 * iterate over all of the elements. When no more values are
9419 * available, the return value is NULL.
9421 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
9423 MonoClass*
9424 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
9426 GList *item;
9428 if (!iter)
9429 return NULL;
9430 if (!klass->nested_classes_inited)
9431 setup_nested_types (klass);
9433 if (!*iter) {
9434 /* start from the first */
9435 if (klass->ext && klass->ext->nested_classes) {
9436 *iter = klass->ext->nested_classes;
9437 return (MonoClass *)klass->ext->nested_classes->data;
9438 } else {
9439 /* no nested types */
9440 return NULL;
9443 item = (GList *)*iter;
9444 item = item->next;
9445 if (item) {
9446 *iter = item;
9447 return (MonoClass *)item->data;
9449 return NULL;
9454 * mono_class_is_delegate
9455 * @klass: the MonoClass to act on
9457 * Returns: TRUE if the MonoClass represents a System.Delegate.
9459 mono_bool
9460 mono_class_is_delegate (MonoClass *klass)
9462 return klass->delegate;
9466 * mono_class_implements_interface
9467 * @klass: The MonoClass to act on
9468 * @interface: The interface to check if @klass implements.
9470 * Returns: TRUE if @klass implements @interface.
9472 mono_bool
9473 mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
9475 return mono_class_is_assignable_from (iface, klass);
9479 * mono_field_get_name:
9480 * @field: the MonoClassField to act on
9482 * Returns: The name of the field.
9484 const char*
9485 mono_field_get_name (MonoClassField *field)
9487 return field->name;
9491 * mono_field_get_type:
9492 * @field: the MonoClassField to act on
9494 * Returns: MonoType of the field.
9496 MonoType*
9497 mono_field_get_type (MonoClassField *field)
9499 MonoError error;
9500 MonoType *type = mono_field_get_type_checked (field, &error);
9501 if (!mono_error_ok (&error)) {
9502 mono_trace_warning (MONO_TRACE_TYPE, "Could not load field's type due to %s", mono_error_get_message (&error));
9503 mono_error_cleanup (&error);
9505 return type;
9510 * mono_field_get_type_checked:
9511 * @field: the MonoClassField to act on
9512 * @error: used to return any erro found while retrieving @field type
9514 * Returns: MonoType of the field.
9516 MonoType*
9517 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
9519 mono_error_init (error);
9520 if (!field->type)
9521 mono_field_resolve_type (field, error);
9522 return field->type;
9526 * mono_field_get_parent:
9527 * @field: the MonoClassField to act on
9529 * Returns: MonoClass where the field was defined.
9531 MonoClass*
9532 mono_field_get_parent (MonoClassField *field)
9534 return field->parent;
9538 * mono_field_get_flags;
9539 * @field: the MonoClassField to act on
9541 * The metadata flags for a field are encoded using the
9542 * FIELD_ATTRIBUTE_* constants. See the tabledefs.h file for details.
9544 * Returns: The flags for the field.
9546 guint32
9547 mono_field_get_flags (MonoClassField *field)
9549 if (!field->type)
9550 return mono_field_resolve_flags (field);
9551 return field->type->attrs;
9555 * mono_field_get_offset:
9556 * @field: the MonoClassField to act on
9558 * Returns: The field offset.
9560 guint32
9561 mono_field_get_offset (MonoClassField *field)
9563 return field->offset;
9566 static const char *
9567 mono_field_get_rva (MonoClassField *field)
9569 guint32 rva;
9570 int field_index;
9571 MonoClass *klass = field->parent;
9572 MonoFieldDefaultValue *field_def_values;
9574 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
9576 if (!klass->ext || !klass->ext->field_def_values) {
9577 mono_class_alloc_ext (klass);
9579 field_def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
9581 mono_image_lock (klass->image);
9582 if (!klass->ext->field_def_values)
9583 klass->ext->field_def_values = field_def_values;
9584 mono_image_unlock (klass->image);
9587 field_index = mono_field_get_index (field);
9589 if (!klass->ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) {
9590 mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL);
9591 if (!rva)
9592 g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
9593 klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
9596 return klass->ext->field_def_values [field_index].data;
9600 * mono_field_get_data:
9601 * @field: the MonoClassField to act on
9603 * Returns: A pointer to the metadata constant value or to the field
9604 * data if it has an RVA flag.
9606 const char *
9607 mono_field_get_data (MonoClassField *field)
9609 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
9610 MonoTypeEnum def_type;
9612 return mono_class_get_field_default_value (field, &def_type);
9613 } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
9614 return mono_field_get_rva (field);
9615 } else {
9616 return NULL;
9621 * mono_property_get_name:
9622 * @prop: the MonoProperty to act on
9624 * Returns: The name of the property
9626 const char*
9627 mono_property_get_name (MonoProperty *prop)
9629 return prop->name;
9633 * mono_property_get_set_method
9634 * @prop: the MonoProperty to act on.
9636 * Returns: The setter method of the property (A MonoMethod)
9638 MonoMethod*
9639 mono_property_get_set_method (MonoProperty *prop)
9641 return prop->set;
9645 * mono_property_get_get_method
9646 * @prop: the MonoProperty to act on.
9648 * Returns: The setter method of the property (A MonoMethod)
9650 MonoMethod*
9651 mono_property_get_get_method (MonoProperty *prop)
9653 return prop->get;
9657 * mono_property_get_parent:
9658 * @prop: the MonoProperty to act on.
9660 * Returns: The MonoClass where the property was defined.
9662 MonoClass*
9663 mono_property_get_parent (MonoProperty *prop)
9665 return prop->parent;
9669 * mono_property_get_flags:
9670 * @prop: the MonoProperty to act on.
9672 * The metadata flags for a property are encoded using the
9673 * PROPERTY_ATTRIBUTE_* constants. See the tabledefs.h file for details.
9675 * Returns: The flags for the property.
9677 guint32
9678 mono_property_get_flags (MonoProperty *prop)
9680 return prop->attrs;
9684 * mono_event_get_name:
9685 * @event: the MonoEvent to act on
9687 * Returns: The name of the event.
9689 const char*
9690 mono_event_get_name (MonoEvent *event)
9692 return event->name;
9696 * mono_event_get_add_method:
9697 * @event: The MonoEvent to act on.
9699 * Returns: The @add' method for the event (a MonoMethod).
9701 MonoMethod*
9702 mono_event_get_add_method (MonoEvent *event)
9704 return event->add;
9708 * mono_event_get_remove_method:
9709 * @event: The MonoEvent to act on.
9711 * Returns: The @remove method for the event (a MonoMethod).
9713 MonoMethod*
9714 mono_event_get_remove_method (MonoEvent *event)
9716 return event->remove;
9720 * mono_event_get_raise_method:
9721 * @event: The MonoEvent to act on.
9723 * Returns: The @raise method for the event (a MonoMethod).
9725 MonoMethod*
9726 mono_event_get_raise_method (MonoEvent *event)
9728 return event->raise;
9732 * mono_event_get_parent:
9733 * @event: the MonoEvent to act on.
9735 * Returns: The MonoClass where the event is defined.
9737 MonoClass*
9738 mono_event_get_parent (MonoEvent *event)
9740 return event->parent;
9744 * mono_event_get_flags
9745 * @event: the MonoEvent to act on.
9747 * The metadata flags for an event are encoded using the
9748 * EVENT_* constants. See the tabledefs.h file for details.
9750 * Returns: The flags for the event.
9752 guint32
9753 mono_event_get_flags (MonoEvent *event)
9755 return event->attrs;
9759 * mono_class_get_method_from_name:
9760 * @klass: where to look for the method
9761 * @name: name of the method
9762 * @param_count: number of parameters. -1 for any number.
9764 * Obtains a MonoMethod with a given name and number of parameters.
9765 * It only works if there are no multiple signatures for any given method name.
9767 MonoMethod *
9768 mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_count)
9770 return mono_class_get_method_from_name_flags (klass, name, param_count, 0);
9773 static MonoMethod*
9774 find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
9776 MonoMethod *res = NULL;
9777 int i;
9779 /* Search directly in the metadata to avoid calling setup_methods () */
9780 for (i = 0; i < klass->method.count; ++i) {
9781 MonoError error;
9782 guint32 cols [MONO_METHOD_SIZE];
9783 MonoMethod *method;
9784 MonoMethodSignature *sig;
9786 /* klass->method.first points into the methodptr table */
9787 mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE);
9789 if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
9790 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
9791 if (!method) {
9792 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9793 continue;
9795 if (param_count == -1) {
9796 res = method;
9797 break;
9799 sig = mono_method_signature_checked (method, &error);
9800 if (!sig) {
9801 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9802 continue;
9804 if (sig->param_count == param_count) {
9805 res = method;
9806 break;
9811 return res;
9815 * mono_class_get_method_from_name_flags:
9816 * @klass: where to look for the method
9817 * @name_space: name of the method
9818 * @param_count: number of parameters. -1 for any number.
9819 * @flags: flags which must be set in the method
9821 * Obtains a MonoMethod with a given name and number of parameters.
9822 * It only works if there are no multiple signatures for any given method name.
9824 MonoMethod *
9825 mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int param_count, int flags)
9827 MonoMethod *res = NULL;
9828 int i;
9830 mono_class_init (klass);
9832 if (klass->generic_class && !klass->methods) {
9833 res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags);
9834 if (res) {
9835 MonoError error;
9836 res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), &error);
9837 if (!mono_error_ok (&error))
9838 mono_error_cleanup (&error); /*FIXME don't swallow the error */
9840 return res;
9843 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
9844 mono_class_setup_methods (klass);
9846 We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9847 See mono/tests/array_load_exception.il
9848 FIXME we should better report this error to the caller
9850 if (!klass->methods)
9851 return NULL;
9852 for (i = 0; i < klass->method.count; ++i) {
9853 MonoMethod *method = klass->methods [i];
9855 if (method->name[0] == name [0] &&
9856 !strcmp (name, method->name) &&
9857 (param_count == -1 || mono_method_signature (method)->param_count == param_count) &&
9858 ((method->flags & flags) == flags)) {
9859 res = method;
9860 break;
9864 else {
9865 res = find_method_in_metadata (klass, name, param_count, flags);
9868 return res;
9872 * mono_class_set_failure:
9873 * @klass: class in which the failure was detected
9874 * @ex_type: the kind of exception/error to be thrown (later)
9875 * @ex_data: exception data (specific to each type of exception/error)
9877 * Keep a detected failure informations in the class for later processing.
9878 * Note that only the first failure is kept.
9880 * LOCKING: Acquires the loader lock.
9882 static gboolean
9883 mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error)
9885 g_assert (boxed_error != NULL);
9887 if (mono_class_has_failure (klass))
9888 return FALSE;
9890 mono_loader_lock ();
9891 klass->has_failure = 1;
9892 mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, boxed_error);
9893 mono_loader_unlock ();
9895 return TRUE;
9898 gboolean
9899 mono_class_has_failure (const MonoClass *klass)
9901 g_assert (klass != NULL);
9902 return klass->has_failure != 0;
9907 * mono_class_set_type_load_failure:
9908 * @klass: class in which the failure was detected
9909 * @fmt: Printf-style error message string.
9911 * Collect detected failure informaion in the class for later processing.
9912 * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class ()
9913 * Note that only the first failure is kept.
9915 * Returns FALSE if a failure was already set on the class, or TRUE otherwise.
9917 * LOCKING: Acquires the loader lock.
9919 gboolean
9920 mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
9922 MonoError prepare_error;
9923 va_list args;
9925 if (mono_class_has_failure (klass))
9926 return FALSE;
9928 mono_error_init (&prepare_error);
9930 va_start (args, fmt);
9931 mono_error_vset_type_load_class (&prepare_error, klass, fmt, args);
9932 va_end (args);
9934 MonoErrorBoxed *box = mono_error_box (&prepare_error, klass->image);
9935 mono_error_cleanup (&prepare_error);
9936 return mono_class_set_failure (klass, box);
9940 * mono_class_get_exception_data:
9942 * Return the exception_data property of KLASS.
9944 * LOCKING: Acquires the loader lock.
9946 static gpointer
9947 mono_class_get_exception_data (const MonoClass *klass)
9949 return mono_image_property_lookup (klass->image, (MonoClass*)klass, MONO_CLASS_PROP_EXCEPTION_DATA);
9953 * mono_classes_init:
9955 * Initialize the resources used by this module.
9957 void
9958 mono_classes_init (void)
9960 mono_os_mutex_init (&classes_mutex);
9962 mono_native_tls_alloc (&setup_fields_tls_id, NULL);
9964 mono_counters_register ("Inflated methods size",
9965 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
9966 mono_counters_register ("Inflated classes",
9967 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes);
9968 mono_counters_register ("Inflated classes size",
9969 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
9970 mono_counters_register ("MonoClass size",
9971 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
9972 mono_counters_register ("MonoClassExt size",
9973 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size);
9977 * mono_classes_cleanup:
9979 * Free the resources used by this module.
9981 void
9982 mono_classes_cleanup (void)
9984 mono_native_tls_free (setup_fields_tls_id);
9986 if (global_interface_bitset)
9987 mono_bitset_free (global_interface_bitset);
9988 global_interface_bitset = NULL;
9989 mono_os_mutex_destroy (&classes_mutex);
9993 * mono_class_get_exception_for_failure:
9994 * @klass: class in which the failure was detected
9996 * Return a constructed MonoException than the caller can then throw
9997 * using mono_raise_exception - or NULL if no failure is present (or
9998 * doesn't result in an exception).
10000 MonoException*
10001 mono_class_get_exception_for_failure (MonoClass *klass)
10003 if (!mono_class_has_failure (klass))
10004 return NULL;
10005 MonoError unboxed_error;
10006 mono_error_init (&unboxed_error);
10007 mono_error_set_for_class_failure (&unboxed_error, klass);
10008 return mono_error_convert_to_exception (&unboxed_error);
10011 static gboolean
10012 is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
10014 outer_klass = mono_class_get_generic_type_definition (outer_klass);
10015 inner_klass = mono_class_get_generic_type_definition (inner_klass);
10016 do {
10017 if (outer_klass == inner_klass)
10018 return TRUE;
10019 inner_klass = inner_klass->nested_in;
10020 } while (inner_klass);
10021 return FALSE;
10024 MonoClass *
10025 mono_class_get_generic_type_definition (MonoClass *klass)
10027 return klass->generic_class ? klass->generic_class->container_class : klass;
10031 * Check if @klass is a subtype of @parent ignoring generic instantiations.
10033 * Generic instantiations are ignored for all super types of @klass.
10035 * Visibility checks ignoring generic instantiations.
10037 gboolean
10038 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
10040 int i;
10041 klass = mono_class_get_generic_type_definition (klass);
10042 parent = mono_class_get_generic_type_definition (parent);
10043 mono_class_setup_supertypes (klass);
10045 for (i = 0; i < klass->idepth; ++i) {
10046 if (parent == mono_class_get_generic_type_definition (klass->supertypes [i]))
10047 return TRUE;
10049 return FALSE;
10052 * Subtype can only access parent members with family protection if the site object
10053 * is subclass of Subtype. For example:
10054 * class A { protected int x; }
10055 * class B : A {
10056 * void valid_access () {
10057 * B b;
10058 * b.x = 0;
10060 * void invalid_access () {
10061 * A a;
10062 * a.x = 0;
10065 * */
10066 static gboolean
10067 is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
10069 if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
10070 return FALSE;
10072 if (context_klass == NULL)
10073 return TRUE;
10074 /*if access_klass is not member_klass context_klass must be type compat*/
10075 if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
10076 return FALSE;
10077 return TRUE;
10080 static gboolean
10081 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
10083 GSList *tmp;
10084 if (accessing == accessed)
10085 return TRUE;
10086 if (!accessed || !accessing)
10087 return FALSE;
10089 /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
10090 * anywhere so untrusted friends are not safe to access platform's code internals */
10091 if (mono_security_core_clr_enabled ()) {
10092 if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
10093 return FALSE;
10096 mono_assembly_load_friends (accessed);
10097 for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
10098 MonoAssemblyName *friend_ = (MonoAssemblyName *)tmp->data;
10099 /* Be conservative with checks */
10100 if (!friend_->name)
10101 continue;
10102 if (strcmp (accessing->aname.name, friend_->name))
10103 continue;
10104 if (friend_->public_key_token [0]) {
10105 if (!accessing->aname.public_key_token [0])
10106 continue;
10107 if (!mono_public_tokens_are_equal (friend_->public_key_token, accessing->aname.public_key_token))
10108 continue;
10110 return TRUE;
10112 return FALSE;
10116 * If klass is a generic type or if it is derived from a generic type, return the
10117 * MonoClass of the generic definition
10118 * Returns NULL if not found
10120 static MonoClass*
10121 get_generic_definition_class (MonoClass *klass)
10123 while (klass) {
10124 if (klass->generic_class && klass->generic_class->container_class)
10125 return klass->generic_class->container_class;
10126 klass = klass->parent;
10128 return NULL;
10131 static gboolean
10132 can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
10134 int i;
10135 for (i = 0; i < ginst->type_argc; ++i) {
10136 MonoType *type = ginst->type_argv[i];
10137 switch (type->type) {
10138 case MONO_TYPE_SZARRAY:
10139 if (!can_access_type (access_klass, type->data.klass))
10140 return FALSE;
10141 break;
10142 case MONO_TYPE_ARRAY:
10143 if (!can_access_type (access_klass, type->data.array->eklass))
10144 return FALSE;
10145 break;
10146 case MONO_TYPE_PTR:
10147 if (!can_access_type (access_klass, mono_class_from_mono_type (type->data.type)))
10148 return FALSE;
10149 break;
10150 case MONO_TYPE_CLASS:
10151 case MONO_TYPE_VALUETYPE:
10152 case MONO_TYPE_GENERICINST:
10153 if (!can_access_type (access_klass, mono_class_from_mono_type (type)))
10154 return FALSE;
10155 default:
10156 break;
10159 return TRUE;
10162 static gboolean
10163 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
10165 int access_level;
10167 if (access_klass == member_klass)
10168 return TRUE;
10170 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
10171 return TRUE;
10173 if (access_klass->element_class && !access_klass->enumtype)
10174 access_klass = access_klass->element_class;
10176 if (member_klass->element_class && !member_klass->enumtype)
10177 member_klass = member_klass->element_class;
10179 access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
10181 if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
10182 return TRUE;
10184 if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst))
10185 return FALSE;
10187 if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
10188 return TRUE;
10190 if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
10191 return FALSE;
10193 /*Non nested type with nested visibility. We just fail it.*/
10194 if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL)
10195 return FALSE;
10197 switch (access_level) {
10198 case TYPE_ATTRIBUTE_NOT_PUBLIC:
10199 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10201 case TYPE_ATTRIBUTE_PUBLIC:
10202 return TRUE;
10204 case TYPE_ATTRIBUTE_NESTED_PUBLIC:
10205 return TRUE;
10207 case TYPE_ATTRIBUTE_NESTED_PRIVATE:
10208 return is_nesting_type (member_klass, access_klass);
10210 case TYPE_ATTRIBUTE_NESTED_FAMILY:
10211 return mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10213 case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
10214 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10216 case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
10217 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) &&
10218 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10220 case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
10221 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) ||
10222 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10224 return FALSE;
10227 /* FIXME: check visibility of type, too */
10228 static gboolean
10229 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
10231 MonoClass *member_generic_def;
10232 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
10233 return TRUE;
10235 if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
10236 access_klass->generic_container) &&
10237 (member_generic_def = get_generic_definition_class (member_klass))) {
10238 MonoClass *access_container;
10240 if (access_klass->generic_container)
10241 access_container = access_klass;
10242 else
10243 access_container = access_klass->generic_class->container_class;
10245 if (can_access_member (access_container, member_generic_def, context_klass, access_level))
10246 return TRUE;
10249 /* Partition I 8.5.3.2 */
10250 /* the access level values are the same for fields and methods */
10251 switch (access_level) {
10252 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
10253 /* same compilation unit */
10254 return access_klass->image == member_klass->image;
10255 case FIELD_ATTRIBUTE_PRIVATE:
10256 return access_klass == member_klass;
10257 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
10258 if (is_valid_family_access (access_klass, member_klass, context_klass) &&
10259 can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
10260 return TRUE;
10261 return FALSE;
10262 case FIELD_ATTRIBUTE_ASSEMBLY:
10263 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10264 case FIELD_ATTRIBUTE_FAMILY:
10265 if (is_valid_family_access (access_klass, member_klass, context_klass))
10266 return TRUE;
10267 return FALSE;
10268 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
10269 if (is_valid_family_access (access_klass, member_klass, context_klass))
10270 return TRUE;
10271 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10272 case FIELD_ATTRIBUTE_PUBLIC:
10273 return TRUE;
10275 return FALSE;
10279 * mono_method_can_access_field:
10280 * @method: Method that will attempt to access the field
10281 * @field: the field to access
10283 * Used to determine if a method is allowed to access the specified field.
10285 * Returns: TRUE if the given @method is allowed to access the @field while following
10286 * the accessibility rules of the CLI.
10288 gboolean
10289 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
10291 /* FIXME: check all overlapping fields */
10292 int can = can_access_member (method->klass, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10293 if (!can) {
10294 MonoClass *nested = method->klass->nested_in;
10295 while (nested) {
10296 can = can_access_member (nested, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10297 if (can)
10298 return TRUE;
10299 nested = nested->nested_in;
10302 return can;
10306 * mono_method_can_access_method:
10307 * @method: Method that will attempt to access the other method
10308 * @called: the method that we want to probe for accessibility.
10310 * Used to determine if the @method is allowed to access the specified @called method.
10312 * Returns: TRUE if the given @method is allowed to invoke the @called while following
10313 * the accessibility rules of the CLI.
10315 gboolean
10316 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
10318 method = mono_method_get_method_definition (method);
10319 called = mono_method_get_method_definition (called);
10320 return mono_method_can_access_method_full (method, called, NULL);
10324 * mono_method_can_access_method_full:
10325 * @method: The caller method
10326 * @called: The called method
10327 * @context_klass: The static type on stack of the owner @called object used
10329 * This function must be used with instance calls, as they have more strict family accessibility.
10330 * It can be used with static methods, but context_klass should be NULL.
10332 * Returns: TRUE if caller have proper visibility and acessibility to @called
10334 gboolean
10335 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
10337 /* Wrappers are except from access checks */
10338 if (method->wrapper_type != MONO_WRAPPER_NONE || called->wrapper_type != MONO_WRAPPER_NONE)
10339 return TRUE;
10341 MonoClass *access_class = method->klass;
10342 MonoClass *member_class = called->klass;
10343 int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10344 if (!can) {
10345 MonoClass *nested = access_class->nested_in;
10346 while (nested) {
10347 can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10348 if (can)
10349 break;
10350 nested = nested->nested_in;
10354 if (!can)
10355 return FALSE;
10357 can = can_access_type (access_class, member_class);
10358 if (!can) {
10359 MonoClass *nested = access_class->nested_in;
10360 while (nested) {
10361 can = can_access_type (nested, member_class);
10362 if (can)
10363 break;
10364 nested = nested->nested_in;
10368 if (!can)
10369 return FALSE;
10371 if (called->is_inflated) {
10372 MonoMethodInflated * infl = (MonoMethodInflated*)called;
10373 if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
10374 return FALSE;
10377 return TRUE;
10382 * mono_method_can_access_field_full:
10383 * @method: The caller method
10384 * @field: The accessed field
10385 * @context_klass: The static type on stack of the owner @field object used
10387 * This function must be used with instance fields, as they have more strict family accessibility.
10388 * It can be used with static fields, but context_klass should be NULL.
10390 * Returns: TRUE if caller have proper visibility and acessibility to @field
10392 gboolean
10393 mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
10395 MonoClass *access_class = method->klass;
10396 MonoClass *member_class = field->parent;
10397 /* FIXME: check all overlapping fields */
10398 int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10399 if (!can) {
10400 MonoClass *nested = access_class->nested_in;
10401 while (nested) {
10402 can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10403 if (can)
10404 break;
10405 nested = nested->nested_in;
10409 if (!can)
10410 return FALSE;
10412 can = can_access_type (access_class, member_class);
10413 if (!can) {
10414 MonoClass *nested = access_class->nested_in;
10415 while (nested) {
10416 can = can_access_type (nested, member_class);
10417 if (can)
10418 break;
10419 nested = nested->nested_in;
10423 if (!can)
10424 return FALSE;
10425 return TRUE;
10429 * mono_class_can_access_class:
10430 * @source_class: The source class
10431 * @target_class: The accessed class
10433 * This function returns is @target_class is visible to @source_class
10435 * Returns: TRUE if source have proper visibility and acessibility to target
10437 gboolean
10438 mono_class_can_access_class (MonoClass *source_class, MonoClass *target_class)
10440 return can_access_type (source_class, target_class);
10444 * mono_type_is_valid_enum_basetype:
10445 * @type: The MonoType to check
10447 * Returns: TRUE if the type can be used as the basetype of an enum
10449 gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
10450 switch (type->type) {
10451 case MONO_TYPE_I1:
10452 case MONO_TYPE_U1:
10453 case MONO_TYPE_BOOLEAN:
10454 case MONO_TYPE_I2:
10455 case MONO_TYPE_U2:
10456 case MONO_TYPE_CHAR:
10457 case MONO_TYPE_I4:
10458 case MONO_TYPE_U4:
10459 case MONO_TYPE_I8:
10460 case MONO_TYPE_U8:
10461 case MONO_TYPE_I:
10462 case MONO_TYPE_U:
10463 return TRUE;
10464 default:
10465 return FALSE;
10470 * mono_class_is_valid_enum:
10471 * @klass: An enum class to be validated
10473 * This method verify the required properties an enum should have.
10475 * Returns: TRUE if the informed enum class is valid
10477 * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
10478 * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
10479 * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
10481 gboolean mono_class_is_valid_enum (MonoClass *klass) {
10482 MonoClassField * field;
10483 gpointer iter = NULL;
10484 gboolean found_base_field = FALSE;
10486 g_assert (klass->enumtype);
10487 /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
10488 if (!klass->parent || strcmp (klass->parent->name, "Enum") || strcmp (klass->parent->name_space, "System") ) {
10489 return FALSE;
10492 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)
10493 return FALSE;
10495 while ((field = mono_class_get_fields (klass, &iter))) {
10496 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
10497 if (found_base_field)
10498 return FALSE;
10499 found_base_field = TRUE;
10500 if (!mono_type_is_valid_enum_basetype (field->type))
10501 return FALSE;
10505 if (!found_base_field)
10506 return FALSE;
10508 if (klass->method.count > 0)
10509 return FALSE;
10511 return TRUE;
10514 gboolean
10515 mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
10517 return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
10521 * mono_class_setup_interface_id:
10523 * Initializes MonoClass::interface_id if required.
10525 * LOCKING: Acquires the loader lock.
10527 void
10528 mono_class_setup_interface_id (MonoClass *klass)
10530 mono_loader_lock ();
10531 if (MONO_CLASS_IS_INTERFACE (klass) && !klass->interface_id)
10532 klass->interface_id = mono_get_unique_iid (klass);
10533 mono_loader_unlock ();
10537 * mono_class_alloc_ext:
10539 * Allocate klass->ext if not already done.
10541 void
10542 mono_class_alloc_ext (MonoClass *klass)
10544 MonoClassExt *ext;
10546 if (klass->ext)
10547 return;
10549 ext = (MonoClassExt *)mono_class_alloc0 (klass, sizeof (MonoClassExt));
10550 mono_image_lock (klass->image);
10551 mono_memory_barrier ();
10552 if (!klass->ext)
10553 klass->ext = ext;
10554 class_ext_size += sizeof (MonoClassExt);
10555 mono_image_unlock (klass->image);
10559 * mono_class_setup_interfaces:
10561 * Initialize klass->interfaces/interfaces_count.
10562 * LOCKING: Acquires the loader lock.
10563 * This function can fail the type.
10565 void
10566 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
10568 int i, interface_count;
10569 MonoClass **interfaces;
10571 mono_error_init (error);
10573 if (klass->interfaces_inited)
10574 return;
10576 if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY) {
10577 MonoType *args [1];
10579 /* generic IList, ICollection, IEnumerable */
10580 interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
10581 interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
10583 args [0] = &klass->element_class->byval_arg;
10584 interfaces [0] = mono_class_bind_generic_parameters (
10585 mono_defaults.generic_ilist_class, 1, args, FALSE);
10586 if (interface_count > 1)
10587 interfaces [1] = mono_class_bind_generic_parameters (
10588 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
10589 } else if (klass->generic_class) {
10590 MonoClass *gklass = klass->generic_class->container_class;
10592 mono_class_setup_interfaces (gklass, error);
10593 if (!mono_error_ok (error)) {
10594 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
10595 return;
10598 interface_count = gklass->interface_count;
10599 interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
10600 for (i = 0; i < interface_count; i++) {
10601 interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error);
10602 if (!mono_error_ok (error)) {
10603 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
10604 return;
10607 } else {
10608 interface_count = 0;
10609 interfaces = NULL;
10612 mono_image_lock (klass->image);
10614 if (!klass->interfaces_inited) {
10615 klass->interface_count = interface_count;
10616 klass->interfaces = interfaces;
10618 mono_memory_barrier ();
10620 klass->interfaces_inited = TRUE;
10623 mono_image_unlock (klass->image);
10626 static void
10627 mono_field_resolve_type (MonoClassField *field, MonoError *error)
10629 MonoClass *klass = field->parent;
10630 MonoImage *image = klass->image;
10631 MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
10632 int field_idx = field - klass->fields;
10634 mono_error_init (error);
10636 if (gtd) {
10637 MonoClassField *gfield = &gtd->fields [field_idx];
10638 MonoType *gtype = mono_field_get_type_checked (gfield, error);
10639 if (!mono_error_ok (error)) {
10640 mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
10643 field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
10644 if (!mono_error_ok (error)) {
10645 mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
10647 } else {
10648 const char *sig;
10649 guint32 cols [MONO_FIELD_SIZE];
10650 MonoGenericContainer *container = NULL;
10651 int idx = klass->field.first + field_idx;
10653 /*FIXME, in theory we do not lazy load SRE fields*/
10654 g_assert (!image_is_dynamic (image));
10656 if (klass->generic_container) {
10657 container = klass->generic_container;
10658 } else if (gtd) {
10659 container = gtd->generic_container;
10660 g_assert (container);
10663 /* klass->field.first and idx points into the fieldptr table */
10664 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
10666 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) {
10667 mono_error_set_type_load_class (error, klass, "Could not verify field %s signature", field->name);;
10668 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
10669 return;
10672 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
10674 mono_metadata_decode_value (sig, &sig);
10675 /* FIELD signature == 0x06 */
10676 g_assert (*sig == 0x06);
10678 field->type = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
10679 if (!field->type) {
10680 mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
10685 static guint32
10686 mono_field_resolve_flags (MonoClassField *field)
10688 MonoClass *klass = field->parent;
10689 MonoImage *image = klass->image;
10690 MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
10691 int field_idx = field - klass->fields;
10694 if (gtd) {
10695 MonoClassField *gfield = &gtd->fields [field_idx];
10696 return mono_field_get_flags (gfield);
10697 } else {
10698 int idx = klass->field.first + field_idx;
10700 /*FIXME, in theory we do not lazy load SRE fields*/
10701 g_assert (!image_is_dynamic (image));
10703 return mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_FLAGS);
10708 * mono_class_get_fields_lazy:
10709 * @klass: the MonoClass to act on
10711 * This routine is an iterator routine for retrieving the fields in a class.
10712 * Only minimal information about fields are loaded. Accessors must be used
10713 * for all MonoClassField returned.
10715 * You must pass a gpointer that points to zero and is treated as an opaque handle to
10716 * iterate over all of the elements. When no more values are
10717 * available, the return value is NULL.
10719 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
10721 MonoClassField*
10722 mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
10724 MonoClassField* field;
10725 if (!iter)
10726 return NULL;
10727 if (!*iter) {
10728 mono_class_setup_basic_field_info (klass);
10729 if (!klass->fields)
10730 return NULL;
10731 /* start from the first */
10732 if (klass->field.count) {
10733 *iter = &klass->fields [0];
10734 return (MonoClassField *)*iter;
10735 } else {
10736 /* no fields */
10737 return NULL;
10740 field = (MonoClassField *)*iter;
10741 field++;
10742 if (field < &klass->fields [klass->field.count]) {
10743 *iter = field;
10744 return (MonoClassField *)*iter;
10746 return NULL;
10749 char*
10750 mono_class_full_name (MonoClass *klass)
10752 return mono_type_full_name (&klass->byval_arg);
10755 /* Declare all shared lazy type lookup functions */
10756 GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle)