Merge pull request #3936 from kumpera/monoclass_reorg2
[mono-project.git] / mono / metadata / class.c
blob3f54ba7397c04d4e32e998a530b0d2a32b7bfd1c
1 /*
2 * class.c: Class management for the Mono runtime
4 * Author:
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12 #include <config.h>
13 #ifdef HAVE_ALLOCA_H
14 #include <alloca.h>
15 #endif
16 #include <glib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <mono/metadata/image.h>
21 #include <mono/metadata/image-internals.h>
22 #include <mono/metadata/assembly.h>
23 #include <mono/metadata/assembly-internals.h>
24 #include <mono/metadata/metadata.h>
25 #include <mono/metadata/metadata-internals.h>
26 #include <mono/metadata/profiler-private.h>
27 #include <mono/metadata/tabledefs.h>
28 #include <mono/metadata/tokentype.h>
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/object.h>
31 #include <mono/metadata/appdomain.h>
32 #include <mono/metadata/mono-endian.h>
33 #include <mono/metadata/debug-helpers.h>
34 #include <mono/metadata/reflection.h>
35 #include <mono/metadata/exception.h>
36 #include <mono/metadata/security-manager.h>
37 #include <mono/metadata/security-core-clr.h>
38 #include <mono/metadata/attrdefs.h>
39 #include <mono/metadata/gc-internals.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/mono-debug.h>
42 #include <mono/utils/mono-counters.h>
43 #include <mono/utils/mono-string.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/mono-logger-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/atomic.h>
48 #include <mono/utils/bsearch.h>
49 #include <mono/utils/checked-build.h>
51 MonoStats mono_stats;
53 gboolean mono_print_vtable = FALSE;
54 gboolean mono_align_small_structs = FALSE;
56 /* Statistics */
57 guint32 inflated_classes_size, inflated_methods_size;
58 guint32 classes_size, class_ext_size, class_ext_count;
59 guint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
61 /* Low level lock which protects data structures in this module */
62 static mono_mutex_t classes_mutex;
64 /* Function supplied by the runtime to find classes by name using information from the AOT file */
65 static MonoGetClassFromName get_class_from_name = NULL;
67 static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error);
68 static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res);
69 static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
70 static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
71 static int generic_array_methods (MonoClass *klass);
72 static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos);
74 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
75 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
76 static void mono_field_resolve_type (MonoClassField *field, MonoError *error);
77 static guint32 mono_field_resolve_flags (MonoClassField *field);
78 static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
79 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
81 static gboolean mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error);
82 static gpointer mono_class_get_exception_data (const MonoClass *klass);
86 We use gclass recording to allow recursive system f types to be referenced by a parent.
88 Given the following type hierarchy:
90 class TextBox : TextBoxBase<TextBox> {}
91 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
92 class TextInput<T> : Input<T> where T: TextInput<T> {}
93 class Input<T> {}
95 The runtime tries to load TextBoxBase<>.
96 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
97 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
98 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
100 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
101 at this point, iow, both are registered in the type map and both and a NULL parent. This means
102 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
104 To fix that what we do is to record all generic instantes created while resolving the parent of
105 any generic type definition and, after resolved, correct the parent field if needed.
108 static int record_gclass_instantiation;
109 static GSList *gclass_recorded_list;
110 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
112 /* This TLS variable points to a GSList of classes which have setup_fields () executing */
113 static MonoNativeTlsKey setup_fields_tls_id;
115 static MonoNativeTlsKey init_pending_tls_id;
117 static inline void
118 classes_lock (void)
120 mono_locks_os_acquire (&classes_mutex, ClassesLock);
123 static inline void
124 classes_unlock (void)
126 mono_locks_os_release (&classes_mutex, ClassesLock);
130 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
132 static void
133 enable_gclass_recording (void)
135 ++record_gclass_instantiation;
139 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
141 static void
142 disable_gclass_recording (gclass_record_func func, void *user_data)
144 GSList **head = &gclass_recorded_list;
146 g_assert (record_gclass_instantiation > 0);
147 --record_gclass_instantiation;
149 while (*head) {
150 GSList *node = *head;
151 if (func ((MonoClass*)node->data, user_data)) {
152 *head = node->next;
153 g_slist_free_1 (node);
154 } else {
155 head = &node->next;
159 /* We automatically discard all recorded gclasses when disabled. */
160 if (!record_gclass_instantiation && gclass_recorded_list) {
161 g_slist_free (gclass_recorded_list);
162 gclass_recorded_list = NULL;
167 * mono_class_from_typeref:
168 * @image: a MonoImage
169 * @type_token: a TypeRef token
171 * Creates the MonoClass* structure representing the type defined by
172 * the typeref token valid inside @image.
173 * Returns: The MonoClass* representing the typeref token, NULL ifcould
174 * not be loaded.
176 MonoClass *
177 mono_class_from_typeref (MonoImage *image, guint32 type_token)
179 MonoError error;
180 MonoClass *klass = mono_class_from_typeref_checked (image, type_token, &error);
181 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
182 return klass;
186 * mono_class_from_typeref_checked:
187 * @image: a MonoImage
188 * @type_token: a TypeRef token
189 * @error: error return code, if any.
191 * Creates the MonoClass* structure representing the type defined by
192 * the typeref token valid inside @image.
194 * Returns: The MonoClass* representing the typeref token, NULL if it could
195 * not be loaded with the @error value filled with the information about the
196 * error.
198 MonoClass *
199 mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
201 guint32 cols [MONO_TYPEREF_SIZE];
202 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
203 guint32 idx;
204 const char *name, *nspace;
205 MonoClass *res = NULL;
206 MonoImage *module;
208 mono_error_init (error);
210 if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
211 return NULL;
213 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
215 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
216 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
218 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
219 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
220 case MONO_RESOLUTION_SCOPE_MODULE:
222 LAMESPEC The spec says that a null module resolution scope should go through the exported type table.
223 This is not the observed behavior of existing implementations.
224 The defacto behavior is that it's just a typedef in disguise.
226 /* a typedef in disguise */
227 res = mono_class_from_name_checked (image, nspace, name, error);
228 goto done;
230 case MONO_RESOLUTION_SCOPE_MODULEREF:
231 module = mono_image_load_module_checked (image, idx, error);
232 if (module)
233 res = mono_class_from_name_checked (module, nspace, name, error);
234 goto done;
236 case MONO_RESOLUTION_SCOPE_TYPEREF: {
237 MonoClass *enclosing;
238 GList *tmp;
240 if (idx == mono_metadata_token_index (type_token)) {
241 mono_error_set_bad_image (error, image, "Image with self-referencing typeref token %08x.", type_token);
242 return NULL;
245 enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
246 return_val_if_nok (error, NULL);
248 MonoClassExt *ext = mono_class_get_ext (enclosing);
249 if (enclosing->nested_classes_inited && ext) {
250 /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
251 for (tmp = ext->nested_classes; tmp; tmp = tmp->next) {
252 res = (MonoClass *)tmp->data;
253 if (strcmp (res->name, name) == 0)
254 return res;
256 } else {
257 /* Don't call mono_class_init as we might've been called by it recursively */
258 int i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, 1);
259 while (i) {
260 guint32 class_nested = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, MONO_NESTED_CLASS_NESTED);
261 guint32 string_offset = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
262 const char *nname = mono_metadata_string_heap (enclosing->image, string_offset);
264 if (strcmp (nname, name) == 0)
265 return mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, error);
267 i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1);
270 g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
271 goto done;
273 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
274 break;
277 if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
278 mono_error_set_bad_image (error, image, "Image with invalid assemblyref token %08x.", idx);
279 return NULL;
282 if (!image->references || !image->references [idx - 1])
283 mono_assembly_load_reference (image, idx - 1);
284 g_assert (image->references [idx - 1]);
286 /* If the assembly did not load, register this as a type load exception */
287 if (image->references [idx - 1] == REFERENCE_MISSING){
288 MonoAssemblyName aname;
289 char *human_name;
291 mono_assembly_get_assemblyref (image, idx - 1, &aname);
292 human_name = mono_stringify_assembly_name (&aname);
293 mono_error_set_assembly_load_simple (error, human_name, image->assembly ? image->assembly->ref_only : FALSE);
294 return NULL;
297 res = mono_class_from_name_checked (image->references [idx - 1]->image, nspace, name, error);
299 done:
300 /* Generic case, should be avoided for when a better error is possible. */
301 if (!res && mono_error_ok (error)) {
302 char *name = mono_class_name_from_token (image, type_token);
303 char *assembly = mono_assembly_name_from_token (image, type_token);
304 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
306 return res;
310 static void *
311 mono_image_memdup (MonoImage *image, void *data, guint size)
313 void *res = mono_image_alloc (image, size);
314 memcpy (res, data, size);
315 return res;
318 /* Copy everything mono_metadata_free_array free. */
319 MonoArrayType *
320 mono_dup_array_type (MonoImage *image, MonoArrayType *a)
322 if (image) {
323 a = (MonoArrayType *)mono_image_memdup (image, a, sizeof (MonoArrayType));
324 if (a->sizes)
325 a->sizes = (int *)mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
326 if (a->lobounds)
327 a->lobounds = (int *)mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
328 } else {
329 a = (MonoArrayType *)g_memdup (a, sizeof (MonoArrayType));
330 if (a->sizes)
331 a->sizes = (int *)g_memdup (a->sizes, a->numsizes * sizeof (int));
332 if (a->lobounds)
333 a->lobounds = (int *)g_memdup (a->lobounds, a->numlobounds * sizeof (int));
335 return a;
338 /* Copy everything mono_metadata_free_method_signature free. */
339 MonoMethodSignature*
340 mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
342 int i;
344 sig = mono_metadata_signature_dup_full (image, sig);
346 sig->ret = mono_metadata_type_dup (image, sig->ret);
347 for (i = 0; i < sig->param_count; ++i)
348 sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
350 return sig;
353 static void
354 _mono_type_get_assembly_name (MonoClass *klass, GString *str)
356 MonoAssembly *ta = klass->image->assembly;
357 char *name;
359 name = mono_stringify_assembly_name (&ta->aname);
360 g_string_append_printf (str, ", %s", name);
361 g_free (name);
364 static inline void
365 mono_type_name_check_byref (MonoType *type, GString *str)
367 if (type->byref)
368 g_string_append_c (str, '&');
372 * mono_identifier_escape_type_name_chars:
373 * @str: a destination string
374 * @identifier: an IDENTIFIER in internal form
376 * Returns: str.
378 * The displayed form of the identifier is appended to str.
380 * The displayed form of an identifier has the characters ,+&*[]\
381 * that have special meaning in type names escaped with a preceeding
382 * backslash (\) character.
384 static GString*
385 mono_identifier_escape_type_name_chars (GString* str, const char* identifier)
387 if (!identifier)
388 return str;
390 size_t n = str->len;
391 // reserve space for common case: there will be no escaped characters.
392 g_string_set_size(str, n + strlen(identifier));
393 g_string_set_size(str, n);
395 for (const char* s = identifier; *s != 0 ; s++) {
396 switch (*s) {
397 case ',':
398 case '+':
399 case '&':
400 case '*':
401 case '[':
402 case ']':
403 case '\\':
404 g_string_append_c (str, '\\');
405 g_string_append_c (str, *s);
406 break;
407 default:
408 g_string_append_c (str, *s);
409 break;
412 return str;
415 static void
416 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
417 MonoTypeNameFormat format)
419 MonoClass *klass;
421 switch (type->type) {
422 case MONO_TYPE_ARRAY: {
423 int i, rank = type->data.array->rank;
424 MonoTypeNameFormat nested_format;
426 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
427 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
429 mono_type_get_name_recurse (
430 &type->data.array->eklass->byval_arg, str, FALSE, nested_format);
431 g_string_append_c (str, '[');
432 if (rank == 1)
433 g_string_append_c (str, '*');
434 for (i = 1; i < rank; i++)
435 g_string_append_c (str, ',');
436 g_string_append_c (str, ']');
438 mono_type_name_check_byref (type, str);
440 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
441 _mono_type_get_assembly_name (type->data.array->eklass, str);
442 break;
444 case MONO_TYPE_SZARRAY: {
445 MonoTypeNameFormat nested_format;
447 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
448 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
450 mono_type_get_name_recurse (
451 &type->data.klass->byval_arg, str, FALSE, nested_format);
452 g_string_append (str, "[]");
454 mono_type_name_check_byref (type, str);
456 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
457 _mono_type_get_assembly_name (type->data.klass, str);
458 break;
460 case MONO_TYPE_PTR: {
461 MonoTypeNameFormat nested_format;
463 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
464 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
466 mono_type_get_name_recurse (
467 type->data.type, str, FALSE, nested_format);
468 g_string_append_c (str, '*');
470 mono_type_name_check_byref (type, str);
472 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
473 _mono_type_get_assembly_name (mono_class_from_mono_type (type->data.type), str);
474 break;
476 case MONO_TYPE_VAR:
477 case MONO_TYPE_MVAR:
478 if (!mono_generic_param_info (type->data.generic_param))
479 g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
480 else
481 g_string_append (str, mono_generic_param_info (type->data.generic_param)->name);
483 mono_type_name_check_byref (type, str);
485 break;
486 default:
487 klass = mono_class_from_mono_type (type);
488 if (klass->nested_in) {
489 mono_type_get_name_recurse (
490 &klass->nested_in->byval_arg, str, TRUE, format);
491 if (format == MONO_TYPE_NAME_FORMAT_IL)
492 g_string_append_c (str, '.');
493 else
494 g_string_append_c (str, '+');
495 } else if (*klass->name_space) {
496 if (format == MONO_TYPE_NAME_FORMAT_IL)
497 g_string_append (str, klass->name_space);
498 else
499 mono_identifier_escape_type_name_chars (str, klass->name_space);
500 g_string_append_c (str, '.');
502 if (format == MONO_TYPE_NAME_FORMAT_IL) {
503 char *s = strchr (klass->name, '`');
504 int len = s ? s - klass->name : strlen (klass->name);
505 g_string_append_len (str, klass->name, len);
506 } else {
507 mono_identifier_escape_type_name_chars (str, klass->name);
509 if (is_recursed)
510 break;
511 if (mono_class_is_ginst (klass)) {
512 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
513 MonoGenericInst *inst = gclass->context.class_inst;
514 MonoTypeNameFormat nested_format;
515 int i;
517 nested_format = format == MONO_TYPE_NAME_FORMAT_FULL_NAME ?
518 MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format;
520 if (format == MONO_TYPE_NAME_FORMAT_IL)
521 g_string_append_c (str, '<');
522 else
523 g_string_append_c (str, '[');
524 for (i = 0; i < inst->type_argc; i++) {
525 MonoType *t = inst->type_argv [i];
527 if (i)
528 g_string_append_c (str, ',');
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, '[');
532 mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
533 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
534 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
535 g_string_append_c (str, ']');
537 if (format == MONO_TYPE_NAME_FORMAT_IL)
538 g_string_append_c (str, '>');
539 else
540 g_string_append_c (str, ']');
541 } else if (mono_class_is_gtd (klass) &&
542 (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
543 (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
544 int i;
546 if (format == MONO_TYPE_NAME_FORMAT_IL)
547 g_string_append_c (str, '<');
548 else
549 g_string_append_c (str, '[');
550 for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) {
551 if (i)
552 g_string_append_c (str, ',');
553 g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name);
555 if (format == MONO_TYPE_NAME_FORMAT_IL)
556 g_string_append_c (str, '>');
557 else
558 g_string_append_c (str, ']');
561 mono_type_name_check_byref (type, str);
563 if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
564 (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
565 _mono_type_get_assembly_name (klass, str);
566 break;
571 * mono_type_get_name_full:
572 * @type: a type
573 * @format: the format for the return string.
576 * Returns: The string representation in a number of formats:
578 * if format is MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
579 * returned in the formatrequired by System.Reflection, this is the
580 * inverse of mono_reflection_parse_type ().
582 * if format is MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
583 * be used by the IL assembler.
585 * if format is MONO_TYPE_NAME_FORMAT_FULL_NAME
587 * if format is MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
589 char*
590 mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
592 GString* result;
594 result = g_string_new ("");
596 mono_type_get_name_recurse (type, result, FALSE, format);
598 return g_string_free (result, FALSE);
602 * mono_type_get_full_name:
603 * @class: a class
605 * Returns: The string representation for type as required by System.Reflection.
606 * The inverse of mono_reflection_parse_type ().
608 char *
609 mono_type_get_full_name (MonoClass *klass)
611 return mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_REFLECTION);
615 * mono_type_get_name:
616 * @type: a type
618 * Returns: The string representation for type as it would be represented in IL code.
620 char*
621 mono_type_get_name (MonoType *type)
623 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
627 * mono_type_get_underlying_type:
628 * @type: a type
630 * Returns: The MonoType for the underlying integer type if @type
631 * is an enum and byref is false, otherwise the type itself.
633 MonoType*
634 mono_type_get_underlying_type (MonoType *type)
636 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype && !type->byref)
637 return mono_class_enum_basetype (type->data.klass);
638 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype && !type->byref)
639 return mono_class_enum_basetype (type->data.generic_class->container_class);
640 return type;
644 * mono_class_is_open_constructed_type:
645 * @type: a type
647 * Returns: TRUE if type represents a generics open constructed type.
648 * IOW, not all type parameters required for the instantiation have
649 * been provided or it's a generic type definition.
651 * An open constructed type means it's a non realizable type. Not to
652 * be mixed up with an abstract type - we can't cast or dispatch to
653 * an open type, for example.
655 gboolean
656 mono_class_is_open_constructed_type (MonoType *t)
658 switch (t->type) {
659 case MONO_TYPE_VAR:
660 case MONO_TYPE_MVAR:
661 return TRUE;
662 case MONO_TYPE_SZARRAY:
663 return mono_class_is_open_constructed_type (&t->data.klass->byval_arg);
664 case MONO_TYPE_ARRAY:
665 return mono_class_is_open_constructed_type (&t->data.array->eklass->byval_arg);
666 case MONO_TYPE_PTR:
667 return mono_class_is_open_constructed_type (t->data.type);
668 case MONO_TYPE_GENERICINST:
669 return t->data.generic_class->context.class_inst->is_open;
670 case MONO_TYPE_CLASS:
671 case MONO_TYPE_VALUETYPE:
672 return mono_class_is_gtd (t->data.klass);
673 default:
674 return FALSE;
679 This is a simple function to catch the most common bad instances of generic types.
680 Specially those that might lead to further failures in the runtime.
682 static gboolean
683 is_valid_generic_argument (MonoType *type)
685 switch (type->type) {
686 case MONO_TYPE_VOID:
687 //case MONO_TYPE_TYPEDBYREF:
688 return FALSE;
689 default:
690 return TRUE;
694 static MonoType*
695 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
697 mono_error_init (error);
699 switch (type->type) {
700 case MONO_TYPE_MVAR: {
701 MonoType *nt;
702 int num = mono_type_get_generic_param_num (type);
703 MonoGenericInst *inst = context->method_inst;
704 if (!inst)
705 return NULL;
706 if (num >= inst->type_argc) {
707 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
708 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
709 num, info ? info->name : "", inst->type_argc);
710 return NULL;
713 if (!is_valid_generic_argument (inst->type_argv [num])) {
714 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
715 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
716 num, info ? info->name : "", inst->type_argv [num]->type);
717 return NULL;
720 * Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
721 * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
722 * ->byref and ->attrs from @type are propagated to the returned type.
724 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
725 nt->byref = type->byref;
726 nt->attrs = type->attrs;
727 return nt;
729 case MONO_TYPE_VAR: {
730 MonoType *nt;
731 int num = mono_type_get_generic_param_num (type);
732 MonoGenericInst *inst = context->class_inst;
733 if (!inst)
734 return NULL;
735 if (num >= inst->type_argc) {
736 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
737 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
738 num, info ? info->name : "", inst->type_argc);
739 return NULL;
741 if (!is_valid_generic_argument (inst->type_argv [num])) {
742 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
743 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
744 num, info ? info->name : "", inst->type_argv [num]->type);
745 return NULL;
747 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
748 nt->byref = type->byref;
749 nt->attrs = type->attrs;
750 return nt;
752 case MONO_TYPE_SZARRAY: {
753 MonoClass *eclass = type->data.klass;
754 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
755 if (!inflated || !mono_error_ok (error))
756 return NULL;
757 nt = mono_metadata_type_dup (image, type);
758 nt->data.klass = mono_class_from_mono_type (inflated);
759 mono_metadata_free_type (inflated);
760 return nt;
762 case MONO_TYPE_ARRAY: {
763 MonoClass *eclass = type->data.array->eklass;
764 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
765 if (!inflated || !mono_error_ok (error))
766 return NULL;
767 nt = mono_metadata_type_dup (image, type);
768 nt->data.array->eklass = mono_class_from_mono_type (inflated);
769 mono_metadata_free_type (inflated);
770 return nt;
772 case MONO_TYPE_GENERICINST: {
773 MonoGenericClass *gclass = type->data.generic_class;
774 MonoGenericInst *inst;
775 MonoType *nt;
776 if (!gclass->context.class_inst->is_open)
777 return NULL;
779 inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
780 return_val_if_nok (error, NULL);
782 if (inst != gclass->context.class_inst)
783 gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
785 if (gclass == type->data.generic_class)
786 return NULL;
788 nt = mono_metadata_type_dup (image, type);
789 nt->data.generic_class = gclass;
790 return nt;
792 case MONO_TYPE_CLASS:
793 case MONO_TYPE_VALUETYPE: {
794 MonoClass *klass = type->data.klass;
795 MonoGenericContainer *container = mono_class_try_get_generic_container (klass);
796 MonoGenericInst *inst;
797 MonoGenericClass *gclass = NULL;
798 MonoType *nt;
800 if (!container)
801 return NULL;
803 /* We can't use context->class_inst directly, since it can have more elements */
804 inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
805 return_val_if_nok (error, NULL);
807 if (inst == container->context.class_inst)
808 return NULL;
810 gclass = mono_metadata_lookup_generic_class (klass, inst, image_is_dynamic (klass->image));
812 nt = mono_metadata_type_dup (image, type);
813 nt->type = MONO_TYPE_GENERICINST;
814 nt->data.generic_class = gclass;
815 return nt;
817 default:
818 return NULL;
820 return NULL;
823 MonoGenericContext *
824 mono_generic_class_get_context (MonoGenericClass *gclass)
826 return &gclass->context;
829 MonoGenericContext *
830 mono_class_get_context (MonoClass *klass)
832 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
833 return gklass ? mono_generic_class_get_context (gklass) : NULL;
837 * mono_class_inflate_generic_type_with_mempool:
838 * @mempool: a mempool
839 * @type: a type
840 * @context: a generics context
841 * @error: error context
843 * The same as mono_class_inflate_generic_type, but allocates the MonoType
844 * from mempool if it is non-NULL. If it is NULL, the MonoType is
845 * allocated on the heap and is owned by the caller.
846 * The returned type can potentially be the same as TYPE, so it should not be
847 * modified by the caller, and it should be freed using mono_metadata_free_type ().
849 MonoType*
850 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
852 MonoType *inflated = NULL;
853 mono_error_init (error);
855 if (context)
856 inflated = inflate_generic_type (image, type, context, error);
857 return_val_if_nok (error, NULL);
859 if (!inflated) {
860 MonoType *shared = mono_metadata_get_shared_type (type);
862 if (shared) {
863 return shared;
864 } else {
865 return mono_metadata_type_dup (image, type);
869 mono_stats.inflated_type_count++;
870 return inflated;
874 * mono_class_inflate_generic_type:
875 * @type: a type
876 * @context: a generics context
878 * If @type is a generic type and @context is not NULL, instantiate it using the
879 * generics context @context.
881 * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
882 * on the heap and is owned by the caller. Returns NULL on error.
884 * @deprecated Please use mono_class_inflate_generic_type_checked instead
886 MonoType*
887 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
889 MonoError error;
890 MonoType *result;
891 result = mono_class_inflate_generic_type_checked (type, context, &error);
892 mono_error_cleanup (&error);
893 return result;
897 * mono_class_inflate_generic_type:
898 * @type: a type
899 * @context: a generics context
900 * @error: error context to use
902 * If @type is a generic type and @context is not NULL, instantiate it using the
903 * generics context @context.
905 * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
906 * on the heap and is owned by the caller.
908 MonoType*
909 mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
911 return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
915 * mono_class_inflate_generic_type_no_copy:
917 * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
918 * was done.
920 static MonoType*
921 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
923 MonoType *inflated = NULL;
925 mono_error_init (error);
926 if (context) {
927 inflated = inflate_generic_type (image, type, context, error);
928 return_val_if_nok (error, NULL);
931 if (!inflated)
932 return type;
934 mono_stats.inflated_type_count++;
935 return inflated;
939 * mono_class_inflate_generic_class:
941 * Inflate the class @gklass with @context. Set @error on failure.
943 MonoClass*
944 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
946 MonoClass *res;
947 MonoType *inflated;
949 inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, error);
950 return_val_if_nok (error, NULL);
952 res = mono_class_from_mono_type (inflated);
953 mono_metadata_free_type (inflated);
955 return res;
958 static MonoGenericContext
959 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
961 MonoGenericInst *class_inst = NULL;
962 MonoGenericInst *method_inst = NULL;
963 MonoGenericContext res = { NULL, NULL };
965 mono_error_init (error);
967 if (context->class_inst) {
968 class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
969 if (!mono_error_ok (error))
970 goto fail;
973 if (context->method_inst) {
974 method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with, error);
975 if (!mono_error_ok (error))
976 goto fail;
979 res.class_inst = class_inst;
980 res.method_inst = method_inst;
981 fail:
982 return res;
986 * mono_class_inflate_generic_method:
987 * @method: a generic method
988 * @context: a generics context
990 * Instantiate the generic method @method using the generics context @context.
992 * Returns: The new instantiated method
994 MonoMethod *
995 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
997 return mono_class_inflate_generic_method_full (method, NULL, context);
1000 MonoMethod *
1001 mono_class_inflate_generic_method_checked (MonoMethod *method, MonoGenericContext *context, MonoError *error)
1003 return mono_class_inflate_generic_method_full_checked (method, NULL, context, error);
1007 * mono_class_inflate_generic_method_full:
1009 * Instantiate method @method with the generic context @context.
1010 * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
1011 * Use mono_method_signature () and mono_method_get_header () to get the correct values.
1013 MonoMethod*
1014 mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context)
1016 MonoError error;
1017 MonoMethod *res = mono_class_inflate_generic_method_full_checked (method, klass_hint, context, &error);
1018 if (!mono_error_ok (&error))
1019 /*FIXME do proper error handling - on this case, kill this function. */
1020 g_error ("Could not inflate generic method due to %s", mono_error_get_message (&error));
1022 return res;
1026 * mono_class_inflate_generic_method_full_checked:
1027 * Same as mono_class_inflate_generic_method_full but return failure using @error.
1029 MonoMethod*
1030 mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error)
1032 MonoMethod *result;
1033 MonoMethodInflated *iresult, *cached;
1034 MonoMethodSignature *sig;
1035 MonoGenericContext tmp_context;
1037 mono_error_init (error);
1039 /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
1040 while (method->is_inflated) {
1041 MonoGenericContext *method_context = mono_method_get_context (method);
1042 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1044 tmp_context = inflate_generic_context (method_context, context, error);
1045 return_val_if_nok (error, NULL);
1047 context = &tmp_context;
1049 if (mono_metadata_generic_context_equal (method_context, context))
1050 return method;
1052 method = imethod->declaring;
1056 * A method only needs to be inflated if the context has argument for which it is
1057 * parametric. Eg:
1059 * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
1060 * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
1063 if (!((method->is_generic && context->method_inst) ||
1064 (mono_class_is_gtd (method->klass) && context->class_inst)))
1065 return method;
1067 iresult = g_new0 (MonoMethodInflated, 1);
1068 iresult->context = *context;
1069 iresult->declaring = method;
1071 if (!context->method_inst && method->is_generic)
1072 iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
1074 if (!context->class_inst) {
1075 g_assert (!mono_class_is_ginst (iresult->declaring->klass));
1076 if (mono_class_is_gtd (iresult->declaring->klass))
1077 iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst;
1079 /* This can happen with some callers like mono_object_get_virtual_method () */
1080 if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass))
1081 iresult->context.class_inst = NULL;
1083 MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
1085 // check cache
1086 mono_image_set_lock (set);
1087 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1088 mono_image_set_unlock (set);
1090 if (cached) {
1091 g_free (iresult);
1092 return (MonoMethod*)cached;
1095 mono_stats.inflated_method_count++;
1097 inflated_methods_size += sizeof (MonoMethodInflated);
1099 sig = mono_method_signature (method);
1100 if (!sig) {
1101 char *name = mono_type_get_full_name (method->klass);
1102 mono_error_set_bad_image (error, method->klass->image, "Could not resolve signature of method %s:%s", name, method->name);
1103 g_free (name);
1104 goto fail;
1107 if (sig->pinvoke) {
1108 memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
1109 } else {
1110 memcpy (&iresult->method.method, method, sizeof (MonoMethod));
1113 result = (MonoMethod *) iresult;
1114 result->is_inflated = TRUE;
1115 result->is_generic = FALSE;
1116 result->sre_method = FALSE;
1117 result->signature = NULL;
1119 if (method->wrapper_type) {
1120 MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
1121 MonoMethodWrapper *resw = (MonoMethodWrapper*)result;
1122 int len = GPOINTER_TO_INT (((void**)mw->method_data) [0]);
1124 resw->method_data = (void **)g_malloc (sizeof (gpointer) * (len + 1));
1125 memcpy (resw->method_data, mw->method_data, sizeof (gpointer) * (len + 1));
1128 if (iresult->context.method_inst) {
1129 /* Set the generic_container of the result to the generic_container of method */
1130 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
1132 if (generic_container && iresult->context.method_inst == generic_container->context.method_inst) {
1133 result->is_generic = 1;
1134 mono_method_set_generic_container (result, generic_container);
1138 if (klass_hint) {
1139 MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint);
1140 if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst))
1141 klass_hint = NULL;
1144 if (mono_class_is_gtd (method->klass))
1145 result->klass = klass_hint;
1147 if (!result->klass) {
1148 MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context, error);
1149 if (!mono_error_ok (error))
1150 goto fail;
1152 result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
1153 if (inflated)
1154 mono_metadata_free_type (inflated);
1158 * FIXME: This should hold, but it doesn't:
1160 * if (result->is_inflated && mono_method_get_context (result)->method_inst &&
1161 * mono_method_get_context (result)->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)result)->declaring)->context.method_inst) {
1162 * g_assert (result->is_generic);
1165 * Fixing this here causes other things to break, hence a very
1166 * ugly hack in mini-trampolines.c - see
1167 * is_generic_method_definition().
1170 // check cache
1171 mono_image_set_lock (set);
1172 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1173 if (!cached) {
1174 g_hash_table_insert (set->gmethod_cache, iresult, iresult);
1175 iresult->owner = set;
1176 cached = iresult;
1178 mono_image_set_unlock (set);
1180 return (MonoMethod*)cached;
1182 fail:
1183 g_free (iresult);
1184 return NULL;
1188 * mono_get_inflated_method:
1190 * Obsolete. We keep it around since it's mentioned in the public API.
1192 MonoMethod*
1193 mono_get_inflated_method (MonoMethod *method)
1195 return method;
1199 * mono_method_get_context_general:
1200 * @method: a method
1201 * @uninflated: handle uninflated methods?
1203 * Returns the generic context of a method or NULL if it doesn't have
1204 * one. For an inflated method that's the context stored in the
1205 * method. Otherwise it's in the method's generic container or in the
1206 * generic container of the method's class.
1208 MonoGenericContext*
1209 mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
1211 if (method->is_inflated) {
1212 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1213 return &imethod->context;
1215 if (!uninflated)
1216 return NULL;
1217 if (method->is_generic)
1218 return &(mono_method_get_generic_container (method)->context);
1219 if (mono_class_is_gtd (method->klass))
1220 return &mono_class_get_generic_container (method->klass)->context;
1221 return NULL;
1225 * mono_method_get_context:
1226 * @method: a method
1228 * Returns the generic context for method if it's inflated, otherwise
1229 * NULL.
1231 MonoGenericContext*
1232 mono_method_get_context (MonoMethod *method)
1234 return mono_method_get_context_general (method, FALSE);
1238 * mono_method_get_generic_container:
1240 * Returns the generic container of METHOD, which should be a generic method definition.
1241 * Returns NULL if METHOD is not a generic method definition.
1242 * LOCKING: Acquires the loader lock.
1244 MonoGenericContainer*
1245 mono_method_get_generic_container (MonoMethod *method)
1247 MonoGenericContainer *container;
1249 if (!method->is_generic)
1250 return NULL;
1252 container = (MonoGenericContainer *)mono_image_property_lookup (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER);
1253 g_assert (container);
1255 return container;
1259 * mono_method_set_generic_container:
1261 * Sets the generic container of METHOD to CONTAINER.
1262 * LOCKING: Acquires the image lock.
1264 void
1265 mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
1267 g_assert (method->is_generic);
1269 mono_image_property_insert (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
1272 /**
1273 * mono_class_find_enum_basetype:
1274 * @class: The enum class
1276 * Determine the basetype of an enum by iterating through its fields. We do this
1277 * in a separate function since it is cheaper than calling mono_class_setup_fields.
1279 static MonoType*
1280 mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
1282 MonoGenericContainer *container = NULL;
1283 MonoImage *m = klass->image;
1284 const int top = mono_class_get_field_count (klass);
1285 int i, first_field_idx;
1287 g_assert (klass->enumtype);
1289 mono_error_init (error);
1291 container = mono_class_try_get_generic_container (klass);
1292 if (mono_class_is_ginst (klass)) {
1293 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1295 container = mono_class_get_generic_container (gklass);
1296 g_assert (container);
1300 * Fetch all the field information.
1302 first_field_idx = mono_class_get_first_field_idx (klass);
1303 for (i = 0; i < top; i++){
1304 const char *sig;
1305 guint32 cols [MONO_FIELD_SIZE];
1306 int idx = first_field_idx + i;
1307 MonoType *ftype;
1309 /* first_field_idx and idx points into the fieldptr table */
1310 mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
1312 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
1313 continue;
1315 if (!mono_verifier_verify_field_signature (klass->image, cols [MONO_FIELD_SIGNATURE], NULL)) {
1316 mono_error_set_bad_image (error, klass->image, "Invalid field signature %x", cols [MONO_FIELD_SIGNATURE]);
1317 goto fail;
1320 sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
1321 mono_metadata_decode_value (sig, &sig);
1322 /* FIELD signature == 0x06 */
1323 if (*sig != 0x06) {
1324 mono_error_set_bad_image (error, klass->image, "Invalid field signature %x, expected 0x6 but got %x", cols [MONO_FIELD_SIGNATURE], *sig);
1325 goto fail;
1328 ftype = mono_metadata_parse_type_checked (m, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
1329 if (!ftype)
1330 goto fail;
1332 if (mono_class_is_ginst (klass)) {
1333 //FIXME do we leak here?
1334 ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error);
1335 if (!mono_error_ok (error))
1336 goto fail;
1337 ftype->attrs = cols [MONO_FIELD_FLAGS];
1340 return ftype;
1342 mono_error_set_type_load_class (error, klass, "Could not find base type");
1344 fail:
1345 return NULL;
1349 * Checks for MonoClass::has_failure without resolving all MonoType's into MonoClass'es
1351 static gboolean
1352 mono_type_has_exceptions (MonoType *type)
1354 switch (type->type) {
1355 case MONO_TYPE_CLASS:
1356 case MONO_TYPE_VALUETYPE:
1357 case MONO_TYPE_SZARRAY:
1358 return mono_class_has_failure (type->data.klass);
1359 case MONO_TYPE_ARRAY:
1360 return mono_class_has_failure (type->data.array->eklass);
1361 case MONO_TYPE_GENERICINST:
1362 return mono_class_has_failure (mono_generic_class_get_class (type->data.generic_class));
1363 default:
1364 return FALSE;
1368 void
1369 mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
1371 g_assert (mono_class_has_failure (klass));
1372 MonoErrorBoxed *box = (MonoErrorBoxed*)mono_class_get_exception_data (klass);
1373 mono_error_set_from_boxed (oerror, box);
1378 * mono_class_alloc:
1380 * Allocate memory for some data belonging to CLASS, either from its image's mempool,
1381 * or from the heap.
1383 gpointer
1384 mono_class_alloc (MonoClass *klass, int size)
1386 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1387 if (gklass)
1388 return mono_image_set_alloc (gklass->owner, size);
1389 else
1390 return mono_image_alloc (klass->image, size);
1393 gpointer
1394 mono_class_alloc0 (MonoClass *klass, int size)
1396 gpointer res;
1398 res = mono_class_alloc (klass, size);
1399 memset (res, 0, size);
1400 return res;
1403 #define mono_class_new0(klass,struct_type, n_structs) \
1404 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
1407 * mono_class_setup_basic_field_info:
1408 * @class: The class to initialize
1410 * Initializes the following fields in MonoClass:
1411 * * klass->fields (only field->parent and field->name)
1412 * * klass->field.count
1413 * * klass->first_field_idx
1414 * LOCKING: Acquires the loader lock
1416 static void
1417 mono_class_setup_basic_field_info (MonoClass *klass)
1419 MonoGenericClass *gklass;
1420 MonoClassField *field;
1421 MonoClassField *fields;
1422 MonoClass *gtd;
1423 MonoImage *image;
1424 int i, top;
1426 if (klass->fields)
1427 return;
1429 gklass = mono_class_try_get_generic_class (klass);
1430 gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
1431 image = klass->image;
1434 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
1436 * This happens when a generic instance of an unfinished generic typebuilder
1437 * is used as an element type for creating an array type. We can't initialize
1438 * the fields of this class using the fields of gklass, since gklass is not
1439 * finished yet, fields could be added to it later.
1441 return;
1444 if (gtd) {
1445 mono_class_setup_basic_field_info (gtd);
1447 mono_loader_lock ();
1448 mono_class_set_field_count (klass, mono_class_get_field_count (gtd));
1449 mono_loader_unlock ();
1452 top = mono_class_get_field_count (klass);
1454 fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
1457 * Fetch all the field information.
1459 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
1460 for (i = 0; i < top; i++) {
1461 field = &fields [i];
1462 field->parent = klass;
1464 if (gtd) {
1465 field->name = mono_field_get_name (&gtd->fields [i]);
1466 } else {
1467 int idx = first_field_idx + i;
1468 /* first_field_idx and idx points into the fieldptr table */
1469 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
1470 /* The name is needed for fieldrefs */
1471 field->name = mono_metadata_string_heap (image, name_idx);
1475 mono_memory_barrier ();
1477 mono_loader_lock ();
1478 if (!klass->fields)
1479 klass->fields = fields;
1480 mono_loader_unlock ();
1484 * mono_class_set_failure_causedby_class:
1485 * @klass: the class that is failing
1486 * @caused_by: the class that caused the failure
1487 * @msg: Why @klass is failing.
1489 * If @caused_by has a failure, sets a TypeLoadException failure on
1490 * @klass with message "@msg, due to: {@caused_by message}".
1492 * Returns: TRUE if a failiure was set, or FALSE if @caused_by doesn't have a failure.
1494 static gboolean
1495 mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg)
1497 if (mono_class_has_failure (caused_by)) {
1498 MonoError cause_error;
1499 mono_error_init (&cause_error);
1500 mono_error_set_for_class_failure (&cause_error, caused_by);
1501 mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (&cause_error));
1502 mono_error_cleanup (&cause_error);
1503 return TRUE;
1504 } else {
1505 return FALSE;
1510 /**
1511 * mono_class_setup_fields:
1512 * @klass: The class to initialize
1514 * Initializes klass->fields, computes class layout and sizes.
1515 * typebuilder_setup_fields () is the corresponding function for dynamic classes.
1516 * Sets the following fields in @klass:
1517 * - all the fields initialized by mono_class_init_sizes ()
1518 * - element_class/cast_class (for enums)
1519 * - field->type/offset for all fields
1520 * - fields_inited
1522 * LOCKING: Acquires the loader lock.
1524 void
1525 mono_class_setup_fields (MonoClass *klass)
1527 MonoError error;
1528 MonoImage *m = klass->image;
1529 int top;
1530 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
1531 int i;
1532 guint32 real_size = 0;
1533 guint32 packing_size = 0;
1534 int instance_size;
1535 gboolean explicit_size;
1536 MonoClassField *field;
1537 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1538 MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
1540 if (klass->fields_inited)
1541 return;
1543 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
1545 * This happens when a generic instance of an unfinished generic typebuilder
1546 * is used as an element type for creating an array type. We can't initialize
1547 * the fields of this class using the fields of gklass, since gklass is not
1548 * finished yet, fields could be added to it later.
1550 return;
1553 mono_class_setup_basic_field_info (klass);
1554 top = mono_class_get_field_count (klass);
1556 if (gtd) {
1557 mono_class_setup_fields (gtd);
1558 if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
1559 return;
1562 instance_size = 0;
1563 if (klass->parent) {
1564 /* For generic instances, klass->parent might not have been initialized */
1565 mono_class_init (klass->parent);
1566 mono_class_setup_fields (klass->parent);
1567 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
1568 return;
1569 instance_size = klass->parent->instance_size;
1570 } else {
1571 instance_size = sizeof (MonoObject);
1574 /* Get the real size */
1575 explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
1576 if (explicit_size)
1577 instance_size += real_size;
1580 * This function can recursively call itself.
1581 * Prevent infinite recursion by using a list in TLS.
1583 GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
1584 if (g_slist_find (init_list, klass))
1585 return;
1586 init_list = g_slist_prepend (init_list, klass);
1587 mono_native_tls_set_value (setup_fields_tls_id, init_list);
1590 * Fetch all the field information.
1592 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
1593 for (i = 0; i < top; i++) {
1594 int idx = first_field_idx + i;
1595 field = &klass->fields [i];
1597 if (!field->type) {
1598 mono_field_resolve_type (field, &error);
1599 if (!mono_error_ok (&error)) {
1600 /*mono_field_resolve_type already failed class*/
1601 mono_error_cleanup (&error);
1602 break;
1604 if (!field->type)
1605 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
1606 g_assert (field->type);
1609 if (mono_field_is_deleted (field))
1610 continue;
1611 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
1612 guint32 uoffset;
1613 mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
1614 int offset = uoffset;
1616 if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1617 mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
1618 break;
1620 if (offset < -1) { /*-1 is used to encode special static fields */
1621 mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
1622 break;
1624 if (mono_class_is_gtd (klass)) {
1625 mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
1626 break;
1629 if (mono_type_has_exceptions (field->type)) {
1630 char *class_name = mono_type_get_full_name (klass);
1631 char *type_name = mono_type_full_name (field->type);
1633 mono_class_set_type_load_failure (klass, "");
1634 g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
1635 g_free (class_name);
1636 g_free (type_name);
1637 break;
1639 /* The def_value of fields is compute lazily during vtable creation */
1642 if (!mono_class_has_failure (klass))
1643 mono_class_layout_fields (klass, instance_size, packing_size, FALSE);
1645 init_list = g_slist_remove (init_list, klass);
1646 mono_native_tls_set_value (setup_fields_tls_id, init_list);
1649 static void
1650 init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
1652 if (cached_info) {
1653 klass->instance_size = cached_info->instance_size;
1654 klass->sizes.class_size = cached_info->class_size;
1655 klass->packing_size = cached_info->packing_size;
1656 klass->min_align = cached_info->min_align;
1657 klass->blittable = cached_info->blittable;
1658 klass->has_references = cached_info->has_references;
1659 klass->has_static_refs = cached_info->has_static_refs;
1660 klass->no_special_static_fields = cached_info->no_special_static_fields;
1662 else {
1663 if (!klass->size_inited)
1664 mono_class_setup_fields (klass);
1669 * mono_class_init_sizes:
1671 * Initializes the size related fields of @klass without loading all field data if possible.
1672 * Sets the following fields in @klass:
1673 * - instance_size
1674 * - sizes.class_size
1675 * - packing_size
1676 * - min_align
1677 * - blittable
1678 * - has_references
1679 * - has_static_refs
1680 * - size_inited
1681 * Can fail the class.
1683 * LOCKING: Acquires the loader lock.
1685 static void
1686 mono_class_init_sizes (MonoClass *klass)
1688 MonoCachedClassInfo cached_info;
1689 gboolean has_cached_info;
1691 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
1693 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
1697 * mono_type_get_basic_type_from_generic:
1698 * @type: a type
1700 * Returns a closed type corresponding to the possibly open type
1701 * passed to it.
1703 MonoType*
1704 mono_type_get_basic_type_from_generic (MonoType *type)
1706 /* When we do generic sharing we let type variables stand for reference/primitive types. */
1707 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) &&
1708 (!type->data.generic_param->gshared_constraint || type->data.generic_param->gshared_constraint->type == MONO_TYPE_OBJECT))
1709 return &mono_defaults.object_class->byval_arg;
1710 return type;
1713 static gboolean
1714 class_has_references (MonoClass *klass)
1716 mono_class_init_sizes (klass);
1719 * has_references is not set if this is called recursively, but this is not a problem since this is only used
1720 * during field layout, and instance fields are initialized before static fields, and instance fields can't
1721 * embed themselves.
1723 return klass->has_references;
1726 static gboolean
1727 type_has_references (MonoClass *klass, MonoType *ftype)
1729 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && class_has_references (mono_class_from_mono_type (ftype)))))
1730 return TRUE;
1731 if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
1732 MonoGenericParam *gparam = ftype->data.generic_param;
1734 if (gparam->gshared_constraint)
1735 return class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
1737 return FALSE;
1741 * mono_class_layout_fields:
1742 * @class: a class
1743 * @base_instance_size: base instance size
1744 * @packing_size:
1746 * This contains the common code for computing the layout of classes and sizes.
1747 * This should only be called from mono_class_setup_fields () and
1748 * typebuilder_setup_fields ().
1750 * LOCKING: Acquires the loader lock
1752 void
1753 mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, gboolean sre)
1755 int i;
1756 const int top = mono_class_get_field_count (klass);
1757 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
1758 guint32 pass, passes, real_size;
1759 gboolean gc_aware_layout = FALSE;
1760 gboolean has_static_fields = FALSE;
1761 gboolean has_references = FALSE;
1762 gboolean has_static_refs = FALSE;
1763 MonoClassField *field;
1764 gboolean blittable;
1765 int instance_size = base_instance_size;
1766 int class_size, min_align;
1767 int *field_offsets;
1770 * We want to avoid doing complicated work inside locks, so we compute all the required
1771 * information and write it to @klass inside a lock.
1773 if (klass->fields_inited)
1774 return;
1776 if ((packing_size & 0xffffff00) != 0) {
1777 mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
1778 return;
1781 if (klass->parent) {
1782 min_align = klass->parent->min_align;
1783 /* we use | since it may have been set already */
1784 has_references = klass->has_references | klass->parent->has_references;
1785 } else {
1786 min_align = 1;
1788 /* We can't really enable 16 bytes alignment until the GC supports it.
1789 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
1790 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
1791 Bug #506144 is an example of this issue.
1793 if (klass->simd_type)
1794 min_align = 16;
1798 * When we do generic sharing we need to have layout
1799 * information for open generic classes (either with a generic
1800 * context containing type variables or with a generic
1801 * container), so we don't return in that case anymore.
1804 if (klass->enumtype) {
1805 for (i = 0; i < top; i++) {
1806 field = &klass->fields [i];
1807 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1808 klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
1809 break;
1813 if (!mono_class_enum_basetype (klass)) {
1814 mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
1815 return;
1820 * Enable GC aware auto layout: in this mode, reference
1821 * fields are grouped together inside objects, increasing collector
1822 * performance.
1823 * Requires that all classes whose layout is known to native code be annotated
1824 * with [StructLayout (LayoutKind.Sequential)]
1825 * Value types have gc_aware_layout disabled by default, as per
1826 * what the default is for other runtimes.
1828 /* corlib is missing [StructLayout] directives in many places */
1829 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
1830 if (!klass->valuetype)
1831 gc_aware_layout = TRUE;
1834 /* Compute klass->blittable */
1835 blittable = TRUE;
1836 if (klass->parent)
1837 blittable = klass->parent->blittable;
1838 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
1839 blittable = FALSE;
1840 for (i = 0; i < top; i++) {
1841 field = &klass->fields [i];
1843 if (mono_field_is_deleted (field))
1844 continue;
1845 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1846 continue;
1847 if (blittable) {
1848 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
1849 blittable = FALSE;
1850 } else {
1851 MonoClass *field_class = mono_class_from_mono_type (field->type);
1852 if (field_class) {
1853 mono_class_setup_fields (field_class);
1854 if (mono_class_has_failure (field_class)) {
1855 MonoError field_error;
1856 mono_error_init (&field_error);
1857 mono_error_set_for_class_failure (&field_error, field_class);
1858 mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (&field_error));
1859 mono_error_cleanup (&field_error);
1860 break;
1863 if (!field_class || !field_class->blittable)
1864 blittable = FALSE;
1867 if (klass->enumtype)
1868 blittable = klass->element_class->blittable;
1870 if (mono_class_has_failure (klass))
1871 return;
1872 if (klass == mono_defaults.string_class)
1873 blittable = FALSE;
1875 /* Compute klass->has_references */
1877 * Process non-static fields first, since static fields might recursively
1878 * refer to the class itself.
1880 for (i = 0; i < top; i++) {
1881 MonoType *ftype;
1883 field = &klass->fields [i];
1885 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1886 ftype = mono_type_get_underlying_type (field->type);
1887 ftype = mono_type_get_basic_type_from_generic (ftype);
1888 if (type_has_references (klass, ftype))
1889 has_references = TRUE;
1894 * Compute field layout and total size (not considering static fields)
1896 field_offsets = g_new0 (int, top);
1897 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
1898 switch (layout) {
1899 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
1900 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
1901 if (gc_aware_layout)
1902 passes = 2;
1903 else
1904 passes = 1;
1906 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
1907 passes = 1;
1909 if (klass->parent) {
1910 mono_class_setup_fields (klass->parent);
1911 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
1912 return;
1913 real_size = klass->parent->instance_size;
1914 } else {
1915 real_size = sizeof (MonoObject);
1918 for (pass = 0; pass < passes; ++pass) {
1919 for (i = 0; i < top; i++){
1920 gint32 align;
1921 guint32 size;
1922 MonoType *ftype;
1924 field = &klass->fields [i];
1926 if (mono_field_is_deleted (field))
1927 continue;
1928 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1929 continue;
1931 ftype = mono_type_get_underlying_type (field->type);
1932 ftype = mono_type_get_basic_type_from_generic (ftype);
1933 if (gc_aware_layout) {
1934 if (type_has_references (klass, ftype)) {
1935 if (pass == 1)
1936 continue;
1937 } else {
1938 if (pass == 0)
1939 continue;
1943 if ((top == 1) && (instance_size == sizeof (MonoObject)) &&
1944 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
1945 /* This field is a hack inserted by MCS to empty structures */
1946 continue;
1949 size = mono_type_size (field->type, &align);
1951 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
1952 align = packing_size ? MIN (packing_size, align): align;
1953 /* if the field has managed references, we need to force-align it
1954 * see bug #77788
1956 if (type_has_references (klass, ftype))
1957 align = MAX (align, sizeof (gpointer));
1959 min_align = MAX (align, min_align);
1960 field_offsets [i] = real_size;
1961 if (align) {
1962 field_offsets [i] += align - 1;
1963 field_offsets [i] &= ~(align - 1);
1965 /*TypeBuilders produce all sort of weird things*/
1966 g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
1967 real_size = field_offsets [i] + size;
1970 instance_size = MAX (real_size, instance_size);
1972 if (instance_size & (min_align - 1)) {
1973 instance_size += min_align - 1;
1974 instance_size &= ~(min_align - 1);
1977 break;
1978 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
1979 guint8 *ref_bitmap;
1981 real_size = 0;
1982 for (i = 0; i < top; i++) {
1983 gint32 align;
1984 guint32 size;
1985 MonoType *ftype;
1987 field = &klass->fields [i];
1990 * There must be info about all the fields in a type if it
1991 * uses explicit layout.
1993 if (mono_field_is_deleted (field))
1994 continue;
1995 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1996 continue;
1998 size = mono_type_size (field->type, &align);
1999 align = packing_size ? MIN (packing_size, align): align;
2000 min_align = MAX (align, min_align);
2002 if (sre) {
2003 /* Already set by typebuilder_setup_fields () */
2004 field_offsets [i] = field->offset + sizeof (MonoObject);
2005 } else {
2006 int idx = first_field_idx + i;
2007 guint32 offset;
2008 mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
2009 field_offsets [i] = offset + sizeof (MonoObject);
2011 ftype = mono_type_get_underlying_type (field->type);
2012 ftype = mono_type_get_basic_type_from_generic (ftype);
2013 if (type_has_references (klass, ftype)) {
2014 if (field_offsets [i] % sizeof (gpointer)) {
2015 mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
2020 * Calc max size.
2022 real_size = MAX (real_size, size + field_offsets [i]);
2025 if (klass->has_references) {
2026 ref_bitmap = g_new0 (guint8, real_size / sizeof (gpointer));
2028 /* Check for overlapping reference and non-reference fields */
2029 for (i = 0; i < top; i++) {
2030 MonoType *ftype;
2032 field = &klass->fields [i];
2034 if (mono_field_is_deleted (field))
2035 continue;
2036 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2037 continue;
2038 ftype = mono_type_get_underlying_type (field->type);
2039 if (MONO_TYPE_IS_REFERENCE (ftype))
2040 ref_bitmap [field_offsets [i] / sizeof (gpointer)] = 1;
2042 for (i = 0; i < top; i++) {
2043 field = &klass->fields [i];
2045 if (mono_field_is_deleted (field))
2046 continue;
2047 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2048 continue;
2050 // FIXME: Too much code does this
2051 #if 0
2052 if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / sizeof (gpointer)]) {
2053 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]);
2055 #endif
2057 g_free (ref_bitmap);
2060 instance_size = MAX (real_size, instance_size);
2061 if (instance_size & (min_align - 1)) {
2062 instance_size += min_align - 1;
2063 instance_size &= ~(min_align - 1);
2065 break;
2069 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
2071 * This leads to all kinds of problems with nested structs, so only
2072 * enable it when a MONO_DEBUG property is set.
2074 * For small structs, set min_align to at least the struct size to improve
2075 * performance, and since the JIT memset/memcpy code assumes this and generates
2076 * unaligned accesses otherwise. See #78990 for a testcase.
2078 if (mono_align_small_structs && top) {
2079 if (instance_size <= sizeof (MonoObject) + sizeof (gpointer))
2080 min_align = MAX (min_align, instance_size - sizeof (MonoObject));
2084 if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
2085 instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
2086 else if (klass->byval_arg.type == MONO_TYPE_PTR)
2087 instance_size = sizeof (MonoObject) + sizeof (gpointer);
2089 /* Publish the data */
2090 mono_loader_lock ();
2091 if (klass->instance_size && !klass->image->dynamic) {
2092 /* Might be already set using cached info */
2093 g_assert (klass->instance_size == instance_size);
2094 } else {
2095 klass->instance_size = instance_size;
2097 klass->blittable = blittable;
2098 klass->has_references = has_references;
2099 klass->packing_size = packing_size;
2100 klass->min_align = min_align;
2101 for (i = 0; i < top; ++i) {
2102 field = &klass->fields [i];
2103 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2104 klass->fields [i].offset = field_offsets [i];
2107 mono_memory_barrier ();
2108 klass->size_inited = 1;
2109 mono_loader_unlock ();
2112 * Compute static field layout and size
2113 * Static fields can reference the class itself, so this has to be
2114 * done after instance_size etc. are initialized.
2116 class_size = 0;
2117 for (i = 0; i < top; i++) {
2118 gint32 align;
2119 guint32 size;
2121 field = &klass->fields [i];
2123 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
2124 continue;
2125 if (mono_field_is_deleted (field))
2126 continue;
2128 if (mono_type_has_exceptions (field->type)) {
2129 mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
2130 break;
2133 has_static_fields = TRUE;
2135 size = mono_type_size (field->type, &align);
2136 field_offsets [i] = class_size;
2137 /*align is always non-zero here*/
2138 field_offsets [i] += align - 1;
2139 field_offsets [i] &= ~(align - 1);
2140 class_size = field_offsets [i] + size;
2143 if (has_static_fields && class_size == 0)
2144 /* Simplify code which depends on class_size != 0 if the class has static fields */
2145 class_size = 8;
2147 /* Compute klass->has_static_refs */
2148 has_static_refs = FALSE;
2149 for (i = 0; i < top; i++) {
2150 MonoType *ftype;
2152 field = &klass->fields [i];
2154 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2155 ftype = mono_type_get_underlying_type (field->type);
2156 ftype = mono_type_get_basic_type_from_generic (ftype);
2157 if (type_has_references (klass, ftype))
2158 has_static_refs = TRUE;
2162 /*valuetypes can't be neither bigger than 1Mb or empty. */
2163 if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
2164 mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
2166 /* Publish the data */
2167 mono_loader_lock ();
2168 if (!klass->rank)
2169 klass->sizes.class_size = class_size;
2170 klass->has_static_refs = has_static_refs;
2171 for (i = 0; i < top; ++i) {
2172 field = &klass->fields [i];
2174 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2175 field->offset = field_offsets [i];
2178 mono_memory_barrier ();
2179 klass->fields_inited = 1;
2180 mono_loader_unlock ();
2182 g_free (field_offsets);
2185 static MonoMethod*
2186 create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *sig)
2188 MonoMethod *method;
2190 method = (MonoMethod *) mono_image_alloc0 (klass->image, sizeof (MonoMethodPInvoke));
2191 method->klass = klass;
2192 method->flags = METHOD_ATTRIBUTE_PUBLIC;
2193 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
2194 method->signature = sig;
2195 method->name = name;
2196 method->slot = -1;
2197 /* .ctor */
2198 if (name [0] == '.') {
2199 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
2200 } else {
2201 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
2203 return method;
2207 * mono_class_setup_methods:
2208 * @class: a class
2210 * Initializes the 'methods' array in CLASS.
2211 * Calling this method should be avoided if possible since it allocates a lot
2212 * of long-living MonoMethod structures.
2213 * Methods belonging to an interface are assigned a sequential slot starting
2214 * from 0.
2216 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
2218 void
2219 mono_class_setup_methods (MonoClass *klass)
2221 int i, count;
2222 MonoMethod **methods;
2224 if (klass->methods)
2225 return;
2227 if (mono_class_is_ginst (klass)) {
2228 MonoError error;
2229 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2231 mono_class_init (gklass);
2232 if (!mono_class_has_failure (gklass))
2233 mono_class_setup_methods (gklass);
2234 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2235 return;
2237 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
2238 count = mono_class_get_method_count (gklass);
2239 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1));
2241 for (i = 0; i < count; i++) {
2242 methods [i] = mono_class_inflate_generic_method_full_checked (
2243 gklass->methods [i], klass, mono_class_get_context (klass), &error);
2244 if (!mono_error_ok (&error)) {
2245 char *method = mono_method_full_name (gklass->methods [i], TRUE);
2246 mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (&error));
2248 g_free (method);
2249 mono_error_cleanup (&error);
2250 return;
2253 } else if (klass->rank) {
2254 MonoError error;
2255 MonoMethod *amethod;
2256 MonoMethodSignature *sig;
2257 int count_generic = 0, first_generic = 0;
2258 int method_num = 0;
2259 gboolean jagged_ctor = FALSE;
2261 count = 3 + (klass->rank > 1? 2: 1);
2263 mono_class_setup_interfaces (klass, &error);
2264 g_assert (mono_error_ok (&error)); /*FIXME can this fail for array types?*/
2266 if (klass->rank == 1 && klass->element_class->rank) {
2267 jagged_ctor = TRUE;
2268 count ++;
2271 if (klass->interface_count) {
2272 count_generic = generic_array_methods (klass);
2273 first_generic = count;
2274 count += klass->interface_count * count_generic;
2277 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * count);
2279 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2280 sig->ret = &mono_defaults.void_class->byval_arg;
2281 sig->pinvoke = TRUE;
2282 sig->hasthis = TRUE;
2283 for (i = 0; i < klass->rank; ++i)
2284 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2286 amethod = create_array_method (klass, ".ctor", sig);
2287 methods [method_num++] = amethod;
2288 if (klass->rank > 1) {
2289 sig = mono_metadata_signature_alloc (klass->image, klass->rank * 2);
2290 sig->ret = &mono_defaults.void_class->byval_arg;
2291 sig->pinvoke = TRUE;
2292 sig->hasthis = TRUE;
2293 for (i = 0; i < klass->rank * 2; ++i)
2294 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2296 amethod = create_array_method (klass, ".ctor", sig);
2297 methods [method_num++] = amethod;
2300 if (jagged_ctor) {
2301 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
2302 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
2303 sig->ret = &mono_defaults.void_class->byval_arg;
2304 sig->pinvoke = TRUE;
2305 sig->hasthis = TRUE;
2306 for (i = 0; i < klass->rank + 1; ++i)
2307 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2308 amethod = create_array_method (klass, ".ctor", sig);
2309 methods [method_num++] = amethod;
2312 /* element Get (idx11, [idx2, ...]) */
2313 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2314 sig->ret = &klass->element_class->byval_arg;
2315 sig->pinvoke = TRUE;
2316 sig->hasthis = TRUE;
2317 for (i = 0; i < klass->rank; ++i)
2318 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2319 amethod = create_array_method (klass, "Get", sig);
2320 methods [method_num++] = amethod;
2321 /* element& Address (idx11, [idx2, ...]) */
2322 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2323 sig->ret = &klass->element_class->this_arg;
2324 sig->pinvoke = TRUE;
2325 sig->hasthis = TRUE;
2326 for (i = 0; i < klass->rank; ++i)
2327 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2328 amethod = create_array_method (klass, "Address", sig);
2329 methods [method_num++] = amethod;
2330 /* void Set (idx11, [idx2, ...], element) */
2331 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
2332 sig->ret = &mono_defaults.void_class->byval_arg;
2333 sig->pinvoke = TRUE;
2334 sig->hasthis = TRUE;
2335 for (i = 0; i < klass->rank; ++i)
2336 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2337 sig->params [i] = &klass->element_class->byval_arg;
2338 amethod = create_array_method (klass, "Set", sig);
2339 methods [method_num++] = amethod;
2341 for (i = 0; i < klass->interface_count; i++)
2342 setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic);
2343 } else if (mono_class_has_static_metadata (klass)) {
2344 MonoError error;
2345 int first_idx = mono_class_get_first_method_idx (klass);
2347 count = mono_class_get_method_count (klass);
2348 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
2349 for (i = 0; i < count; ++i) {
2350 int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
2351 methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, &error);
2352 if (!methods [i]) {
2353 mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (&error));
2354 mono_error_cleanup (&error);
2357 } else {
2358 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
2359 count = 0;
2362 if (MONO_CLASS_IS_INTERFACE (klass)) {
2363 int slot = 0;
2364 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
2365 for (i = 0; i < count; ++i) {
2366 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
2367 methods [i]->slot = slot++;
2371 mono_image_lock (klass->image);
2373 if (!klass->methods) {
2374 mono_class_set_method_count (klass, count);
2376 /* Needed because of the double-checking locking pattern */
2377 mono_memory_barrier ();
2379 klass->methods = methods;
2382 mono_image_unlock (klass->image);
2386 * mono_class_get_method_by_index:
2388 * Returns klass->methods [index], initializing klass->methods if neccesary.
2390 * LOCKING: Acquires the loader lock.
2392 MonoMethod*
2393 mono_class_get_method_by_index (MonoClass *klass, int index)
2395 MonoError error;
2397 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
2398 /* Avoid calling setup_methods () if possible */
2399 if (gklass && !klass->methods) {
2400 MonoMethod *m;
2402 m = mono_class_inflate_generic_method_full_checked (
2403 gklass->container_class->methods [index], klass, mono_class_get_context (klass), &error);
2404 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2406 * If setup_methods () is called later for this class, no duplicates are created,
2407 * since inflate_generic_method guarantees that only one instance of a method
2408 * is created for each context.
2411 mono_class_setup_methods (klass);
2412 g_assert (m == klass->methods [index]);
2414 return m;
2415 } else {
2416 mono_class_setup_methods (klass);
2417 if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
2418 return NULL;
2419 g_assert (index >= 0 && index < mono_class_get_method_count (klass));
2420 return klass->methods [index];
2425 * mono_class_get_inflated_method:
2427 * Given an inflated class CLASS and a method METHOD which should be a method of
2428 * CLASS's generic definition, return the inflated method corresponding to METHOD.
2430 MonoMethod*
2431 mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method)
2433 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2434 int i, mcount;
2436 g_assert (method->klass == gklass);
2438 mono_class_setup_methods (gklass);
2439 g_assert (!mono_class_has_failure (gklass)); /*FIXME do proper error handling*/
2441 mcount = mono_class_get_method_count (gklass);
2442 for (i = 0; i < mcount; ++i) {
2443 if (gklass->methods [i] == method) {
2444 if (klass->methods) {
2445 return klass->methods [i];
2446 } else {
2447 MonoError error;
2448 MonoMethod *result = mono_class_inflate_generic_method_full_checked (gklass->methods [i], klass, mono_class_get_context (klass), &error);
2449 g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
2450 return result;
2455 return NULL;
2459 * mono_class_get_vtable_entry:
2461 * Returns klass->vtable [offset], computing it if neccesary. Returns NULL on failure.
2462 * LOCKING: Acquires the loader lock.
2464 MonoMethod*
2465 mono_class_get_vtable_entry (MonoClass *klass, int offset)
2467 MonoMethod *m;
2469 if (klass->rank == 1) {
2471 * szarrays do not overwrite any methods of Array, so we can avoid
2472 * initializing their vtables in some cases.
2474 mono_class_setup_vtable (klass->parent);
2475 if (offset < klass->parent->vtable_size)
2476 return klass->parent->vtable [offset];
2479 if (mono_class_is_ginst (klass)) {
2480 MonoError error;
2481 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2482 mono_class_setup_vtable (gklass);
2483 m = gklass->vtable [offset];
2485 m = mono_class_inflate_generic_method_full_checked (m, klass, mono_class_get_context (klass), &error);
2486 g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
2487 } else {
2488 mono_class_setup_vtable (klass);
2489 if (mono_class_has_failure (klass))
2490 return NULL;
2491 m = klass->vtable [offset];
2494 return m;
2498 * mono_class_get_vtable_size:
2500 * Return the vtable size for KLASS.
2503 mono_class_get_vtable_size (MonoClass *klass)
2505 mono_class_setup_vtable (klass);
2507 return klass->vtable_size;
2511 * mono_class_setup_properties:
2513 * Initialize klass->ext.property and klass->ext.properties.
2515 * This method can fail the class.
2517 static void
2518 mono_class_setup_properties (MonoClass *klass)
2520 guint startm, endm, i, j;
2521 guint32 cols [MONO_PROPERTY_SIZE];
2522 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
2523 MonoProperty *properties;
2524 guint32 last;
2525 int first, count;
2527 MonoClassExt *ext = mono_class_get_ext (klass);
2528 if (ext && ext->properties)
2529 return;
2531 if (mono_class_is_ginst (klass)) {
2532 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2534 mono_class_init (gklass);
2535 mono_class_setup_properties (gklass);
2536 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2537 return;
2539 MonoClassExt *gext = mono_class_get_ext (gklass);
2540 properties = mono_class_new0 (klass, MonoProperty, gext->property.count + 1);
2542 for (i = 0; i < gext->property.count; i++) {
2543 MonoError error;
2544 MonoProperty *prop = &properties [i];
2546 *prop = gext->properties [i];
2548 if (prop->get)
2549 prop->get = mono_class_inflate_generic_method_full_checked (
2550 prop->get, klass, mono_class_get_context (klass), &error);
2551 if (prop->set)
2552 prop->set = mono_class_inflate_generic_method_full_checked (
2553 prop->set, klass, mono_class_get_context (klass), &error);
2555 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2556 prop->parent = klass;
2559 first = gext->property.first;
2560 count = gext->property.count;
2561 } else {
2562 first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
2563 count = last - first;
2565 if (count) {
2566 mono_class_setup_methods (klass);
2567 if (mono_class_has_failure (klass))
2568 return;
2571 properties = (MonoProperty *)mono_class_alloc0 (klass, sizeof (MonoProperty) * count);
2572 for (i = first; i < last; ++i) {
2573 mono_metadata_decode_table_row (klass->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
2574 properties [i - first].parent = klass;
2575 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
2576 properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
2578 startm = mono_metadata_methods_from_property (klass->image, i, &endm);
2579 int first_idx = mono_class_get_first_method_idx (klass);
2580 for (j = startm; j < endm; ++j) {
2581 MonoMethod *method;
2583 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2585 if (klass->image->uncompressed_metadata) {
2586 MonoError error;
2587 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2588 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
2589 mono_error_cleanup (&error); /* FIXME don't swallow this error */
2590 } else {
2591 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
2594 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2595 case METHOD_SEMANTIC_SETTER:
2596 properties [i - first].set = method;
2597 break;
2598 case METHOD_SEMANTIC_GETTER:
2599 properties [i - first].get = method;
2600 break;
2601 default:
2602 break;
2608 mono_class_alloc_ext (klass);
2609 ext = mono_class_get_ext (klass);
2611 mono_image_lock (klass->image);
2613 if (ext->properties) {
2614 /* We leak 'properties' which was allocated from the image mempool */
2615 mono_image_unlock (klass->image);
2616 return;
2619 ext->property.first = first;
2620 ext->property.count = count;
2622 /* Flush any pending writes as we do double checked locking on klass->ext->properties */
2623 mono_memory_barrier ();
2625 /* Leave this assignment as the last op in the function */
2626 ext->properties = properties;
2628 mono_image_unlock (klass->image);
2631 static MonoMethod**
2632 inflate_method_listz (MonoMethod **methods, MonoClass *klass, MonoGenericContext *context)
2634 MonoMethod **om, **retval;
2635 int count;
2637 for (om = methods, count = 0; *om; ++om, ++count)
2640 retval = g_new0 (MonoMethod*, count + 1);
2641 count = 0;
2642 for (om = methods, count = 0; *om; ++om, ++count) {
2643 MonoError error;
2644 retval [count] = mono_class_inflate_generic_method_full_checked (*om, klass, context, &error);
2645 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2648 return retval;
2651 /*This method can fail the class.*/
2652 static void
2653 mono_class_setup_events (MonoClass *klass)
2655 int first, count;
2656 guint startm, endm, i, j;
2657 guint32 cols [MONO_EVENT_SIZE];
2658 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
2659 guint32 last;
2660 MonoEvent *events;
2662 MonoClassExt *ext = mono_class_get_ext (klass);
2663 if (ext && ext->events)
2664 return;
2666 if (mono_class_is_ginst (klass)) {
2667 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2668 MonoGenericContext *context = NULL;
2670 mono_class_setup_events (gklass);
2671 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2672 return;
2674 MonoClassExt *gext = mono_class_get_ext (gklass);
2675 first = gext->event.first;
2676 count = gext->event.count;
2678 events = mono_class_new0 (klass, MonoEvent, count);
2680 if (count)
2681 context = mono_class_get_context (klass);
2683 for (i = 0; i < count; i++) {
2684 MonoError error;
2685 MonoEvent *event = &events [i];
2686 MonoEvent *gevent = &gext->events [i];
2688 mono_error_init (&error); //since we do conditional calls, we must ensure the default value is ok
2690 event->parent = klass;
2691 event->name = gevent->name;
2692 event->add = gevent->add ? mono_class_inflate_generic_method_full_checked (gevent->add, klass, context, &error) : NULL;
2693 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2694 event->remove = gevent->remove ? mono_class_inflate_generic_method_full_checked (gevent->remove, klass, context, &error) : NULL;
2695 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2696 event->raise = gevent->raise ? mono_class_inflate_generic_method_full_checked (gevent->raise, klass, context, &error) : NULL;
2697 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2699 #ifndef MONO_SMALL_CONFIG
2700 event->other = gevent->other ? inflate_method_listz (gevent->other, klass, context) : NULL;
2701 #endif
2702 event->attrs = gevent->attrs;
2704 } else {
2705 first = mono_metadata_events_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
2706 count = last - first;
2708 if (count) {
2709 mono_class_setup_methods (klass);
2710 if (mono_class_has_failure (klass)) {
2711 return;
2715 events = (MonoEvent *)mono_class_alloc0 (klass, sizeof (MonoEvent) * count);
2716 for (i = first; i < last; ++i) {
2717 MonoEvent *event = &events [i - first];
2719 mono_metadata_decode_table_row (klass->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
2720 event->parent = klass;
2721 event->attrs = cols [MONO_EVENT_FLAGS];
2722 event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
2724 startm = mono_metadata_methods_from_event (klass->image, i, &endm);
2725 int first_idx = mono_class_get_first_method_idx (klass);
2726 for (j = startm; j < endm; ++j) {
2727 MonoMethod *method;
2729 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2731 if (klass->image->uncompressed_metadata) {
2732 MonoError error;
2733 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2734 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
2735 mono_error_cleanup (&error); /* FIXME don't swallow this error */
2736 } else {
2737 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
2740 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2741 case METHOD_SEMANTIC_ADD_ON:
2742 event->add = method;
2743 break;
2744 case METHOD_SEMANTIC_REMOVE_ON:
2745 event->remove = method;
2746 break;
2747 case METHOD_SEMANTIC_FIRE:
2748 event->raise = method;
2749 break;
2750 case METHOD_SEMANTIC_OTHER: {
2751 #ifndef MONO_SMALL_CONFIG
2752 int n = 0;
2754 if (event->other == NULL) {
2755 event->other = g_new0 (MonoMethod*, 2);
2756 } else {
2757 while (event->other [n])
2758 n++;
2759 event->other = (MonoMethod **)g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
2761 event->other [n] = method;
2762 /* NULL terminated */
2763 event->other [n + 1] = NULL;
2764 #endif
2765 break;
2767 default:
2768 break;
2774 mono_class_alloc_ext (klass);
2775 ext = mono_class_get_ext (klass);
2777 mono_image_lock (klass->image);
2779 if (ext->events) {
2780 mono_image_unlock (klass->image);
2781 return;
2784 ext->event.first = first;
2785 ext->event.count = count;
2787 /* Flush any pending writes as we do double checked locking on klass->ext.events */
2788 mono_memory_barrier ();
2790 /* Leave this assignment as the last op in the function */
2791 ext->events = events;
2793 mono_image_unlock (klass->image);
2797 * Global pool of interface IDs, represented as a bitset.
2798 * LOCKING: Protected by the classes lock.
2800 static MonoBitSet *global_interface_bitset = NULL;
2803 * mono_unload_interface_ids:
2804 * @bitset: bit set of interface IDs
2806 * When an image is unloaded, the interface IDs associated with
2807 * the image are put back in the global pool of IDs so the numbers
2808 * can be reused.
2810 void
2811 mono_unload_interface_ids (MonoBitSet *bitset)
2813 classes_lock ();
2814 mono_bitset_sub (global_interface_bitset, bitset);
2815 classes_unlock ();
2818 void
2819 mono_unload_interface_id (MonoClass *klass)
2821 if (global_interface_bitset && klass->interface_id) {
2822 classes_lock ();
2823 mono_bitset_clear (global_interface_bitset, klass->interface_id);
2824 classes_unlock ();
2829 * mono_get_unique_iid:
2830 * @class: interface
2832 * Assign a unique integer ID to the interface represented by @class.
2833 * The ID will positive and as small as possible.
2834 * LOCKING: Acquires the classes lock.
2835 * Returns: The new ID.
2837 static guint32
2838 mono_get_unique_iid (MonoClass *klass)
2840 int iid;
2842 g_assert (MONO_CLASS_IS_INTERFACE (klass));
2844 classes_lock ();
2846 if (!global_interface_bitset) {
2847 global_interface_bitset = mono_bitset_new (128, 0);
2850 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
2851 if (iid < 0) {
2852 int old_size = mono_bitset_size (global_interface_bitset);
2853 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
2854 mono_bitset_free (global_interface_bitset);
2855 global_interface_bitset = new_set;
2856 iid = old_size;
2858 mono_bitset_set (global_interface_bitset, iid);
2859 /* set the bit also in the per-image set */
2860 if (!mono_class_is_ginst (klass)) {
2861 if (klass->image->interface_bitset) {
2862 if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
2863 MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
2864 mono_bitset_free (klass->image->interface_bitset);
2865 klass->image->interface_bitset = new_set;
2867 } else {
2868 klass->image->interface_bitset = mono_bitset_new (iid + 1, 0);
2870 mono_bitset_set (klass->image->interface_bitset, iid);
2873 classes_unlock ();
2875 #ifndef MONO_SMALL_CONFIG
2876 if (mono_print_vtable) {
2877 int generic_id;
2878 char *type_name = mono_type_full_name (&klass->byval_arg);
2879 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
2880 if (gklass && !gklass->context.class_inst->is_open) {
2881 generic_id = gklass->context.class_inst->id;
2882 g_assert (generic_id != 0);
2883 } else {
2884 generic_id = 0;
2886 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->name, type_name, generic_id);
2887 g_free (type_name);
2889 #endif
2891 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
2892 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
2893 g_assert (iid < INT_MAX);
2894 return iid;
2897 static void
2898 collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, MonoError *error)
2900 int i;
2901 MonoClass *ic;
2903 mono_class_setup_interfaces (klass, error);
2904 return_if_nok (error);
2906 for (i = 0; i < klass->interface_count; i++) {
2907 ic = klass->interfaces [i];
2909 if (*res == NULL)
2910 *res = g_ptr_array_new ();
2911 g_ptr_array_add (*res, ic);
2912 mono_class_init (ic);
2913 if (mono_class_has_failure (ic)) {
2914 mono_error_set_type_load_class (error, ic, "Error Loading class");
2915 return;
2918 collect_implemented_interfaces_aux (ic, res, error);
2919 return_if_nok (error);
2923 GPtrArray*
2924 mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error)
2926 GPtrArray *res = NULL;
2928 collect_implemented_interfaces_aux (klass, &res, error);
2929 if (!mono_error_ok (error)) {
2930 if (res)
2931 g_ptr_array_free (res, TRUE);
2932 return NULL;
2934 return res;
2937 static int
2938 compare_interface_ids (const void *p_key, const void *p_element) {
2939 const MonoClass *key = (const MonoClass *)p_key;
2940 const MonoClass *element = *(const MonoClass **)p_element;
2942 return (key->interface_id - element->interface_id);
2945 /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/
2947 mono_class_interface_offset (MonoClass *klass, MonoClass *itf) {
2948 MonoClass **result = (MonoClass **)mono_binary_search (
2949 itf,
2950 klass->interfaces_packed,
2951 klass->interface_offsets_count,
2952 sizeof (MonoClass *),
2953 compare_interface_ids);
2954 if (result) {
2955 return klass->interface_offsets_packed [result - (klass->interfaces_packed)];
2956 } else {
2957 return -1;
2962 * mono_class_interface_offset_with_variance:
2964 * Return the interface offset of @itf in @klass. Sets @non_exact_match to TRUE if the match required variance check
2965 * If @itf is an interface with generic variant arguments, try to find the compatible one.
2967 * Note that this function is responsible for resolving ambiguities. Right now we use whatever ordering interfaces_packed gives us.
2969 * FIXME figure out MS disambiguation rules and fix this function.
2972 mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match) {
2973 int i = mono_class_interface_offset (klass, itf);
2974 *non_exact_match = FALSE;
2975 if (i >= 0)
2976 return i;
2978 if (!mono_class_has_variant_generic_params (itf))
2979 return -1;
2981 for (i = 0; i < klass->interface_offsets_count; i++) {
2982 if (mono_class_is_variant_compatible (itf, klass->interfaces_packed [i], FALSE)) {
2983 *non_exact_match = TRUE;
2984 return klass->interface_offsets_packed [i];
2988 return -1;
2991 static void
2992 print_implemented_interfaces (MonoClass *klass) {
2993 char *name;
2994 MonoError error;
2995 GPtrArray *ifaces = NULL;
2996 int i;
2997 int ancestor_level = 0;
2999 name = mono_type_get_full_name (klass);
3000 printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
3001 g_free (name);
3003 for (i = 0; i < klass->interface_offsets_count; i++)
3004 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
3005 klass->interfaces_packed [i]->interface_id,
3006 klass->interface_offsets_packed [i],
3007 mono_class_get_method_count (klass->interfaces_packed [i]),
3008 klass->interfaces_packed [i]->name_space,
3009 klass->interfaces_packed [i]->name );
3010 printf ("Interface flags: ");
3011 for (i = 0; i <= klass->max_interface_id; i++)
3012 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
3013 printf ("(%d,T)", i);
3014 else
3015 printf ("(%d,F)", i);
3016 printf ("\n");
3017 printf ("Dump interface flags:");
3018 #ifdef COMPRESSED_INTERFACE_BITMAP
3020 const uint8_t* p = klass->interface_bitmap;
3021 i = klass->max_interface_id;
3022 while (i > 0) {
3023 printf (" %d x 00 %02X", p [0], p [1]);
3024 i -= p [0] * 8;
3025 i -= 8;
3028 #else
3029 for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
3030 printf (" %02X", klass->interface_bitmap [i]);
3031 #endif
3032 printf ("\n");
3033 while (klass != NULL) {
3034 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
3035 ifaces = mono_class_get_implemented_interfaces (klass, &error);
3036 if (!mono_error_ok (&error)) {
3037 printf (" Type failed due to %s\n", mono_error_get_message (&error));
3038 mono_error_cleanup (&error);
3039 } else if (ifaces) {
3040 for (i = 0; i < ifaces->len; i++) {
3041 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3042 printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
3043 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
3044 ic->interface_id,
3045 mono_class_interface_offset (klass, ic),
3046 mono_class_get_method_count (ic),
3047 ic->name_space,
3048 ic->name );
3050 g_ptr_array_free (ifaces, TRUE);
3052 ancestor_level ++;
3053 klass = klass->parent;
3057 static MonoClass*
3058 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
3060 MonoType *args [1];
3061 args [0] = &arg0->byval_arg;
3063 return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
3066 static MonoClass*
3067 array_class_get_if_rank (MonoClass *klass, guint rank)
3069 return rank ? mono_array_class_get (klass, rank) : klass;
3072 static void
3073 fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *eclass, int rank)
3075 valuetype_types [0] = eclass;
3076 if (eclass == mono_defaults.int16_class)
3077 valuetype_types [1] = mono_defaults.uint16_class;
3078 else if (eclass == mono_defaults.uint16_class)
3079 valuetype_types [1] = mono_defaults.int16_class;
3080 else if (eclass == mono_defaults.int32_class)
3081 valuetype_types [1] = mono_defaults.uint32_class;
3082 else if (eclass == mono_defaults.uint32_class)
3083 valuetype_types [1] = mono_defaults.int32_class;
3084 else if (eclass == mono_defaults.int64_class)
3085 valuetype_types [1] = mono_defaults.uint64_class;
3086 else if (eclass == mono_defaults.uint64_class)
3087 valuetype_types [1] = mono_defaults.int64_class;
3088 else if (eclass == mono_defaults.byte_class)
3089 valuetype_types [1] = mono_defaults.sbyte_class;
3090 else if (eclass == mono_defaults.sbyte_class)
3091 valuetype_types [1] = mono_defaults.byte_class;
3092 else if (eclass->enumtype && mono_class_enum_basetype (eclass))
3093 valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass));
3096 static GENERATE_GET_CLASS_WITH_CACHE (generic_icollection, System.Collections.Generic, ICollection`1)
3097 static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerable, System.Collections.Generic, IEnumerable`1)
3098 static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerator, System.Collections.Generic, IEnumerator`1)
3099 static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlylist, System.Collections.Generic, IReadOnlyList`1)
3100 static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlycollection, System.Collections.Generic, IReadOnlyCollection`1)
3102 /* this won't be needed once bug #325495 is completely fixed
3103 * though we'll need something similar to know which interfaces to allow
3104 * in arrays when they'll be lazyly created
3106 * FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
3107 * MS returns diferrent types based on which instance is called. For example:
3108 * object obj = new byte[10][];
3109 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
3110 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
3111 * a != b ==> true
3113 * Fixing this should kill quite some code, save some bits and improve compatibility.
3115 static MonoClass**
3116 get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enumerator)
3118 MonoClass *eclass = klass->element_class;
3119 MonoClass* generic_icollection_class;
3120 MonoClass* generic_ienumerable_class;
3121 MonoClass* generic_ienumerator_class;
3122 MonoClass* generic_ireadonlylist_class;
3123 MonoClass* generic_ireadonlycollection_class;
3124 MonoClass *valuetype_types[2] = { NULL, NULL };
3125 MonoClass **interfaces = NULL;
3126 int i, nifaces, interface_count, real_count, original_rank;
3127 int all_interfaces;
3128 gboolean internal_enumerator;
3129 gboolean eclass_is_valuetype;
3131 if (!mono_defaults.generic_ilist_class) {
3132 *num = 0;
3133 return NULL;
3135 internal_enumerator = FALSE;
3136 eclass_is_valuetype = FALSE;
3137 original_rank = eclass->rank;
3138 if (klass->byval_arg.type != MONO_TYPE_SZARRAY) {
3139 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
3140 if (gklass && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0) {
3142 * For a Enumerator<T[]> we need to get the list of interfaces for T.
3144 eclass = mono_class_from_mono_type (gklass->context.class_inst->type_argv [0]);
3145 original_rank = eclass->rank;
3146 if (!eclass->rank)
3147 eclass = eclass->element_class;
3148 internal_enumerator = TRUE;
3149 *is_enumerator = TRUE;
3150 } else {
3151 *num = 0;
3152 return NULL;
3157 * with this non-lazy impl we can't implement all the interfaces so we do just the minimal stuff
3158 * for deep levels of arrays of arrays (string[][] has all the interfaces, string[][][] doesn't)
3160 all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
3162 generic_icollection_class = mono_class_get_generic_icollection_class ();
3163 generic_ienumerable_class = mono_class_get_generic_ienumerable_class ();
3164 generic_ienumerator_class = mono_class_get_generic_ienumerator_class ();
3165 generic_ireadonlylist_class = mono_class_get_generic_ireadonlylist_class ();
3166 generic_ireadonlycollection_class = mono_class_get_generic_ireadonlycollection_class ();
3168 mono_class_init (eclass);
3171 * Arrays in 2.0 need to implement a number of generic interfaces
3172 * (IList`1, ICollection`1, IEnumerable`1 for a number of types depending
3173 * on the element class). For net 4.5, we also need to implement IReadOnlyList`1/IReadOnlyCollection`1.
3174 * We collect the types needed to build the
3175 * instantiations in interfaces at intervals of 3/5, because 3/5 are
3176 * the generic interfaces needed to implement.
3178 * On 4.5, as an optimization, we don't expand ref classes for the variant generic interfaces
3179 * (IEnumerator, IReadOnlyList and IReadOnlyColleciton). The regular dispatch code can handle those cases.
3181 if (eclass->valuetype) {
3182 nifaces = generic_ireadonlylist_class ? 5 : 3;
3183 fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank);
3185 /* IList, ICollection, IEnumerable, IReadOnlyList`1 */
3186 real_count = interface_count = valuetype_types [1] ? (nifaces * 2) : nifaces;
3187 if (internal_enumerator) {
3188 ++real_count;
3189 if (valuetype_types [1])
3190 ++real_count;
3193 interfaces = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * real_count);
3194 interfaces [0] = valuetype_types [0];
3195 if (valuetype_types [1])
3196 interfaces [nifaces] = valuetype_types [1];
3198 eclass_is_valuetype = TRUE;
3199 } else {
3200 int j;
3201 int idepth = eclass->idepth;
3202 if (!internal_enumerator)
3203 idepth--;
3204 nifaces = generic_ireadonlylist_class ? 2 : 3;
3206 // FIXME: This doesn't seem to work/required for generic params
3207 if (!(eclass->this_arg.type == MONO_TYPE_VAR || eclass->this_arg.type == MONO_TYPE_MVAR || (image_is_dynamic (eclass->image) && !eclass->wastypebuilder)))
3208 mono_class_setup_interface_offsets (eclass);
3210 interface_count = all_interfaces? eclass->interface_offsets_count: eclass->interface_count;
3211 /* we add object for interfaces and the supertypes for the other
3212 * types. The last of the supertypes is the element class itself which we
3213 * already created the explicit interfaces for (so we include it for IEnumerator
3214 * and exclude it for arrays).
3216 if (MONO_CLASS_IS_INTERFACE (eclass))
3217 interface_count++;
3218 else
3219 interface_count += idepth;
3220 if (eclass->rank && eclass->element_class->valuetype) {
3221 fill_valuetype_array_derived_types (valuetype_types, eclass->element_class, original_rank);
3222 if (valuetype_types [1])
3223 ++interface_count;
3225 /* IList, ICollection, IEnumerable, IReadOnlyList */
3226 interface_count *= nifaces;
3227 real_count = interface_count;
3228 if (internal_enumerator) {
3229 real_count += (MONO_CLASS_IS_INTERFACE (eclass) ? 1 : idepth) + eclass->interface_offsets_count;
3230 if (valuetype_types [1])
3231 ++real_count;
3233 interfaces = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * real_count);
3234 if (MONO_CLASS_IS_INTERFACE (eclass)) {
3235 interfaces [0] = mono_defaults.object_class;
3236 j = nifaces;
3237 } else {
3238 j = 0;
3239 for (i = 0; i < idepth; i++) {
3240 mono_class_init (eclass->supertypes [i]);
3241 interfaces [j] = eclass->supertypes [i];
3242 j += nifaces;
3245 if (all_interfaces) {
3246 for (i = 0; i < eclass->interface_offsets_count; i++) {
3247 interfaces [j] = eclass->interfaces_packed [i];
3248 j += nifaces;
3250 } else {
3251 for (i = 0; i < eclass->interface_count; i++) {
3252 interfaces [j] = eclass->interfaces [i];
3253 j += nifaces;
3256 if (valuetype_types [1]) {
3257 interfaces [j] = array_class_get_if_rank (valuetype_types [1], original_rank);
3258 j += nifaces;
3262 /* instantiate the generic interfaces */
3263 for (i = 0; i < interface_count; i += nifaces) {
3264 MonoClass *iface = interfaces [i];
3266 interfaces [i + 0] = inflate_class_one_arg (mono_defaults.generic_ilist_class, iface);
3267 interfaces [i + 1] = inflate_class_one_arg (generic_icollection_class, iface);
3269 if (eclass->valuetype) {
3270 interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
3271 if (generic_ireadonlylist_class) {
3272 interfaces [i + 3] = inflate_class_one_arg (generic_ireadonlylist_class, iface);
3273 interfaces [i + 4] = inflate_class_one_arg (generic_ireadonlycollection_class, iface);
3275 } else {
3276 if (!generic_ireadonlylist_class)
3277 interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
3280 if (internal_enumerator) {
3281 int j;
3282 /* instantiate IEnumerator<iface> */
3283 for (i = 0; i < interface_count; i++) {
3284 interfaces [i] = inflate_class_one_arg (generic_ienumerator_class, interfaces [i]);
3286 j = interface_count;
3287 if (!eclass_is_valuetype) {
3288 if (MONO_CLASS_IS_INTERFACE (eclass)) {
3289 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, mono_defaults.object_class);
3290 j ++;
3291 } else {
3292 for (i = 0; i < eclass->idepth; i++) {
3293 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->supertypes [i]);
3294 j ++;
3297 for (i = 0; i < eclass->interface_offsets_count; i++) {
3298 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->interfaces_packed [i]);
3299 j ++;
3301 } else {
3302 interfaces [j++] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [0], original_rank));
3304 if (valuetype_types [1])
3305 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [1], original_rank));
3307 #if 0
3309 char *type_name = mono_type_get_name_full (&klass->byval_arg, 0);
3310 for (i = 0; i < real_count; ++i) {
3311 char *name = mono_type_get_name_full (&interfaces [i]->byval_arg, 0);
3312 g_print ("%s implements %s\n", type_name, name);
3313 g_free (name);
3315 g_free (type_name);
3317 #endif
3318 *num = real_count;
3319 return interfaces;
3322 static int
3323 find_array_interface (MonoClass *klass, const char *name)
3325 int i;
3326 for (i = 0; i < klass->interface_count; ++i) {
3327 if (strcmp (klass->interfaces [i]->name, name) == 0)
3328 return i;
3330 return -1;
3334 * Return the number of virtual methods.
3335 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
3336 * Return -1 on failure.
3337 * FIXME It would be nice if this information could be cached somewhere.
3339 static int
3340 count_virtual_methods (MonoClass *klass)
3342 int i, mcount, vcount = 0;
3343 guint32 flags;
3344 klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/
3346 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
3347 mono_class_setup_methods (klass);
3348 if (mono_class_has_failure (klass))
3349 return -1;
3351 mcount = mono_class_get_method_count (klass);
3352 for (i = 0; i < mcount; ++i) {
3353 flags = klass->methods [i]->flags;
3354 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3355 ++vcount;
3357 } else {
3358 int first_idx = mono_class_get_first_method_idx (klass);
3359 mcount = mono_class_get_method_count (klass);
3360 for (i = 0; i < mcount; ++i) {
3361 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
3363 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3364 ++vcount;
3367 return vcount;
3370 static int
3371 find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic)
3373 int m, l = 0;
3374 if (!num_ifaces)
3375 return -1;
3376 while (1) {
3377 if (l > num_ifaces)
3378 return -1;
3379 m = (l + num_ifaces) / 2;
3380 if (interfaces_full [m] == ic)
3381 return m;
3382 if (l == num_ifaces)
3383 return -1;
3384 if (!interfaces_full [m] || interfaces_full [m]->interface_id > ic->interface_id) {
3385 num_ifaces = m - 1;
3386 } else {
3387 l = m + 1;
3392 static int
3393 find_interface_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic)
3395 int i = find_interface (num_ifaces, interfaces_full, ic);
3396 if (i >= 0)
3397 return interface_offsets_full [i];
3398 return -1;
3401 static mono_bool
3402 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
3404 int i = find_interface (num_ifaces, interfaces_full, ic);
3405 if (i >= 0) {
3406 if (!force_set)
3407 return TRUE;
3408 interface_offsets_full [i] = offset;
3409 return FALSE;
3411 for (i = 0; i < num_ifaces; ++i) {
3412 if (interfaces_full [i]) {
3413 int end;
3414 if (interfaces_full [i]->interface_id < ic->interface_id)
3415 continue;
3416 end = i + 1;
3417 while (end < num_ifaces && interfaces_full [end]) end++;
3418 memmove (interfaces_full + i + 1, interfaces_full + i, sizeof (MonoClass*) * (end - i));
3419 memmove (interface_offsets_full + i + 1, interface_offsets_full + i, sizeof (int) * (end - i));
3421 interfaces_full [i] = ic;
3422 interface_offsets_full [i] = offset;
3423 break;
3425 return FALSE;
3428 #ifdef COMPRESSED_INTERFACE_BITMAP
3431 * Compressed interface bitmap design.
3433 * Interface bitmaps take a large amount of memory, because their size is
3434 * linear with the maximum interface id assigned in the process (each interface
3435 * is assigned a unique id as it is loaded). The number of interface classes
3436 * is high because of the many implicit interfaces implemented by arrays (we'll
3437 * need to lazy-load them in the future).
3438 * Most classes implement a very small number of interfaces, so the bitmap is
3439 * sparse. This bitmap needs to be checked by interface casts, so access to the
3440 * needed bit must be fast and doable with few jit instructions.
3442 * The current compression format is as follows:
3443 * *) it is a sequence of one or more two-byte elements
3444 * *) the first byte in the element is the count of empty bitmap bytes
3445 * at the current bitmap position
3446 * *) the second byte in the element is an actual bitmap byte at the current
3447 * bitmap position
3449 * As an example, the following compressed bitmap bytes:
3450 * 0x07 0x01 0x00 0x7
3451 * correspond to the following bitmap:
3452 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
3454 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
3455 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
3456 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
3460 * mono_compress_bitmap:
3461 * @dest: destination buffer
3462 * @bitmap: bitmap buffer
3463 * @size: size of @bitmap in bytes
3465 * This is a mono internal function.
3466 * The @bitmap data is compressed into a format that is small but
3467 * still searchable in few instructions by the JIT and runtime.
3468 * The compressed data is stored in the buffer pointed to by the
3469 * @dest array. Passing a #NULL value for @dest allows to just compute
3470 * the size of the buffer.
3471 * This compression algorithm assumes the bits set in the bitmap are
3472 * few and far between, like in interface bitmaps.
3473 * Returns: The size of the compressed bitmap in bytes.
3476 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
3478 int numz = 0;
3479 int res = 0;
3480 const uint8_t *end = bitmap + size;
3481 while (bitmap < end) {
3482 if (*bitmap || numz == 255) {
3483 if (dest) {
3484 *dest++ = numz;
3485 *dest++ = *bitmap;
3487 res += 2;
3488 numz = 0;
3489 bitmap++;
3490 continue;
3492 bitmap++;
3493 numz++;
3495 if (numz) {
3496 res += 2;
3497 if (dest) {
3498 *dest++ = numz;
3499 *dest++ = 0;
3502 return res;
3506 * mono_class_interface_match:
3507 * @bitmap: a compressed bitmap buffer
3508 * @id: the index to check in the bitmap
3510 * This is a mono internal function.
3511 * Checks if a bit is set in a compressed interface bitmap. @id must
3512 * be already checked for being smaller than the maximum id encoded in the
3513 * bitmap.
3515 * Returns: A non-zero value if bit @id is set in the bitmap @bitmap,
3516 * #FALSE otherwise.
3519 mono_class_interface_match (const uint8_t *bitmap, int id)
3521 while (TRUE) {
3522 id -= bitmap [0] * 8;
3523 if (id < 8) {
3524 if (id < 0)
3525 return 0;
3526 return bitmap [1] & (1 << id);
3528 bitmap += 2;
3529 id -= 8;
3532 #endif
3535 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
3536 * LOCKING: Acquires the loader lock.
3538 static int
3539 setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
3541 MonoError error;
3542 MonoClass *k, *ic;
3543 int i, j, num_ifaces;
3544 guint32 max_iid;
3545 MonoClass **interfaces_full = NULL;
3546 int *interface_offsets_full = NULL;
3547 GPtrArray *ifaces;
3548 GPtrArray **ifaces_array = NULL;
3549 int interface_offsets_count;
3550 MonoClass **array_interfaces = NULL;
3551 int num_array_interfaces;
3552 int is_enumerator = FALSE;
3554 mono_loader_lock ();
3556 mono_class_setup_supertypes (klass);
3558 * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator<T>
3559 * implicit interfaces have the property that they are assigned the same slot in the
3560 * vtables for compatible interfaces
3562 array_interfaces = get_implicit_generic_array_interfaces (klass, &num_array_interfaces, &is_enumerator);
3564 /* compute maximum number of slots and maximum interface id */
3565 max_iid = 0;
3566 num_ifaces = num_array_interfaces; /* this can include duplicated ones */
3567 ifaces_array = g_new0 (GPtrArray *, klass->idepth);
3568 for (j = 0; j < klass->idepth; j++) {
3569 k = klass->supertypes [j];
3570 g_assert (k);
3571 num_ifaces += k->interface_count;
3572 for (i = 0; i < k->interface_count; i++) {
3573 ic = k->interfaces [i];
3575 mono_class_init (ic);
3577 if (max_iid < ic->interface_id)
3578 max_iid = ic->interface_id;
3580 ifaces = mono_class_get_implemented_interfaces (k, &error);
3581 if (!mono_error_ok (&error)) {
3582 char *name = mono_type_get_full_name (k);
3583 mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error));
3584 g_free (name);
3585 mono_error_cleanup (&error);
3586 cur_slot = -1;
3587 goto end;
3589 if (ifaces) {
3590 num_ifaces += ifaces->len;
3591 for (i = 0; i < ifaces->len; ++i) {
3592 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3593 if (max_iid < ic->interface_id)
3594 max_iid = ic->interface_id;
3596 ifaces_array [j] = ifaces;
3600 for (i = 0; i < num_array_interfaces; ++i) {
3601 ic = array_interfaces [i];
3602 mono_class_init (ic);
3603 if (max_iid < ic->interface_id)
3604 max_iid = ic->interface_id;
3607 if (MONO_CLASS_IS_INTERFACE (klass)) {
3608 num_ifaces++;
3609 if (max_iid < klass->interface_id)
3610 max_iid = klass->interface_id;
3613 /* compute vtable offset for interfaces */
3614 interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
3615 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
3617 for (i = 0; i < num_ifaces; i++)
3618 interface_offsets_full [i] = -1;
3620 /* skip the current class */
3621 for (j = 0; j < klass->idepth - 1; j++) {
3622 k = klass->supertypes [j];
3623 ifaces = ifaces_array [j];
3625 if (ifaces) {
3626 for (i = 0; i < ifaces->len; ++i) {
3627 int io;
3628 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3630 /*Force the sharing of interface offsets between parent and subtypes.*/
3631 io = mono_class_interface_offset (k, ic);
3632 g_assert (io >= 0);
3633 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
3638 g_assert (klass == klass->supertypes [klass->idepth - 1]);
3639 ifaces = ifaces_array [klass->idepth - 1];
3640 if (ifaces) {
3641 for (i = 0; i < ifaces->len; ++i) {
3642 int count;
3643 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3644 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
3645 continue;
3646 count = count_virtual_methods (ic);
3647 if (count == -1) {
3648 char *name = mono_type_get_full_name (ic);
3649 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
3650 g_free (name);
3651 cur_slot = -1;
3652 goto end;
3654 cur_slot += count;
3658 if (MONO_CLASS_IS_INTERFACE (klass))
3659 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE);
3661 if (num_array_interfaces) {
3662 if (is_enumerator) {
3663 int ienumerator_idx = find_array_interface (klass, "IEnumerator`1");
3664 int ienumerator_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ienumerator_idx]);
3665 g_assert (ienumerator_offset >= 0);
3666 for (i = 0; i < num_array_interfaces; ++i) {
3667 ic = array_interfaces [i];
3668 if (strcmp (ic->name, "IEnumerator`1") == 0)
3669 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, ienumerator_offset, TRUE);
3670 else
3671 g_assert_not_reached ();
3672 /*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);*/
3674 } else {
3675 int ilist_offset, icollection_offset, ienumerable_offset, ireadonlylist_offset, ireadonlycollection_offset;
3676 int ilist_iface_idx = find_array_interface (klass, "IList`1");
3677 MonoClass* ilist_class = klass->interfaces [ilist_iface_idx];
3678 int ireadonlylist_iface_idx = find_array_interface (klass, "IReadOnlyList`1");
3679 MonoClass* ireadonlylist_class = ireadonlylist_iface_idx != -1 ? klass->interfaces [ireadonlylist_iface_idx] : NULL;
3680 int icollection_iface_idx = find_array_interface (ilist_class, "ICollection`1");
3681 int ienumerable_iface_idx = find_array_interface (ilist_class, "IEnumerable`1");
3682 int ireadonlycollection_iface_idx = ireadonlylist_iface_idx != -1 ? find_array_interface (ireadonlylist_class, "IReadOnlyCollection`1") : -1;
3683 ilist_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ilist_iface_idx]);
3684 icollection_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [icollection_iface_idx]);
3685 ienumerable_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [ienumerable_iface_idx]);
3686 ireadonlylist_offset = ireadonlylist_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, klass->interfaces [ireadonlylist_iface_idx]) : -1;
3687 ireadonlycollection_offset = ireadonlycollection_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ireadonlylist_class->interfaces [ireadonlycollection_iface_idx]) : -1;
3688 g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0);
3689 for (i = 0; i < num_array_interfaces; ++i) {
3690 int offset;
3691 ic = array_interfaces [i];
3692 if (mono_class_get_generic_class (ic)->container_class == mono_defaults.generic_ilist_class)
3693 offset = ilist_offset;
3694 else if (strcmp (ic->name, "ICollection`1") == 0)
3695 offset = icollection_offset;
3696 else if (strcmp (ic->name, "IEnumerable`1") == 0)
3697 offset = ienumerable_offset;
3698 else if (strcmp (ic->name, "IReadOnlyList`1") == 0)
3699 offset = ireadonlylist_offset;
3700 else if (strcmp (ic->name, "IReadOnlyCollection`1") == 0)
3701 offset = ireadonlycollection_offset;
3702 else
3703 g_assert_not_reached ();
3704 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, offset, TRUE);
3705 /*g_print ("type %s has %s offset at %d (%s)\n", klass->name, ic->name, offset, klass->interfaces [0]->name);*/
3710 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
3711 if (interface_offsets_full [i] != -1)
3712 interface_offsets_count ++;
3715 /* Publish the data */
3716 klass->max_interface_id = max_iid;
3718 * We might get called multiple times:
3719 * - mono_class_init ()
3720 * - mono_class_setup_vtable ().
3721 * - mono_class_setup_interface_offsets ().
3722 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
3723 * means we have to overwrite those when called from other places (#4440).
3725 if (klass->interfaces_packed) {
3726 if (!overwrite)
3727 g_assert (klass->interface_offsets_count == interface_offsets_count);
3728 } else {
3729 uint8_t *bitmap;
3730 int bsize;
3731 klass->interface_offsets_count = interface_offsets_count;
3732 klass->interfaces_packed = (MonoClass **)mono_class_alloc (klass, sizeof (MonoClass*) * interface_offsets_count);
3733 klass->interface_offsets_packed = (guint16 *)mono_class_alloc (klass, sizeof (guint16) * interface_offsets_count);
3734 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
3735 #ifdef COMPRESSED_INTERFACE_BITMAP
3736 bitmap = g_malloc0 (bsize);
3737 #else
3738 bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
3739 #endif
3740 for (i = 0; i < interface_offsets_count; i++) {
3741 guint32 id = interfaces_full [i]->interface_id;
3742 bitmap [id >> 3] |= (1 << (id & 7));
3743 klass->interfaces_packed [i] = interfaces_full [i];
3744 klass->interface_offsets_packed [i] = interface_offsets_full [i];
3745 /*if (num_array_interfaces)
3746 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]);*/
3748 #ifdef COMPRESSED_INTERFACE_BITMAP
3749 i = mono_compress_bitmap (NULL, bitmap, bsize);
3750 klass->interface_bitmap = mono_class_alloc0 (klass, i);
3751 mono_compress_bitmap (klass->interface_bitmap, bitmap, bsize);
3752 g_free (bitmap);
3753 #else
3754 klass->interface_bitmap = bitmap;
3755 #endif
3757 end:
3758 mono_loader_unlock ();
3760 g_free (interfaces_full);
3761 g_free (interface_offsets_full);
3762 g_free (array_interfaces);
3763 for (i = 0; i < klass->idepth; i++) {
3764 ifaces = ifaces_array [i];
3765 if (ifaces)
3766 g_ptr_array_free (ifaces, TRUE);
3768 g_free (ifaces_array);
3770 //printf ("JUST DONE: ");
3771 //print_implemented_interfaces (klass);
3773 return cur_slot;
3777 * Setup interface offsets for interfaces.
3778 * Initializes:
3779 * - klass->max_interface_id
3780 * - klass->interface_offsets_count
3781 * - klass->interfaces_packed
3782 * - klass->interface_offsets_packed
3783 * - klass->interface_bitmap
3785 * This function can fail @class.
3787 void
3788 mono_class_setup_interface_offsets (MonoClass *klass)
3790 setup_interface_offsets (klass, 0, FALSE);
3793 /*Checks if @klass has @parent as one of it's parents type gtd
3795 * For example:
3796 * Foo<T>
3797 * Bar<T> : Foo<Bar<Bar<T>>>
3800 static gboolean
3801 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
3803 klass = mono_class_get_generic_type_definition (klass);
3804 parent = mono_class_get_generic_type_definition (parent);
3805 mono_class_setup_supertypes (klass);
3806 mono_class_setup_supertypes (parent);
3808 return klass->idepth >= parent->idepth &&
3809 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
3812 gboolean
3813 mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
3815 MonoGenericInst *ginst;
3816 int i;
3818 if (!mono_class_is_ginst (klass)) {
3819 mono_class_setup_vtable_full (klass, in_setup);
3820 return !mono_class_has_failure (klass);
3823 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
3824 if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
3825 return FALSE;
3827 ginst = mono_class_get_generic_class (klass)->context.class_inst;
3828 for (i = 0; i < ginst->type_argc; ++i) {
3829 MonoClass *arg;
3830 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
3831 continue;
3832 arg = mono_class_from_mono_type (ginst->type_argv [i]);
3833 /*Those 2 will be checked by mono_class_setup_vtable itself*/
3834 if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
3835 continue;
3836 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
3837 mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
3838 return FALSE;
3841 return TRUE;
3845 * mono_class_setup_vtable:
3847 * Creates the generic vtable of CLASS.
3848 * Initializes the following fields in MonoClass:
3849 * - vtable
3850 * - vtable_size
3851 * Plus all the fields initialized by setup_interface_offsets ().
3852 * If there is an error during vtable construction, klass->has_failure
3853 * is set and details are stored in a MonoErrorBoxed.
3855 * LOCKING: Acquires the loader lock.
3857 void
3858 mono_class_setup_vtable (MonoClass *klass)
3860 mono_class_setup_vtable_full (klass, NULL);
3863 static void
3864 mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
3866 MonoError error;
3867 MonoMethod **overrides;
3868 MonoGenericContext *context;
3869 guint32 type_token;
3870 int onum = 0;
3871 gboolean ok = TRUE;
3873 if (klass->vtable)
3874 return;
3876 if (MONO_CLASS_IS_INTERFACE (klass)) {
3877 /* This sets method->slot for all methods if this is an interface */
3878 mono_class_setup_methods (klass);
3879 return;
3882 if (mono_class_has_failure (klass))
3883 return;
3885 if (g_list_find (in_setup, klass))
3886 return;
3888 mono_loader_lock ();
3890 if (klass->vtable) {
3891 mono_loader_unlock ();
3892 return;
3895 mono_stats.generic_vtable_count ++;
3896 in_setup = g_list_prepend (in_setup, klass);
3898 if (mono_class_is_ginst (klass)) {
3899 if (!mono_class_check_vtable_constraints (klass, in_setup)) {
3900 mono_loader_unlock ();
3901 g_list_remove (in_setup, klass);
3902 return;
3905 context = mono_class_get_context (klass);
3906 type_token = mono_class_get_generic_class (klass)->container_class->type_token;
3907 } else {
3908 context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
3909 type_token = klass->type_token;
3912 if (image_is_dynamic (klass->image)) {
3913 /* Generic instances can have zero method overrides without causing any harm.
3914 * This is true since we don't do layout all over again for them, we simply inflate
3915 * the layout of the parent.
3917 mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, &error);
3918 if (!is_ok (&error)) {
3919 mono_loader_unlock ();
3920 g_list_remove (in_setup, klass);
3921 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (&error));
3922 mono_error_cleanup (&error);
3923 return;
3925 } else {
3926 /* The following call fails if there are missing methods in the type */
3927 /* FIXME it's probably a good idea to avoid this for generic instances. */
3928 ok = mono_class_get_overrides_full (klass->image, type_token, &overrides, &onum, context);
3931 if (ok)
3932 mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
3933 else
3934 mono_class_set_type_load_failure (klass, "Could not load list of method overrides");
3936 g_free (overrides);
3938 mono_loader_unlock ();
3939 g_list_remove (in_setup, klass);
3941 return;
3944 #define DEBUG_INTERFACE_VTABLE_CODE 0
3945 #define TRACE_INTERFACE_VTABLE_CODE 0
3946 #define VERIFY_INTERFACE_VTABLE_CODE 0
3947 #define VTABLE_SELECTOR (1)
3949 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3950 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
3951 if (!(VTABLE_SELECTOR)) break; \
3952 stmt;\
3953 } while (0)
3954 #else
3955 #define DEBUG_INTERFACE_VTABLE(stmt)
3956 #endif
3958 #if TRACE_INTERFACE_VTABLE_CODE
3959 #define TRACE_INTERFACE_VTABLE(stmt) do {\
3960 if (!(VTABLE_SELECTOR)) break; \
3961 stmt;\
3962 } while (0)
3963 #else
3964 #define TRACE_INTERFACE_VTABLE(stmt)
3965 #endif
3967 #if VERIFY_INTERFACE_VTABLE_CODE
3968 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
3969 if (!(VTABLE_SELECTOR)) break; \
3970 stmt;\
3971 } while (0)
3972 #else
3973 #define VERIFY_INTERFACE_VTABLE(stmt)
3974 #endif
3977 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3978 static char*
3979 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
3981 int i;
3982 char *result;
3983 GString *res = g_string_new ("");
3985 g_string_append_c (res, '(');
3986 for (i = 0; i < sig->param_count; ++i) {
3987 if (i > 0)
3988 g_string_append_c (res, ',');
3989 mono_type_get_desc (res, sig->params [i], include_namespace);
3991 g_string_append (res, ")=>");
3992 if (sig->ret != NULL) {
3993 mono_type_get_desc (res, sig->ret, include_namespace);
3994 } else {
3995 g_string_append (res, "NULL");
3997 result = res->str;
3998 g_string_free (res, FALSE);
3999 return result;
4001 static void
4002 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
4003 char *im_sig = mono_signature_get_full_desc (mono_method_signature (im), TRUE);
4004 char *cm_sig = mono_signature_get_full_desc (mono_method_signature (cm), TRUE);
4005 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
4006 g_free (im_sig);
4007 g_free (cm_sig);
4011 #endif
4012 static gboolean
4013 is_wcf_hack_disabled (void)
4015 static gboolean disabled;
4016 static gboolean inited = FALSE;
4017 if (!inited) {
4018 disabled = g_getenv ("MONO_DISABLE_WCF_HACK") != NULL;
4019 inited = TRUE;
4021 return disabled;
4024 static gboolean
4025 check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty)
4027 MonoMethodSignature *cmsig, *imsig;
4028 if (strcmp (im->name, cm->name) == 0) {
4029 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
4030 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
4031 return FALSE;
4033 if (! slot_is_empty) {
4034 if (require_newslot) {
4035 if (! interface_is_explicitly_implemented_by_class) {
4036 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
4037 return FALSE;
4039 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
4040 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
4041 return FALSE;
4043 } else {
4044 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
4047 cmsig = mono_method_signature (cm);
4048 imsig = mono_method_signature (im);
4049 if (!cmsig || !imsig) {
4050 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
4051 return FALSE;
4054 if (! mono_metadata_signature_equal (cmsig, imsig)) {
4055 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
4056 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
4057 TRACE_INTERFACE_VTABLE (printf ("]"));
4058 return FALSE;
4060 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
4061 if (mono_security_core_clr_enabled ())
4062 mono_security_core_clr_check_override (klass, cm, im);
4064 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
4065 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
4066 char *body_name = mono_method_full_name (cm, TRUE);
4067 char *decl_name = mono_method_full_name (im, TRUE);
4068 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4069 g_free (body_name);
4070 g_free (decl_name);
4071 return FALSE;
4074 return TRUE;
4075 } else {
4076 MonoClass *ic = im->klass;
4077 const char *ic_name_space = ic->name_space;
4078 const char *ic_name = ic->name;
4079 char *subname;
4081 if (! require_newslot) {
4082 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
4083 return FALSE;
4085 if (cm->klass->rank == 0) {
4086 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
4087 return FALSE;
4089 cmsig = mono_method_signature (cm);
4090 imsig = mono_method_signature (im);
4091 if (!cmsig || !imsig) {
4092 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
4093 return FALSE;
4096 if (! mono_metadata_signature_equal (cmsig, imsig)) {
4097 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
4098 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
4099 TRACE_INTERFACE_VTABLE (printf ("]"));
4100 return FALSE;
4102 if (mono_class_get_image (ic) != mono_defaults.corlib) {
4103 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
4104 return FALSE;
4106 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
4107 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
4108 return FALSE;
4110 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))) {
4111 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
4112 return FALSE;
4115 subname = strstr (cm->name, ic_name_space);
4116 if (subname != cm->name) {
4117 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
4118 return FALSE;
4120 subname += strlen (ic_name_space);
4121 if (subname [0] != '.') {
4122 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
4123 return FALSE;
4125 subname ++;
4126 if (strstr (subname, ic_name) != subname) {
4127 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
4128 return FALSE;
4130 subname += strlen (ic_name);
4131 if (subname [0] != '.') {
4132 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
4133 return FALSE;
4135 subname ++;
4136 if (strcmp (subname, im->name) != 0) {
4137 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
4138 return FALSE;
4141 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
4142 if (mono_security_core_clr_enabled ())
4143 mono_security_core_clr_check_override (klass, cm, im);
4145 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
4146 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
4147 char *body_name = mono_method_full_name (cm, TRUE);
4148 char *decl_name = mono_method_full_name (im, TRUE);
4149 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4150 g_free (body_name);
4151 g_free (decl_name);
4152 return FALSE;
4155 return TRUE;
4159 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
4160 static void
4161 foreach_override (gpointer key, gpointer value, gpointer user_data) {
4162 MonoMethod *method = key;
4163 MonoMethod *override = value;
4164 MonoClass *method_class = mono_method_get_class (method);
4165 MonoClass *override_class = mono_method_get_class (override);
4167 printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
4168 mono_class_get_namespace (method_class), mono_class_get_name (method_class), mono_method_get_name (method),
4169 mono_class_get_namespace (override_class), mono_class_get_name (override_class), mono_method_get_name (override));
4171 static void
4172 print_overrides (GHashTable *override_map, const char *message) {
4173 if (override_map) {
4174 printf ("Override map \"%s\" START:\n", message);
4175 g_hash_table_foreach (override_map, foreach_override, NULL);
4176 printf ("Override map \"%s\" END.\n", message);
4177 } else {
4178 printf ("Override map \"%s\" EMPTY.\n", message);
4181 static void
4182 print_vtable_full (MonoClass *klass, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
4183 char *full_name = mono_type_full_name (&klass->byval_arg);
4184 int i;
4185 int parent_size;
4187 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
4189 if (print_interfaces) {
4190 print_implemented_interfaces (klass);
4191 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
4194 if (klass->parent) {
4195 parent_size = klass->parent->vtable_size;
4196 } else {
4197 parent_size = 0;
4199 for (i = 0; i < size; ++i) {
4200 MonoMethod *cm = vtable [i];
4201 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
4202 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
4204 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
4205 g_free (cm_name);
4208 g_free (full_name);
4210 #endif
4212 #if VERIFY_INTERFACE_VTABLE_CODE
4213 static int
4214 mono_method_try_get_vtable_index (MonoMethod *method)
4216 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
4217 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
4218 if (imethod->declaring->is_generic)
4219 return imethod->declaring->slot;
4221 return method->slot;
4224 static void
4225 mono_class_verify_vtable (MonoClass *klass)
4227 int i, count;
4228 char *full_name = mono_type_full_name (&klass->byval_arg);
4230 printf ("*** Verifying VTable of class '%s' \n", full_name);
4231 g_free (full_name);
4232 full_name = NULL;
4234 if (!klass->methods)
4235 return;
4237 count = mono_class_method_count (klass);
4238 for (i = 0; i < count; ++i) {
4239 MonoMethod *cm = klass->methods [i];
4240 int slot;
4242 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
4243 continue;
4245 g_free (full_name);
4246 full_name = mono_method_full_name (cm, TRUE);
4248 slot = mono_method_try_get_vtable_index (cm);
4249 if (slot >= 0) {
4250 if (slot >= klass->vtable_size) {
4251 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, klass->vtable_size);
4252 continue;
4255 if (slot >= 0 && klass->vtable [slot] != cm && (klass->vtable [slot])) {
4256 char *other_name = klass->vtable [slot] ? mono_method_full_name (klass->vtable [slot], TRUE) : g_strdup ("[null value]");
4257 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
4258 g_free (other_name);
4260 } else
4261 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
4263 g_free (full_name);
4265 #endif
4267 static void
4268 print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum)
4270 int index, mcount;
4271 char *method_signature;
4272 char *type_name;
4274 for (index = 0; index < onum; ++index) {
4275 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name,
4276 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
4278 method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
4279 type_name = mono_type_full_name (&klass->byval_arg);
4280 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s\n",
4281 mono_type_get_name (&ic->byval_arg), im->name, method_signature, type_name);
4282 g_free (method_signature);
4283 g_free (type_name);
4284 mono_class_setup_methods (klass);
4285 if (mono_class_has_failure (klass)) {
4286 char *name = mono_type_get_full_name (klass);
4287 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods\n", name);
4288 g_free (name);
4289 return;
4291 mcount = mono_class_get_method_count (klass);
4292 for (index = 0; index < mcount; ++index) {
4293 MonoMethod *cm = klass->methods [index];
4294 method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
4296 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)\n", cm->name, method_signature);
4297 g_free (method_signature);
4301 static MonoMethod*
4302 mono_method_get_method_definition (MonoMethod *method)
4304 while (method->is_inflated)
4305 method = ((MonoMethodInflated*)method)->declaring;
4306 return method;
4309 static gboolean
4310 verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
4312 int i;
4314 for (i = 0; i < onum; ++i) {
4315 MonoMethod *decl = overrides [i * 2];
4316 MonoMethod *body = overrides [i * 2 + 1];
4318 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
4319 mono_class_set_type_load_failure (klass, "Method belongs to a different class than the declared one");
4320 return FALSE;
4323 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
4324 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4325 mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
4326 else
4327 mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
4328 return FALSE;
4331 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
4332 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4333 mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
4334 else
4335 mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
4336 return FALSE;
4339 if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
4340 mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
4341 return FALSE;
4344 body = mono_method_get_method_definition (body);
4345 decl = mono_method_get_method_definition (decl);
4347 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
4348 char *body_name = mono_method_full_name (body, TRUE);
4349 char *decl_name = mono_method_full_name (decl, TRUE);
4350 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4351 g_free (body_name);
4352 g_free (decl_name);
4353 return FALSE;
4356 return TRUE;
4359 static gboolean
4360 mono_class_need_stelemref_method (MonoClass *klass)
4362 return klass->rank == 1 && MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg);
4366 * LOCKING: this is supposed to be called with the loader lock held.
4368 void
4369 mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup)
4371 MonoError error;
4372 MonoClass *k, *ic;
4373 MonoMethod **vtable;
4374 int i, max_vtsize = 0, cur_slot = 0;
4375 guint32 max_iid;
4376 GPtrArray *ifaces = NULL;
4377 GHashTable *override_map = NULL;
4378 MonoMethod *cm;
4379 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
4380 int first_non_interface_slot;
4381 #endif
4382 GSList *virt_methods = NULL, *l;
4383 int stelemref_slot = 0;
4385 if (klass->vtable)
4386 return;
4388 if (overrides && !verify_class_overrides (klass, overrides, onum))
4389 return;
4391 ifaces = mono_class_get_implemented_interfaces (klass, &error);
4392 if (!mono_error_ok (&error)) {
4393 char *name = mono_type_get_full_name (klass);
4394 mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error));
4395 g_free (name);
4396 mono_error_cleanup (&error);
4397 return;
4398 } else if (ifaces) {
4399 for (i = 0; i < ifaces->len; i++) {
4400 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
4401 max_vtsize += mono_class_get_method_count (ic);
4403 g_ptr_array_free (ifaces, TRUE);
4404 ifaces = NULL;
4407 if (klass->parent) {
4408 mono_class_init (klass->parent);
4409 mono_class_setup_vtable_full (klass->parent, in_setup);
4411 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
4412 return;
4414 max_vtsize += klass->parent->vtable_size;
4415 cur_slot = klass->parent->vtable_size;
4418 max_vtsize += mono_class_get_method_count (klass);
4420 /*Array have a slot for stelemref*/
4421 if (mono_class_need_stelemref_method (klass)) {
4422 stelemref_slot = cur_slot;
4423 ++max_vtsize;
4424 ++cur_slot;
4427 vtable = (MonoMethod **)alloca (sizeof (gpointer) * max_vtsize);
4428 memset (vtable, 0, sizeof (gpointer) * max_vtsize);
4430 /* printf ("METAINIT %s.%s\n", klass->name_space, klass->name); */
4432 cur_slot = setup_interface_offsets (klass, cur_slot, TRUE);
4433 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
4434 return;
4436 max_iid = klass->max_interface_id;
4437 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
4439 /* Optimized version for generic instances */
4440 if (mono_class_is_ginst (klass)) {
4441 MonoError error;
4442 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4443 MonoMethod **tmp;
4445 mono_class_setup_vtable_full (gklass, in_setup);
4446 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
4447 return;
4449 tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
4450 klass->vtable_size = gklass->vtable_size;
4451 for (i = 0; i < gklass->vtable_size; ++i)
4452 if (gklass->vtable [i]) {
4453 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), &error);
4454 if (!mono_error_ok (&error)) {
4455 mono_class_set_type_load_failure (klass, "Could not inflate method due to %s", mono_error_get_message (&error));
4456 mono_error_cleanup (&error);
4457 return;
4459 tmp [i] = inflated;
4460 tmp [i]->slot = gklass->vtable [i]->slot;
4462 mono_memory_barrier ();
4463 klass->vtable = tmp;
4465 /* Have to set method->slot for abstract virtual methods */
4466 if (klass->methods && gklass->methods) {
4467 int mcount = mono_class_get_method_count (klass);
4468 for (i = 0; i < mcount; ++i)
4469 if (klass->methods [i]->slot == -1)
4470 klass->methods [i]->slot = gklass->methods [i]->slot;
4473 return;
4476 if (klass->parent && klass->parent->vtable_size) {
4477 MonoClass *parent = klass->parent;
4478 int i;
4480 memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
4482 // Also inherit parent interface vtables, just as a starting point.
4483 // This is needed otherwise bug-77127.exe fails when the property methods
4484 // have different names in the iterface and the class, because for child
4485 // classes the ".override" information is not used anymore.
4486 for (i = 0; i < parent->interface_offsets_count; i++) {
4487 MonoClass *parent_interface = parent->interfaces_packed [i];
4488 int interface_offset = mono_class_interface_offset (klass, parent_interface);
4489 /*FIXME this is now dead code as this condition will never hold true.
4490 Since interface offsets are inherited then the offset of an interface implemented
4491 by a parent will never be the out of it's vtable boundary.
4493 if (interface_offset >= parent->vtable_size) {
4494 int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
4495 int j;
4497 mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
4498 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
4499 int mcount = mono_class_get_method_count (parent_interface);
4500 for (j = 0; j < mcount && !mono_class_has_failure (klass); j++) {
4501 vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
4502 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
4503 parent_interface_offset + j, parent_interface_offset, j,
4504 interface_offset + j, interface_offset, j));
4511 /*Array have a slot for stelemref*/
4512 if (mono_class_need_stelemref_method (klass)) {
4513 MonoMethod *method = mono_marshal_get_virtual_stelemref (klass);
4514 if (!method->slot)
4515 method->slot = stelemref_slot;
4516 else
4517 g_assert (method->slot == stelemref_slot);
4519 vtable [stelemref_slot] = method;
4522 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
4523 /* override interface methods */
4524 for (i = 0; i < onum; i++) {
4525 MonoMethod *decl = overrides [i*2];
4526 if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
4527 int dslot;
4528 dslot = mono_method_get_vtable_slot (decl);
4529 if (dslot == -1) {
4530 mono_class_set_type_load_failure (klass, "");
4531 return;
4534 dslot += mono_class_interface_offset (klass, decl->klass);
4535 vtable [dslot] = overrides [i*2 + 1];
4536 vtable [dslot]->slot = dslot;
4537 if (!override_map)
4538 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4540 g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
4542 if (mono_security_core_clr_enabled ())
4543 mono_security_core_clr_check_override (klass, vtable [dslot], decl);
4546 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
4547 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
4550 * Create a list of virtual methods to avoid calling
4551 * mono_class_get_virtual_methods () which is slow because of the metadata
4552 * optimization.
4555 gpointer iter = NULL;
4556 MonoMethod *cm;
4558 virt_methods = NULL;
4559 while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
4560 virt_methods = g_slist_prepend (virt_methods, cm);
4562 if (mono_class_has_failure (klass))
4563 goto fail;
4566 // Loop on all implemented interfaces...
4567 for (i = 0; i < klass->interface_offsets_count; i++) {
4568 MonoClass *parent = klass->parent;
4569 int ic_offset;
4570 gboolean interface_is_explicitly_implemented_by_class;
4571 int im_index;
4573 ic = klass->interfaces_packed [i];
4574 ic_offset = mono_class_interface_offset (klass, ic);
4576 mono_class_setup_methods (ic);
4577 if (mono_class_has_failure (ic))
4578 goto fail;
4580 // Check if this interface is explicitly implemented (instead of just inherited)
4581 if (parent != NULL) {
4582 int implemented_interfaces_index;
4583 interface_is_explicitly_implemented_by_class = FALSE;
4584 for (implemented_interfaces_index = 0; implemented_interfaces_index < klass->interface_count; implemented_interfaces_index++) {
4585 if (ic == klass->interfaces [implemented_interfaces_index]) {
4586 interface_is_explicitly_implemented_by_class = TRUE;
4587 break;
4590 } else {
4591 interface_is_explicitly_implemented_by_class = TRUE;
4594 // Loop on all interface methods...
4595 int mcount = mono_class_get_method_count (ic);
4596 for (im_index = 0; im_index < mcount; im_index++) {
4597 MonoMethod *im = ic->methods [im_index];
4598 int im_slot = ic_offset + im->slot;
4599 MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL;
4601 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4602 continue;
4604 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
4606 // If there is an explicit implementation, just use it right away,
4607 // otherwise look for a matching method
4608 if (override_im == NULL) {
4609 int cm_index;
4610 MonoMethod *cm;
4612 // First look for a suitable method among the class methods
4613 for (l = virt_methods; l; l = l->next) {
4614 cm = (MonoMethod *)l->data;
4615 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)));
4616 if (check_interface_method_override (klass, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
4617 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
4618 vtable [im_slot] = cm;
4619 /* Why do we need this? */
4620 if (cm->slot < 0) {
4621 cm->slot = im_slot;
4624 TRACE_INTERFACE_VTABLE (printf ("\n"));
4625 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
4626 goto fail;
4629 // If the slot is still empty, look in all the inherited virtual methods...
4630 if ((vtable [im_slot] == NULL) && klass->parent != NULL) {
4631 MonoClass *parent = klass->parent;
4632 // Reverse order, so that last added methods are preferred
4633 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
4634 MonoMethod *cm = parent->vtable [cm_index];
4636 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));
4637 if ((cm != NULL) && check_interface_method_override (klass, im, cm, FALSE, FALSE, TRUE)) {
4638 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
4639 vtable [im_slot] = cm;
4640 /* Why do we need this? */
4641 if (cm->slot < 0) {
4642 cm->slot = im_slot;
4644 break;
4646 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
4647 goto fail;
4648 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
4651 } else {
4652 g_assert (vtable [im_slot] == override_im);
4657 // If the class is not abstract, check that all its interface slots are full.
4658 // The check is done here and not directly at the end of the loop above because
4659 // it can happen (for injected generic array interfaces) that the same slot is
4660 // processed multiple times (those interfaces have overlapping slots), and it
4661 // will not always be the first pass the one that fills the slot.
4662 if (!mono_class_is_abstract (klass)) {
4663 for (i = 0; i < klass->interface_offsets_count; i++) {
4664 int ic_offset;
4665 int im_index;
4667 ic = klass->interfaces_packed [i];
4668 ic_offset = mono_class_interface_offset (klass, ic);
4670 int mcount = mono_class_get_method_count (ic);
4671 for (im_index = 0; im_index < mcount; im_index++) {
4672 MonoMethod *im = ic->methods [im_index];
4673 int im_slot = ic_offset + im->slot;
4675 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4676 continue;
4678 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
4679 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
4680 if (vtable [im_slot] == NULL) {
4681 print_unimplemented_interface_method_info (klass, ic, im, im_slot, overrides, onum);
4682 goto fail;
4688 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
4689 for (l = virt_methods; l; l = l->next) {
4690 cm = (MonoMethod *)l->data;
4692 * If the method is REUSE_SLOT, we must check in the
4693 * base class for a method to override.
4695 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
4696 int slot = -1;
4697 for (k = klass->parent; k ; k = k->parent) {
4698 gpointer k_iter;
4699 MonoMethod *m1;
4701 k_iter = NULL;
4702 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
4703 MonoMethodSignature *cmsig, *m1sig;
4705 cmsig = mono_method_signature (cm);
4706 m1sig = mono_method_signature (m1);
4708 if (!cmsig || !m1sig) {
4709 /* FIXME proper error message */
4710 mono_class_set_type_load_failure (klass, "");
4711 return;
4714 if (!strcmp(cm->name, m1->name) &&
4715 mono_metadata_signature_equal (cmsig, m1sig)) {
4717 if (mono_security_core_clr_enabled ())
4718 mono_security_core_clr_check_override (klass, cm, m1);
4720 slot = mono_method_get_vtable_slot (m1);
4721 if (slot == -1)
4722 goto fail;
4724 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
4725 char *body_name = mono_method_full_name (cm, TRUE);
4726 char *decl_name = mono_method_full_name (m1, TRUE);
4727 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4728 g_free (body_name);
4729 g_free (decl_name);
4730 goto fail;
4733 g_assert (cm->slot < max_vtsize);
4734 if (!override_map)
4735 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4736 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
4737 mono_method_full_name (m1, 1), m1,
4738 mono_method_full_name (cm, 1), cm));
4739 g_hash_table_insert (override_map, m1, cm);
4740 break;
4743 if (mono_class_has_failure (k))
4744 goto fail;
4746 if (slot >= 0)
4747 break;
4749 if (slot >= 0)
4750 cm->slot = slot;
4753 /*Non final newslot methods must be given a non-interface vtable slot*/
4754 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
4755 cm->slot = -1;
4757 if (cm->slot < 0)
4758 cm->slot = cur_slot++;
4760 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
4761 vtable [cm->slot] = cm;
4764 /* override non interface methods */
4765 for (i = 0; i < onum; i++) {
4766 MonoMethod *decl = overrides [i*2];
4767 if (!MONO_CLASS_IS_INTERFACE (decl->klass)) {
4768 g_assert (decl->slot != -1);
4769 vtable [decl->slot] = overrides [i*2 + 1];
4770 overrides [i * 2 + 1]->slot = decl->slot;
4771 if (!override_map)
4772 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4773 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
4774 mono_method_full_name (decl, 1), decl,
4775 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
4776 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
4778 if (mono_security_core_clr_enabled ())
4779 mono_security_core_clr_check_override (klass, vtable [decl->slot], decl);
4784 * If a method occupies more than one place in the vtable, and it is
4785 * overriden, then change the other occurances too.
4787 if (override_map) {
4788 MonoMethod *cm;
4790 for (i = 0; i < max_vtsize; ++i)
4791 if (vtable [i]) {
4792 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
4794 cm = (MonoMethod *)g_hash_table_lookup (override_map, vtable [i]);
4795 if (cm)
4796 vtable [i] = cm;
4799 g_hash_table_destroy (override_map);
4800 override_map = NULL;
4803 g_slist_free (virt_methods);
4804 virt_methods = NULL;
4806 /* Ensure that all vtable slots are filled with concrete instance methods */
4807 if (!mono_class_is_abstract (klass)) {
4808 for (i = 0; i < cur_slot; ++i) {
4809 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
4810 char *type_name = mono_type_get_full_name (klass);
4811 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
4812 mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
4813 g_free (type_name);
4814 g_free (method_name);
4815 return;
4820 if (mono_class_is_ginst (klass)) {
4821 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4823 mono_class_init (gklass);
4825 klass->vtable_size = MAX (gklass->vtable_size, cur_slot);
4826 } else {
4827 /* Check that the vtable_size value computed in mono_class_init () is correct */
4828 if (klass->vtable_size)
4829 g_assert (cur_slot == klass->vtable_size);
4830 klass->vtable_size = cur_slot;
4833 /* Try to share the vtable with our parent. */
4834 if (klass->parent && (klass->parent->vtable_size == klass->vtable_size) && (memcmp (klass->parent->vtable, vtable, sizeof (gpointer) * klass->vtable_size) == 0)) {
4835 mono_memory_barrier ();
4836 klass->vtable = klass->parent->vtable;
4837 } else {
4838 MonoMethod **tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * klass->vtable_size);
4839 memcpy (tmp, vtable, sizeof (gpointer) * klass->vtable_size);
4840 mono_memory_barrier ();
4841 klass->vtable = tmp;
4844 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass, klass->vtable, klass->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
4845 if (mono_print_vtable) {
4846 int icount = 0;
4848 print_implemented_interfaces (klass);
4850 for (i = 0; i <= max_iid; i++)
4851 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
4852 icount++;
4854 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&klass->byval_arg),
4855 klass->vtable_size, icount);
4857 for (i = 0; i < cur_slot; ++i) {
4858 MonoMethod *cm;
4860 cm = vtable [i];
4861 if (cm) {
4862 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
4863 mono_method_full_name (cm, TRUE));
4868 if (icount) {
4869 printf ("Interfaces %s.%s (max_iid = %d)\n", klass->name_space,
4870 klass->name, max_iid);
4872 for (i = 0; i < klass->interface_count; i++) {
4873 ic = klass->interfaces [i];
4874 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
4875 mono_class_interface_offset (klass, ic),
4876 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4879 for (k = klass->parent; k ; k = k->parent) {
4880 for (i = 0; i < k->interface_count; i++) {
4881 ic = k->interfaces [i];
4882 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
4883 mono_class_interface_offset (klass, ic),
4884 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4890 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass));
4891 return;
4893 fail:
4895 char *name = mono_type_get_full_name (klass);
4896 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
4897 g_free (name);
4898 if (override_map)
4899 g_hash_table_destroy (override_map);
4900 if (virt_methods)
4901 g_slist_free (virt_methods);
4906 * mono_method_get_vtable_slot:
4908 * Returns method->slot, computing it if neccesary. Return -1 on failure.
4909 * LOCKING: Acquires the loader lock.
4911 * FIXME Use proper MonoError machinery here.
4914 mono_method_get_vtable_slot (MonoMethod *method)
4916 if (method->slot == -1) {
4917 mono_class_setup_vtable (method->klass);
4918 if (mono_class_has_failure (method->klass))
4919 return -1;
4920 if (method->slot == -1) {
4921 MonoClass *gklass;
4922 int i, mcount;
4924 if (!mono_class_is_ginst (method->klass)) {
4925 g_assert (method->is_inflated);
4926 return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
4929 /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
4930 g_assert (mono_class_is_ginst (method->klass));
4931 gklass = mono_class_get_generic_class (method->klass)->container_class;
4932 mono_class_setup_methods (method->klass);
4933 g_assert (method->klass->methods);
4934 mcount = mono_class_get_method_count (method->klass);
4935 for (i = 0; i < mcount; ++i) {
4936 if (method->klass->methods [i] == method)
4937 break;
4939 g_assert (i < mcount);
4940 g_assert (gklass->methods);
4941 method->slot = gklass->methods [i]->slot;
4943 g_assert (method->slot != -1);
4945 return method->slot;
4949 * mono_method_get_vtable_index:
4950 * @method: a method
4952 * Returns the index into the runtime vtable to access the method or,
4953 * in the case of a virtual generic method, the virtual generic method
4954 * thunk. Returns -1 on failure.
4956 * FIXME Use proper MonoError machinery here.
4959 mono_method_get_vtable_index (MonoMethod *method)
4961 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
4962 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
4963 if (imethod->declaring->is_generic)
4964 return mono_method_get_vtable_slot (imethod->declaring);
4966 return mono_method_get_vtable_slot (method);
4969 static MonoMethod *default_ghc = NULL;
4970 static MonoMethod *default_finalize = NULL;
4971 static int finalize_slot = -1;
4972 static int ghc_slot = -1;
4974 static void
4975 initialize_object_slots (MonoClass *klass)
4977 int i;
4978 if (default_ghc)
4979 return;
4980 if (klass == mono_defaults.object_class) {
4981 mono_class_setup_vtable (klass);
4982 for (i = 0; i < klass->vtable_size; ++i) {
4983 MonoMethod *cm = klass->vtable [i];
4985 if (!strcmp (cm->name, "GetHashCode"))
4986 ghc_slot = i;
4987 else if (!strcmp (cm->name, "Finalize"))
4988 finalize_slot = i;
4991 g_assert (ghc_slot > 0);
4992 default_ghc = klass->vtable [ghc_slot];
4994 g_assert (finalize_slot > 0);
4995 default_finalize = klass->vtable [finalize_slot];
4999 typedef struct {
5000 MonoMethod *array_method;
5001 char *name;
5002 } GenericArrayMethodInfo;
5004 static int generic_array_method_num = 0;
5005 static GenericArrayMethodInfo *generic_array_method_info = NULL;
5007 static int
5008 generic_array_methods (MonoClass *klass)
5010 int i, count_generic = 0, mcount;
5011 GList *list = NULL, *tmp;
5012 if (generic_array_method_num)
5013 return generic_array_method_num;
5014 mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
5015 g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
5016 mcount = mono_class_get_method_count (klass->parent);
5017 for (i = 0; i < mcount; i++) {
5018 MonoMethod *m = klass->parent->methods [i];
5019 if (!strncmp (m->name, "InternalArray__", 15)) {
5020 count_generic++;
5021 list = g_list_prepend (list, m);
5024 list = g_list_reverse (list);
5025 generic_array_method_info = (GenericArrayMethodInfo *)mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
5026 i = 0;
5027 for (tmp = list; tmp; tmp = tmp->next) {
5028 const char *mname, *iname;
5029 gchar *name;
5030 MonoMethod *m = (MonoMethod *)tmp->data;
5031 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
5032 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
5034 generic_array_method_info [i].array_method = m;
5035 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
5036 iname = "System.Collections.Generic.ICollection`1.";
5037 mname = m->name + 27;
5038 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
5039 iname = "System.Collections.Generic.IEnumerable`1.";
5040 mname = m->name + 27;
5041 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
5042 iname = "System.Collections.Generic.IReadOnlyList`1.";
5043 mname = m->name + strlen (ireadonlylist_prefix);
5044 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
5045 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
5046 mname = m->name + strlen (ireadonlycollection_prefix);
5047 } else if (!strncmp (m->name, "InternalArray__", 15)) {
5048 iname = "System.Collections.Generic.IList`1.";
5049 mname = m->name + 15;
5050 } else {
5051 g_assert_not_reached ();
5054 name = (gchar *)mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
5055 strcpy (name, iname);
5056 strcpy (name + strlen (iname), mname);
5057 generic_array_method_info [i].name = name;
5058 i++;
5060 /*g_print ("array generic methods: %d\n", count_generic);*/
5062 generic_array_method_num = count_generic;
5063 g_list_free (list);
5064 return generic_array_method_num;
5067 static void
5068 setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos)
5070 MonoGenericContext tmp_context;
5071 int i;
5073 tmp_context.class_inst = NULL;
5074 tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst;
5075 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
5077 for (i = 0; i < generic_array_method_num; i++) {
5078 MonoError error;
5079 MonoMethod *m = generic_array_method_info [i].array_method;
5080 MonoMethod *inflated;
5082 inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, &error);
5083 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
5084 methods [pos++] = mono_marshal_get_generic_array_helper (klass, iface, generic_array_method_info [i].name, inflated);
5088 static char*
5089 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
5091 int null_length = strlen ("(null)");
5092 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
5093 char *s = (char *)mono_image_alloc (image, len);
5094 int result;
5096 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
5097 g_assert (result == len - 1);
5099 return s;
5103 * mono_class_init:
5104 * @klass: the class to initialize
5106 * Compute the instance_size, class_size and other infos that cannot be
5107 * computed at mono_class_get() time. Also compute vtable_size if possible.
5108 * Returns TRUE on success or FALSE if there was a problem in loading
5109 * the type (incorrect assemblies, missing assemblies, methods, etc).
5110 * Initializes the following fields in @klass:
5111 * - all the fields initialized by mono_class_init_sizes ()
5112 * - has_cctor
5113 * - ghcimpl
5114 * - inited
5116 * LOCKING: Acquires the loader lock.
5118 gboolean
5119 mono_class_init (MonoClass *klass)
5121 int i, vtable_size = 0, array_method_count = 0;
5122 MonoCachedClassInfo cached_info;
5123 gboolean has_cached_info;
5124 gboolean locked = FALSE;
5125 gboolean ghcimpl = FALSE;
5126 gboolean has_cctor = FALSE;
5127 int first_iface_slot = 0;
5129 g_assert (klass);
5131 /* Double-checking locking pattern */
5132 if (klass->inited || mono_class_has_failure (klass))
5133 return !mono_class_has_failure (klass);
5135 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
5138 * This function can recursively call itself.
5140 GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
5141 if (g_slist_find (init_list, klass)) {
5142 mono_class_set_type_load_failure (klass, "Recursive type definition detected");
5143 goto leave;
5145 init_list = g_slist_prepend (init_list, klass);
5146 mono_native_tls_set_value (init_pending_tls_id, init_list);
5149 * We want to avoid doing complicated work inside locks, so we compute all the required
5150 * information and write it to @klass inside a lock.
5153 if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
5154 mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
5155 goto leave;
5158 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
5159 MonoClass *element_class = klass->element_class;
5160 if (!element_class->inited)
5161 mono_class_init (element_class);
5162 if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
5163 goto leave;
5166 mono_stats.initialized_class_count++;
5168 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
5169 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5171 mono_class_init (gklass);
5172 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
5173 goto leave;
5175 mono_class_setup_interface_id (klass);
5178 if (klass->parent && !klass->parent->inited)
5179 mono_class_init (klass->parent);
5181 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
5183 /* Compute instance size etc. */
5184 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
5185 if (mono_class_has_failure (klass))
5186 goto leave;
5188 mono_class_setup_supertypes (klass);
5190 if (!default_ghc)
5191 initialize_object_slots (klass);
5194 * Initialize the rest of the data without creating a generic vtable if possible.
5195 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
5196 * also avoid computing a generic vtable.
5198 if (has_cached_info) {
5199 /* AOT case */
5200 vtable_size = cached_info.vtable_size;
5201 ghcimpl = cached_info.ghcimpl;
5202 has_cctor = cached_info.has_cctor;
5203 } else if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
5204 /* SZARRAY can have 2 vtable layouts, with and without the stelemref method.
5205 * The first slot if for array with.
5207 static int szarray_vtable_size[2] = { 0 };
5209 int slot = MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg) ? 0 : 1;
5211 /* SZARRAY case */
5212 if (!szarray_vtable_size [slot]) {
5213 mono_class_setup_vtable (klass);
5214 szarray_vtable_size [slot] = klass->vtable_size;
5215 vtable_size = klass->vtable_size;
5216 } else {
5217 vtable_size = szarray_vtable_size[slot];
5219 } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE (klass)) {
5220 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5222 /* Generic instance case */
5223 ghcimpl = gklass->ghcimpl;
5224 has_cctor = gklass->has_cctor;
5226 mono_class_setup_vtable (gklass);
5227 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
5228 goto leave;
5230 vtable_size = gklass->vtable_size;
5231 } else {
5232 /* General case */
5234 /* ghcimpl is not currently used
5235 klass->ghcimpl = 1;
5236 if (klass->parent) {
5237 MonoMethod *cmethod = klass->vtable [ghc_slot];
5238 if (cmethod->is_inflated)
5239 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5240 if (cmethod == default_ghc) {
5241 klass->ghcimpl = 0;
5246 /* C# doesn't allow interfaces to have cctors */
5247 if (!MONO_CLASS_IS_INTERFACE (klass) || klass->image != mono_defaults.corlib) {
5248 MonoMethod *cmethod = NULL;
5250 if (mono_class_is_ginst (klass)) {
5251 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5253 /* Generic instance case */
5254 ghcimpl = gklass->ghcimpl;
5255 has_cctor = gklass->has_cctor;
5256 } else if (klass->type_token && !image_is_dynamic(klass->image)) {
5257 cmethod = find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
5258 /* The find_method function ignores the 'flags' argument */
5259 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
5260 has_cctor = 1;
5261 } else {
5262 mono_class_setup_methods (klass);
5263 if (mono_class_has_failure (klass))
5264 goto leave;
5266 int mcount = mono_class_get_method_count (klass);
5267 for (i = 0; i < mcount; ++i) {
5268 MonoMethod *method = klass->methods [i];
5269 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
5270 (strcmp (".cctor", method->name) == 0)) {
5271 has_cctor = 1;
5272 break;
5279 if (klass->rank) {
5280 array_method_count = 3 + (klass->rank > 1? 2: 1);
5282 if (klass->interface_count) {
5283 int count_generic = generic_array_methods (klass);
5284 array_method_count += klass->interface_count * count_generic;
5288 if (klass->parent) {
5289 if (!klass->parent->vtable_size)
5290 mono_class_setup_vtable (klass->parent);
5291 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
5292 goto leave;
5293 g_assert (klass->parent->vtable_size);
5294 first_iface_slot = klass->parent->vtable_size;
5295 if (mono_class_need_stelemref_method (klass))
5296 ++first_iface_slot;
5300 * Do the actual changes to @klass inside the loader lock
5302 mono_loader_lock ();
5303 locked = TRUE;
5305 if (klass->inited || mono_class_has_failure (klass)) {
5306 mono_loader_unlock ();
5307 /* Somebody might have gotten in before us */
5308 return !mono_class_has_failure (klass);
5311 mono_stats.initialized_class_count++;
5313 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic)
5314 mono_stats.generic_class_count++;
5316 if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
5317 klass->nested_classes_inited = TRUE;
5318 klass->ghcimpl = ghcimpl;
5319 klass->has_cctor = has_cctor;
5320 if (vtable_size)
5321 klass->vtable_size = vtable_size;
5322 if (has_cached_info) {
5323 klass->has_finalize = cached_info.has_finalize;
5324 klass->has_finalize_inited = TRUE;
5326 if (klass->rank)
5327 mono_class_set_method_count (klass, array_method_count);
5329 mono_loader_unlock ();
5330 locked = FALSE;
5332 setup_interface_offsets (klass, first_iface_slot, TRUE);
5334 if (mono_security_core_clr_enabled ())
5335 mono_security_core_clr_check_inheritance (klass);
5337 if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
5338 mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
5340 goto leave;
5342 leave:
5343 init_list = g_slist_remove (init_list, klass);
5344 mono_native_tls_set_value (init_pending_tls_id, init_list);
5346 /* Because of the double-checking locking pattern */
5347 mono_memory_barrier ();
5348 klass->inited = 1;
5350 if (locked)
5351 mono_loader_unlock ();
5353 return !mono_class_has_failure (klass);
5357 * mono_class_has_finalizer:
5359 * Return whenever KLASS has a finalizer, initializing klass->has_finalizer in the
5360 * process.
5362 gboolean
5363 mono_class_has_finalizer (MonoClass *klass)
5365 gboolean has_finalize = FALSE;
5367 if (klass->has_finalize_inited)
5368 return klass->has_finalize;
5370 /* Interfaces and valuetypes are not supposed to have finalizers */
5371 if (!(MONO_CLASS_IS_INTERFACE (klass) || klass->valuetype)) {
5372 MonoMethod *cmethod = NULL;
5374 if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
5375 } else if (mono_class_is_ginst (klass)) {
5376 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5378 has_finalize = mono_class_has_finalizer (gklass);
5379 } else if (klass->parent && klass->parent->has_finalize) {
5380 has_finalize = TRUE;
5381 } else {
5382 if (klass->parent) {
5384 * Can't search in metadata for a method named Finalize, because that
5385 * ignores overrides.
5387 mono_class_setup_vtable (klass);
5388 if (mono_class_has_failure (klass))
5389 cmethod = NULL;
5390 else
5391 cmethod = klass->vtable [finalize_slot];
5394 if (cmethod) {
5395 g_assert (klass->vtable_size > finalize_slot);
5397 if (klass->parent) {
5398 if (cmethod->is_inflated)
5399 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5400 if (cmethod != default_finalize)
5401 has_finalize = TRUE;
5407 mono_image_lock (klass->image);
5409 if (!klass->has_finalize_inited) {
5410 klass->has_finalize = has_finalize ? 1 : 0;
5412 mono_memory_barrier ();
5413 klass->has_finalize_inited = TRUE;
5416 mono_image_unlock (klass->image);
5418 return klass->has_finalize;
5421 gboolean
5422 mono_is_corlib_image (MonoImage *image)
5424 return image == mono_defaults.corlib;
5428 * LOCKING: this assumes the loader lock is held
5430 void
5431 mono_class_setup_mono_type (MonoClass *klass)
5433 const char *name = klass->name;
5434 const char *nspace = klass->name_space;
5435 gboolean is_corlib = mono_is_corlib_image (klass->image);
5437 klass->this_arg.byref = 1;
5438 klass->this_arg.data.klass = klass;
5439 klass->this_arg.type = MONO_TYPE_CLASS;
5440 klass->byval_arg.data.klass = klass;
5441 klass->byval_arg.type = MONO_TYPE_CLASS;
5443 if (is_corlib && !strcmp (nspace, "System")) {
5444 if (!strcmp (name, "ValueType")) {
5446 * do not set the valuetype bit for System.ValueType.
5447 * klass->valuetype = 1;
5449 klass->blittable = TRUE;
5450 } else if (!strcmp (name, "Enum")) {
5452 * do not set the valuetype bit for System.Enum.
5453 * klass->valuetype = 1;
5455 klass->valuetype = 0;
5456 klass->enumtype = 0;
5457 } else if (!strcmp (name, "Object")) {
5458 klass->byval_arg.type = MONO_TYPE_OBJECT;
5459 klass->this_arg.type = MONO_TYPE_OBJECT;
5460 } else if (!strcmp (name, "String")) {
5461 klass->byval_arg.type = MONO_TYPE_STRING;
5462 klass->this_arg.type = MONO_TYPE_STRING;
5463 } else if (!strcmp (name, "TypedReference")) {
5464 klass->byval_arg.type = MONO_TYPE_TYPEDBYREF;
5465 klass->this_arg.type = MONO_TYPE_TYPEDBYREF;
5469 if (klass->valuetype) {
5470 int t = MONO_TYPE_VALUETYPE;
5472 if (is_corlib && !strcmp (nspace, "System")) {
5473 switch (*name) {
5474 case 'B':
5475 if (!strcmp (name, "Boolean")) {
5476 t = MONO_TYPE_BOOLEAN;
5477 } else if (!strcmp(name, "Byte")) {
5478 t = MONO_TYPE_U1;
5479 klass->blittable = TRUE;
5481 break;
5482 case 'C':
5483 if (!strcmp (name, "Char")) {
5484 t = MONO_TYPE_CHAR;
5486 break;
5487 case 'D':
5488 if (!strcmp (name, "Double")) {
5489 t = MONO_TYPE_R8;
5490 klass->blittable = TRUE;
5492 break;
5493 case 'I':
5494 if (!strcmp (name, "Int32")) {
5495 t = MONO_TYPE_I4;
5496 klass->blittable = TRUE;
5497 } else if (!strcmp(name, "Int16")) {
5498 t = MONO_TYPE_I2;
5499 klass->blittable = TRUE;
5500 } else if (!strcmp(name, "Int64")) {
5501 t = MONO_TYPE_I8;
5502 klass->blittable = TRUE;
5503 } else if (!strcmp(name, "IntPtr")) {
5504 t = MONO_TYPE_I;
5505 klass->blittable = TRUE;
5507 break;
5508 case 'S':
5509 if (!strcmp (name, "Single")) {
5510 t = MONO_TYPE_R4;
5511 klass->blittable = TRUE;
5512 } else if (!strcmp(name, "SByte")) {
5513 t = MONO_TYPE_I1;
5514 klass->blittable = TRUE;
5516 break;
5517 case 'U':
5518 if (!strcmp (name, "UInt32")) {
5519 t = MONO_TYPE_U4;
5520 klass->blittable = TRUE;
5521 } else if (!strcmp(name, "UInt16")) {
5522 t = MONO_TYPE_U2;
5523 klass->blittable = TRUE;
5524 } else if (!strcmp(name, "UInt64")) {
5525 t = MONO_TYPE_U8;
5526 klass->blittable = TRUE;
5527 } else if (!strcmp(name, "UIntPtr")) {
5528 t = MONO_TYPE_U;
5529 klass->blittable = TRUE;
5531 break;
5532 case 'T':
5533 if (!strcmp (name, "TypedReference")) {
5534 t = MONO_TYPE_TYPEDBYREF;
5535 klass->blittable = TRUE;
5537 break;
5538 case 'V':
5539 if (!strcmp (name, "Void")) {
5540 t = MONO_TYPE_VOID;
5542 break;
5543 default:
5544 break;
5547 klass->byval_arg.type = (MonoTypeEnum)t;
5548 klass->this_arg.type = (MonoTypeEnum)t;
5551 if (MONO_CLASS_IS_INTERFACE (klass))
5552 klass->interface_id = mono_get_unique_iid (klass);
5555 #ifndef DISABLE_COM
5557 * COM initialization is delayed until needed.
5558 * However when a [ComImport] attribute is present on a type it will trigger
5559 * the initialization. This is not a problem unless the BCL being executed
5560 * lacks the types that COM depends on (e.g. Variant on Silverlight).
5562 static void
5563 init_com_from_comimport (MonoClass *klass)
5565 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
5566 if (mono_security_core_clr_enabled ()) {
5567 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
5568 if (!mono_security_core_clr_determine_platform_image (klass->image)) {
5569 /* but it can not be made available for application (i.e. user code) since all COM calls
5570 * are considered native calls. In this case we fail with a TypeLoadException (just like
5571 * Silverlight 2 does */
5572 mono_class_set_type_load_failure (klass, "");
5573 return;
5577 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
5579 #endif /*DISABLE_COM*/
5582 * LOCKING: this assumes the loader lock is held
5584 void
5585 mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
5587 gboolean system_namespace;
5588 gboolean is_corlib = mono_is_corlib_image (klass->image);
5590 system_namespace = !strcmp (klass->name_space, "System") && is_corlib;
5592 /* if root of the hierarchy */
5593 if (system_namespace && !strcmp (klass->name, "Object")) {
5594 klass->parent = NULL;
5595 klass->instance_size = sizeof (MonoObject);
5596 return;
5598 if (!strcmp (klass->name, "<Module>")) {
5599 klass->parent = NULL;
5600 klass->instance_size = 0;
5601 return;
5604 if (!MONO_CLASS_IS_INTERFACE (klass)) {
5605 /* Imported COM Objects always derive from __ComObject. */
5606 #ifndef DISABLE_COM
5607 if (MONO_CLASS_IS_IMPORT (klass)) {
5608 init_com_from_comimport (klass);
5609 if (parent == mono_defaults.object_class)
5610 parent = mono_class_get_com_object_class ();
5612 #endif
5613 if (!parent) {
5614 /* set the parent to something useful and safe, but mark the type as broken */
5615 parent = mono_defaults.object_class;
5616 mono_class_set_type_load_failure (klass, "");
5617 g_assert (parent);
5620 klass->parent = parent;
5622 if (mono_class_is_ginst (parent) && !parent->name) {
5624 * If the parent is a generic instance, we may get
5625 * called before it is fully initialized, especially
5626 * before it has its name.
5628 return;
5631 #ifndef DISABLE_REMOTING
5632 klass->marshalbyref = parent->marshalbyref;
5633 klass->contextbound = parent->contextbound;
5634 #endif
5636 klass->delegate = parent->delegate;
5638 if (MONO_CLASS_IS_IMPORT (klass) || mono_class_is_com_object (parent))
5639 mono_class_set_is_com_object (klass);
5641 if (system_namespace) {
5642 #ifndef DISABLE_REMOTING
5643 if (klass->name [0] == 'M' && !strcmp (klass->name, "MarshalByRefObject"))
5644 klass->marshalbyref = 1;
5646 if (klass->name [0] == 'C' && !strcmp (klass->name, "ContextBoundObject"))
5647 klass->contextbound = 1;
5648 #endif
5649 if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate"))
5650 klass->delegate = 1;
5653 if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) &&
5654 (strcmp (klass->parent->name_space, "System") == 0)))
5655 klass->valuetype = 1;
5656 if (mono_is_corlib_image (klass->parent->image) && ((strcmp (klass->parent->name, "Enum") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) {
5657 klass->valuetype = klass->enumtype = 1;
5659 /*klass->enumtype = klass->parent->enumtype; */
5660 } else {
5661 /* initialize com types if COM interfaces are present */
5662 #ifndef DISABLE_COM
5663 if (MONO_CLASS_IS_IMPORT (klass))
5664 init_com_from_comimport (klass);
5665 #endif
5666 klass->parent = NULL;
5672 * mono_class_setup_supertypes:
5673 * @class: a class
5675 * Build the data structure needed to make fast type checks work.
5676 * This currently sets two fields in @class:
5677 * - idepth: distance between @class and System.Object in the type
5678 * hierarchy + 1
5679 * - supertypes: array of classes: each element has a class in the hierarchy
5680 * starting from @class up to System.Object
5682 * LOCKING: Acquires the loader lock.
5684 void
5685 mono_class_setup_supertypes (MonoClass *klass)
5687 int ms, idepth;
5688 MonoClass **supertypes;
5690 mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes);
5691 if (supertypes)
5692 return;
5694 if (klass->parent && !klass->parent->supertypes)
5695 mono_class_setup_supertypes (klass->parent);
5696 if (klass->parent)
5697 idepth = klass->parent->idepth + 1;
5698 else
5699 idepth = 1;
5701 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, idepth);
5702 supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
5704 if (klass->parent) {
5705 CHECKED_METADATA_WRITE_PTR ( supertypes [idepth - 1] , klass );
5707 int supertype_idx;
5708 for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
5709 CHECKED_METADATA_WRITE_PTR ( supertypes [supertype_idx] , klass->parent->supertypes [supertype_idx] );
5710 } else {
5711 CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
5714 mono_memory_barrier ();
5716 mono_loader_lock ();
5717 klass->idepth = idepth;
5718 /* Needed so idepth is visible before supertypes is set */
5719 mono_memory_barrier ();
5720 klass->supertypes = supertypes;
5721 mono_loader_unlock ();
5724 static gboolean
5725 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
5727 MonoClass *gtd = (MonoClass*)user_data;
5728 /* Only try to fix generic instances of @gtd */
5729 if (mono_class_get_generic_class (gclass)->container_class != gtd)
5730 return FALSE;
5732 /* Check if the generic instance has no parent. */
5733 if (gtd->parent && !gclass->parent)
5734 mono_generic_class_setup_parent (gclass, gtd);
5736 return TRUE;
5739 static void
5740 mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
5742 mono_class_set_type_load_failure (klass, "%s", msg);
5743 mono_error_set_type_load_class (error, klass, "%s", msg);
5747 * mono_class_create_from_typedef:
5748 * @image: image where the token is valid
5749 * @type_token: typedef token
5750 * @error: used to return any error found while creating the type
5752 * Create the MonoClass* representing the specified type token.
5753 * @type_token must be a TypeDef token.
5755 * FIXME: don't return NULL on failure, just the the caller figure it out.
5757 static MonoClass *
5758 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
5760 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
5761 MonoClass *klass, *parent = NULL;
5762 guint32 cols [MONO_TYPEDEF_SIZE];
5763 guint32 cols_next [MONO_TYPEDEF_SIZE];
5764 guint tidx = mono_metadata_token_index (type_token);
5765 MonoGenericContext *context = NULL;
5766 const char *name, *nspace;
5767 guint icount = 0;
5768 MonoClass **interfaces;
5769 guint32 field_last, method_last;
5770 guint32 nesting_tokeen;
5772 mono_error_init (error);
5774 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
5775 mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
5776 return NULL;
5779 mono_loader_lock ();
5781 if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
5782 mono_loader_unlock ();
5783 return klass;
5786 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
5788 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
5789 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
5791 if (mono_metadata_has_generic_params (image, type_token)) {
5792 klass = mono_image_alloc0 (image, sizeof (MonoClassGtd));
5793 klass->class_kind = MONO_CLASS_GTD;
5794 classes_size += sizeof (MonoClassGtd);
5795 ++class_gtd_count;
5796 } else {
5797 klass = mono_image_alloc0 (image, sizeof (MonoClassDef));
5798 klass->class_kind = MONO_CLASS_DEF;
5799 classes_size += sizeof (MonoClassDef);
5800 ++class_def_count;
5803 klass->name = name;
5804 klass->name_space = nspace;
5806 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
5808 klass->image = image;
5809 klass->type_token = type_token;
5810 mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
5812 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
5815 * Check whether we're a generic type definition.
5817 if (mono_class_is_gtd (klass)) {
5818 MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
5819 generic_container->owner.klass = klass;
5820 generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
5821 context = &generic_container->context;
5822 mono_class_set_generic_container (klass, generic_container);
5823 enable_gclass_recording ();
5826 if (cols [MONO_TYPEDEF_EXTENDS]) {
5827 MonoClass *tmp;
5828 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
5830 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
5831 /*WARNING: this must satisfy mono_metadata_type_hash*/
5832 klass->this_arg.byref = 1;
5833 klass->this_arg.data.klass = klass;
5834 klass->this_arg.type = MONO_TYPE_CLASS;
5835 klass->byval_arg.data.klass = klass;
5836 klass->byval_arg.type = MONO_TYPE_CLASS;
5838 parent = mono_class_get_checked (image, parent_token, error);
5839 if (parent && context) /* Always inflate */
5840 parent = mono_class_inflate_generic_class_checked (parent, context, error);
5842 if (parent == NULL) {
5843 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5844 goto parent_failure;
5847 for (tmp = parent; tmp; tmp = tmp->parent) {
5848 if (tmp == klass) {
5849 mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
5850 goto parent_failure;
5852 if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
5853 mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
5854 goto parent_failure;
5859 mono_class_setup_parent (klass, parent);
5861 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
5862 mono_class_setup_mono_type (klass);
5864 if (mono_class_is_gtd (klass))
5865 disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
5868 * This might access klass->byval_arg for recursion generated by generic constraints,
5869 * so it has to come after setup_mono_type ().
5871 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
5872 klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
5873 if (!mono_error_ok (error)) {
5874 /*FIXME implement a mono_class_set_failure_from_mono_error */
5875 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5876 mono_loader_unlock ();
5877 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5878 return NULL;
5882 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
5883 klass->unicode = 1;
5885 #ifdef HOST_WIN32
5886 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
5887 klass->unicode = 1;
5888 #endif
5890 klass->cast_class = klass->element_class = klass;
5892 if (!klass->enumtype) {
5893 if (!mono_metadata_interfaces_from_typedef_full (
5894 image, type_token, &interfaces, &icount, FALSE, context, error)){
5896 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5897 mono_loader_unlock ();
5898 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5899 return NULL;
5902 /* This is required now that it is possible for more than 2^16 interfaces to exist. */
5903 g_assert(icount <= 65535);
5905 klass->interfaces = interfaces;
5906 klass->interface_count = icount;
5907 klass->interfaces_inited = 1;
5910 /*g_print ("Load class %s\n", name);*/
5913 * Compute the field and method lists
5915 int first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
5916 mono_class_set_first_field_idx (klass, first_field_idx);
5917 int first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
5918 mono_class_set_first_method_idx (klass, first_method_idx);
5920 if (tt->rows > tidx){
5921 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
5922 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
5923 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
5924 } else {
5925 field_last = image->tables [MONO_TABLE_FIELD].rows;
5926 method_last = image->tables [MONO_TABLE_METHOD].rows;
5929 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
5930 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
5931 mono_class_set_field_count (klass, field_last - first_field_idx);
5932 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
5933 mono_class_set_method_count (klass, method_last - first_method_idx);
5935 /* reserve space to store vector pointer in arrays */
5936 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
5937 klass->instance_size += 2 * sizeof (gpointer);
5938 g_assert (mono_class_get_field_count (klass) == 0);
5941 if (klass->enumtype) {
5942 MonoType *enum_basetype = mono_class_find_enum_basetype (klass, error);
5943 if (!enum_basetype) {
5944 /*set it to a default value as the whole runtime can't handle this to be null*/
5945 klass->cast_class = klass->element_class = mono_defaults.int32_class;
5946 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5947 mono_loader_unlock ();
5948 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5949 return NULL;
5951 klass->cast_class = klass->element_class = mono_class_from_mono_type (enum_basetype);
5955 * If we're a generic type definition, load the constraints.
5956 * We must do this after the class has been constructed to make certain recursive scenarios
5957 * work.
5959 if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
5960 mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
5961 mono_loader_unlock ();
5962 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5963 return NULL;
5966 if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
5967 if (!strncmp (name, "Vector", 6))
5968 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");
5971 mono_loader_unlock ();
5973 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
5975 return klass;
5977 parent_failure:
5978 mono_class_setup_mono_type (klass);
5979 mono_loader_unlock ();
5980 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5981 return NULL;
5984 /** Is klass a Nullable<T> ginst? */
5985 gboolean
5986 mono_class_is_nullable (MonoClass *klass)
5988 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
5989 return gklass && gklass->container_class == mono_defaults.generic_nullable_class;
5993 /** if klass is T? return T */
5994 MonoClass*
5995 mono_class_get_nullable_param (MonoClass *klass)
5997 g_assert (mono_class_is_nullable (klass));
5998 return mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
6001 static void
6002 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
6004 if (gtd->parent) {
6005 MonoError error;
6006 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
6008 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
6009 if (!mono_error_ok (&error)) {
6010 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
6011 klass->parent = mono_defaults.object_class;
6012 mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (&error));
6013 mono_error_cleanup (&error);
6016 if (klass->parent)
6017 mono_class_setup_parent (klass, klass->parent);
6019 if (klass->enumtype) {
6020 klass->cast_class = gtd->cast_class;
6021 klass->element_class = gtd->element_class;
6027 * Create the `MonoClass' for an instantiation of a generic type.
6028 * We only do this if we actually need it.
6030 MonoClass*
6031 mono_generic_class_get_class (MonoGenericClass *gclass)
6033 MonoClass *klass, *gklass;
6035 if (gclass->cached_class)
6036 return gclass->cached_class;
6038 mono_loader_lock ();
6039 if (gclass->cached_class) {
6040 mono_loader_unlock ();
6041 return gclass->cached_class;
6044 klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
6046 gklass = gclass->container_class;
6048 if (record_gclass_instantiation > 0)
6049 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
6051 if (gklass->nested_in) {
6052 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
6053 klass->nested_in = gklass->nested_in;
6056 klass->name = gklass->name;
6057 klass->name_space = gklass->name_space;
6059 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
6061 klass->image = gklass->image;
6062 klass->type_token = gklass->type_token;
6064 klass->class_kind = MONO_CLASS_GINST;
6065 //FIXME add setter
6066 ((MonoClassGenericInst*)klass)->generic_class = gclass;
6068 klass->byval_arg.type = MONO_TYPE_GENERICINST;
6069 klass->this_arg.type = klass->byval_arg.type;
6070 klass->this_arg.data.generic_class = klass->byval_arg.data.generic_class = gclass;
6071 klass->this_arg.byref = TRUE;
6072 klass->enumtype = gklass->enumtype;
6073 klass->valuetype = gklass->valuetype;
6075 klass->cast_class = klass->element_class = klass;
6077 if (mono_class_is_nullable (klass))
6078 klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
6081 * We're not interested in the nested classes of a generic instance.
6082 * We use the generic type definition to look for nested classes.
6085 mono_generic_class_setup_parent (klass, gklass);
6087 if (gclass->is_dynamic) {
6089 * 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.
6090 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
6091 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
6093 if (!gklass->wastypebuilder)
6094 klass->inited = 1;
6096 mono_class_setup_supertypes (klass);
6098 if (klass->enumtype) {
6100 * For enums, gklass->fields might not been set, but instance_size etc. is
6101 * already set in mono_reflection_create_internal_class (). For non-enums,
6102 * these will be computed normally in mono_class_layout_fields ().
6104 klass->instance_size = gklass->instance_size;
6105 klass->sizes.class_size = gklass->sizes.class_size;
6106 mono_memory_barrier ();
6107 klass->size_inited = 1;
6111 mono_memory_barrier ();
6112 gclass->cached_class = klass;
6114 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6116 ++class_ginst_count;
6117 inflated_classes_size += sizeof (MonoClassGenericInst);
6119 mono_loader_unlock ();
6121 return klass;
6124 static MonoImage *
6125 get_image_for_container (MonoGenericContainer *container)
6127 MonoImage *result;
6128 if (container->is_anonymous) {
6129 result = container->owner.image;
6130 } else {
6131 MonoClass *klass;
6132 if (container->is_method) {
6133 MonoMethod *method = container->owner.method;
6134 g_assert_checked (method);
6135 klass = method->klass;
6136 } else {
6137 klass = container->owner.klass;
6139 g_assert_checked (klass);
6140 result = klass->image;
6142 g_assert (result);
6143 return result;
6146 MonoImage *
6147 get_image_for_generic_param (MonoGenericParam *param)
6149 MonoGenericContainer *container = mono_generic_param_owner (param);
6150 g_assert_checked (container);
6151 return get_image_for_container (container);
6154 // Make a string in the designated image consisting of a single integer.
6155 #define INT_STRING_SIZE 16
6156 char *
6157 make_generic_name_string (MonoImage *image, int num)
6159 char *name = (char *)mono_image_alloc0 (image, INT_STRING_SIZE);
6160 g_snprintf (name, INT_STRING_SIZE, "%d", num);
6161 return name;
6164 // This is called by mono_class_from_generic_parameter_internal when a new class must be created.
6165 // pinfo is derived from param by the caller for us.
6166 static MonoClass*
6167 make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
6169 MonoClass *klass, **ptr;
6170 int count, pos, i;
6171 MonoGenericContainer *container = mono_generic_param_owner (param);
6172 g_assert_checked (container);
6174 MonoImage *image = get_image_for_container (container);
6175 gboolean is_mvar = container->is_method;
6176 gboolean is_anonymous = container->is_anonymous;
6178 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
6179 klass->class_kind = MONO_CLASS_GPARAM;
6180 classes_size += sizeof (MonoClassGenericParam);
6181 ++class_gparam_count;
6183 if (pinfo) {
6184 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
6185 } else {
6186 int n = mono_generic_param_num (param);
6187 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->name , make_generic_name_string (image, n) );
6190 if (is_anonymous) {
6191 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , "" );
6192 } else if (is_mvar) {
6193 MonoMethod *omethod = container->owner.method;
6194 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , (omethod && omethod->klass) ? omethod->klass->name_space : "" );
6195 } else {
6196 MonoClass *oklass = container->owner.klass;
6197 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
6200 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
6202 // Count non-NULL items in pinfo->constraints
6203 count = 0;
6204 if (pinfo)
6205 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
6208 pos = 0;
6209 if ((count > 0) && !MONO_CLASS_IS_INTERFACE (pinfo->constraints [0])) {
6210 CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
6211 pos++;
6212 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
6213 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
6214 } else {
6215 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
6218 if (count - pos > 0) {
6219 klass->interface_count = count - pos;
6220 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->interfaces , (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos)) );
6221 klass->interfaces_inited = TRUE;
6222 for (i = pos; i < count; i++)
6223 CHECKED_METADATA_WRITE_PTR ( klass->interfaces [i - pos] , pinfo->constraints [i] );
6226 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->image , image );
6228 klass->inited = TRUE;
6229 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
6230 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
6232 klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
6233 klass->this_arg.type = klass->byval_arg.type;
6234 CHECKED_METADATA_WRITE_PTR ( klass->this_arg.data.generic_param , param );
6235 CHECKED_METADATA_WRITE_PTR ( klass->byval_arg.data.generic_param , param );
6236 klass->this_arg.byref = TRUE;
6238 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
6239 klass->sizes.generic_param_token = pinfo ? pinfo->token : 0;
6241 /*Init these fields to sane values*/
6242 klass->min_align = 1;
6244 * This makes sure the the value size of this class is equal to the size of the types the gparam is
6245 * constrained to, the JIT depends on this.
6247 klass->instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
6248 mono_memory_barrier ();
6249 klass->size_inited = 1;
6251 mono_class_setup_supertypes (klass);
6253 if (count - pos > 0) {
6254 mono_class_setup_vtable (klass->parent);
6255 if (mono_class_has_failure (klass->parent))
6256 mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
6257 else
6258 setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
6261 return klass;
6264 #define FAST_CACHE_SIZE 16
6267 * get_anon_gparam_class and set_anon_gparam_class are helpers for mono_class_from_generic_parameter_internal.
6268 * The latter will sometimes create MonoClasses for anonymous generic params. To prevent this being wasteful,
6269 * we cache the MonoClasses.
6270 * FIXME: It would be better to instead cache anonymous MonoGenericParams, and allow anonymous params to point directly to classes using the pklass field.
6271 * LOCKING: Takes the image lock depending on @take_lock.
6273 static MonoClass *
6274 get_anon_gparam_class (MonoGenericParam *param, gboolean take_lock)
6276 int n = mono_generic_param_num (param);
6277 MonoImage *image = get_image_for_generic_param (param);
6278 gboolean is_mvar = mono_generic_param_owner (param)->is_method;
6279 MonoClass *klass = NULL;
6280 GHashTable *ht;
6282 g_assert (image);
6284 // For params with a small num and no constraints, we use a "fast" cache which does simple num lookup in an array.
6285 // For high numbers or constraints we have to use pointer hashes.
6286 if (param->gshared_constraint) {
6287 ht = is_mvar ? image->mvar_cache_constrained : image->var_cache_constrained;
6288 if (ht) {
6289 if (take_lock)
6290 mono_image_lock (image);
6291 klass = (MonoClass *)g_hash_table_lookup (ht, param);
6292 if (take_lock)
6293 mono_image_unlock (image);
6295 return klass;
6298 if (n < FAST_CACHE_SIZE) {
6299 if (is_mvar)
6300 return image->mvar_cache_fast ? image->mvar_cache_fast [n] : NULL;
6301 else
6302 return image->var_cache_fast ? image->var_cache_fast [n] : NULL;
6303 } else {
6304 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6305 if (ht) {
6306 if (take_lock)
6307 mono_image_lock (image);
6308 klass = (MonoClass *)g_hash_table_lookup (ht, GINT_TO_POINTER (n));
6309 if (take_lock)
6310 mono_image_unlock (image);
6312 return klass;
6317 * LOCKING: Image lock (param->image) must be held
6319 static void
6320 set_anon_gparam_class (MonoGenericParam *param, MonoClass *klass)
6322 int n = mono_generic_param_num (param);
6323 MonoImage *image = get_image_for_generic_param (param);
6324 gboolean is_mvar = mono_generic_param_owner (param)->is_method;
6326 g_assert (image);
6328 if (param->gshared_constraint) {
6329 GHashTable *ht = is_mvar ? image->mvar_cache_constrained : image->var_cache_constrained;
6330 if (!ht) {
6331 ht = g_hash_table_new ((GHashFunc)mono_metadata_generic_param_hash, (GEqualFunc)mono_metadata_generic_param_equal);
6332 mono_memory_barrier ();
6333 if (is_mvar)
6334 image->mvar_cache_constrained = ht;
6335 else
6336 image->var_cache_constrained = ht;
6338 g_hash_table_insert (ht, param, klass);
6339 } else if (n < FAST_CACHE_SIZE) {
6340 if (is_mvar) {
6341 /* Requires locking to avoid droping an already published class */
6342 if (!image->mvar_cache_fast)
6343 image->mvar_cache_fast = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6344 image->mvar_cache_fast [n] = klass;
6345 } else {
6346 if (!image->var_cache_fast)
6347 image->var_cache_fast = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6348 image->var_cache_fast [n] = klass;
6350 } else {
6351 GHashTable *ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6352 if (!ht) {
6353 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6354 if (!ht) {
6355 ht = g_hash_table_new (NULL, NULL);
6356 mono_memory_barrier ();
6357 if (is_mvar)
6358 image->mvar_cache_slow = ht;
6359 else
6360 image->var_cache_slow = ht;
6363 g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
6368 * LOCKING: Acquires the image lock (@image).
6370 MonoClass *
6371 mono_class_from_generic_parameter_internal (MonoGenericParam *param)
6373 MonoImage *image = get_image_for_generic_param (param);
6374 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
6375 MonoClass *klass, *klass2;
6377 // If a klass already exists for this object and is cached, return it.
6378 if (pinfo) // Non-anonymous
6379 klass = pinfo->pklass;
6380 else // Anonymous
6381 klass = get_anon_gparam_class (param, TRUE);
6383 if (klass)
6384 return klass;
6386 // Create a new klass
6387 klass = make_generic_param_class (param, pinfo);
6389 // Now we need to cache the klass we created.
6390 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
6391 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
6392 // and allow our newly-created klass object to just leak.
6393 mono_memory_barrier ();
6395 mono_image_lock (image);
6397 // Here "klass2" refers to the klass potentially created by the other thread.
6398 if (pinfo) // Repeat check from above
6399 klass2 = pinfo->pklass;
6400 else
6401 klass2 = get_anon_gparam_class (param, FALSE);
6403 if (klass2) {
6404 klass = klass2;
6405 } else {
6406 // Cache here
6407 if (pinfo)
6408 pinfo->pklass = klass;
6409 else
6410 set_anon_gparam_class (param, klass);
6412 mono_image_unlock (image);
6414 /* FIXME: Should this go inside 'make_generic_param_klass'? */
6415 if (klass2)
6416 mono_profiler_class_loaded (klass2, MONO_PROFILE_FAILED); // Alert profiler about botched class create
6417 else
6418 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6420 return klass;
6424 * mono_class_from_generic_parameter:
6425 * @param: Parameter to find/construct a class for.
6426 * @arg2: Is ignored.
6427 * @arg3: Is ignored.
6429 MonoClass *
6430 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GNUC_UNUSED, gboolean arg3 G_GNUC_UNUSED)
6432 return mono_class_from_generic_parameter_internal (param);
6436 MonoClass *
6437 mono_ptr_class_get (MonoType *type)
6439 MonoClass *result;
6440 MonoClass *el_class;
6441 MonoImage *image;
6442 char *name;
6444 el_class = mono_class_from_mono_type (type);
6445 image = el_class->image;
6447 mono_image_lock (image);
6448 if (image->ptr_cache) {
6449 if ((result = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
6450 mono_image_unlock (image);
6451 return result;
6454 mono_image_unlock (image);
6456 result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
6458 classes_size += sizeof (MonoClassPointer);
6459 ++class_pointer_count;
6461 result->parent = NULL; /* no parent for PTR types */
6462 result->name_space = el_class->name_space;
6463 name = g_strdup_printf ("%s*", el_class->name);
6464 result->name = mono_image_strdup (image, name);
6465 result->class_kind = MONO_CLASS_POINTER;
6466 g_free (name);
6468 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6470 result->image = el_class->image;
6471 result->inited = TRUE;
6472 result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
6473 result->cast_class = result->element_class = el_class;
6474 result->blittable = TRUE;
6476 result->byval_arg.type = MONO_TYPE_PTR;
6477 result->this_arg.type = result->byval_arg.type;
6478 result->this_arg.data.type = result->byval_arg.data.type = &result->element_class->byval_arg;
6479 result->this_arg.byref = TRUE;
6481 mono_class_setup_supertypes (result);
6483 mono_image_lock (image);
6484 if (image->ptr_cache) {
6485 MonoClass *result2;
6486 if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
6487 mono_image_unlock (image);
6488 mono_profiler_class_loaded (result, MONO_PROFILE_FAILED);
6489 return result2;
6491 } else {
6492 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6494 g_hash_table_insert (image->ptr_cache, el_class, result);
6495 mono_image_unlock (image);
6497 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6499 return result;
6502 static MonoClass *
6503 mono_fnptr_class_get (MonoMethodSignature *sig)
6505 MonoClass *result;
6506 static GHashTable *ptr_hash = NULL;
6508 /* FIXME: These should be allocate from a mempool as well, but which one ? */
6510 mono_loader_lock ();
6512 if (!ptr_hash)
6513 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
6515 if ((result = (MonoClass *)g_hash_table_lookup (ptr_hash, sig))) {
6516 mono_loader_unlock ();
6517 return result;
6519 result = g_new0 (MonoClass, 1);
6521 classes_size += sizeof (MonoClassPointer);
6522 ++class_pointer_count;
6524 result->parent = NULL; /* no parent for PTR types */
6525 result->name_space = "System";
6526 result->name = "MonoFNPtrFakeClass";
6527 result->class_kind = MONO_CLASS_POINTER;
6529 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6531 result->image = mono_defaults.corlib; /* need to fix... */
6532 result->inited = TRUE;
6533 result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
6534 result->cast_class = result->element_class = result;
6535 result->blittable = TRUE;
6537 result->byval_arg.type = MONO_TYPE_FNPTR;
6538 result->this_arg.type = result->byval_arg.type;
6539 result->this_arg.data.method = result->byval_arg.data.method = sig;
6540 result->this_arg.byref = TRUE;
6541 result->blittable = TRUE;
6543 mono_class_setup_supertypes (result);
6545 g_hash_table_insert (ptr_hash, sig, result);
6547 mono_loader_unlock ();
6549 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6551 return result;
6555 * mono_class_from_mono_type:
6556 * @type: describes the type to return
6558 * This returns a MonoClass for the specified MonoType, the value is never NULL.
6560 MonoClass *
6561 mono_class_from_mono_type (MonoType *type)
6563 switch (type->type) {
6564 case MONO_TYPE_OBJECT:
6565 return type->data.klass? type->data.klass: mono_defaults.object_class;
6566 case MONO_TYPE_VOID:
6567 return type->data.klass? type->data.klass: mono_defaults.void_class;
6568 case MONO_TYPE_BOOLEAN:
6569 return type->data.klass? type->data.klass: mono_defaults.boolean_class;
6570 case MONO_TYPE_CHAR:
6571 return type->data.klass? type->data.klass: mono_defaults.char_class;
6572 case MONO_TYPE_I1:
6573 return type->data.klass? type->data.klass: mono_defaults.sbyte_class;
6574 case MONO_TYPE_U1:
6575 return type->data.klass? type->data.klass: mono_defaults.byte_class;
6576 case MONO_TYPE_I2:
6577 return type->data.klass? type->data.klass: mono_defaults.int16_class;
6578 case MONO_TYPE_U2:
6579 return type->data.klass? type->data.klass: mono_defaults.uint16_class;
6580 case MONO_TYPE_I4:
6581 return type->data.klass? type->data.klass: mono_defaults.int32_class;
6582 case MONO_TYPE_U4:
6583 return type->data.klass? type->data.klass: mono_defaults.uint32_class;
6584 case MONO_TYPE_I:
6585 return type->data.klass? type->data.klass: mono_defaults.int_class;
6586 case MONO_TYPE_U:
6587 return type->data.klass? type->data.klass: mono_defaults.uint_class;
6588 case MONO_TYPE_I8:
6589 return type->data.klass? type->data.klass: mono_defaults.int64_class;
6590 case MONO_TYPE_U8:
6591 return type->data.klass? type->data.klass: mono_defaults.uint64_class;
6592 case MONO_TYPE_R4:
6593 return type->data.klass? type->data.klass: mono_defaults.single_class;
6594 case MONO_TYPE_R8:
6595 return type->data.klass? type->data.klass: mono_defaults.double_class;
6596 case MONO_TYPE_STRING:
6597 return type->data.klass? type->data.klass: mono_defaults.string_class;
6598 case MONO_TYPE_TYPEDBYREF:
6599 return type->data.klass? type->data.klass: mono_defaults.typed_reference_class;
6600 case MONO_TYPE_ARRAY:
6601 return mono_bounded_array_class_get (type->data.array->eklass, type->data.array->rank, TRUE);
6602 case MONO_TYPE_PTR:
6603 return mono_ptr_class_get (type->data.type);
6604 case MONO_TYPE_FNPTR:
6605 return mono_fnptr_class_get (type->data.method);
6606 case MONO_TYPE_SZARRAY:
6607 return mono_array_class_get (type->data.klass, 1);
6608 case MONO_TYPE_CLASS:
6609 case MONO_TYPE_VALUETYPE:
6610 return type->data.klass;
6611 case MONO_TYPE_GENERICINST:
6612 return mono_generic_class_get_class (type->data.generic_class);
6613 case MONO_TYPE_MVAR:
6614 case MONO_TYPE_VAR:
6615 return mono_class_from_generic_parameter_internal (type->data.generic_param);
6616 default:
6617 g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
6618 g_assert_not_reached ();
6621 // Yes, this returns NULL, even if it is documented as not doing so, but there
6622 // is no way for the code to make it this far, due to the assert above.
6623 return NULL;
6627 * mono_type_retrieve_from_typespec
6628 * @image: context where the image is created
6629 * @type_spec: typespec token
6630 * @context: the generic context used to evaluate generic instantiations in
6632 static MonoType *
6633 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
6635 MonoType *t = mono_type_create_from_typespec_checked (image, type_spec, error);
6637 *did_inflate = FALSE;
6639 if (!t)
6640 return NULL;
6642 if (context && (context->class_inst || context->method_inst)) {
6643 MonoType *inflated = inflate_generic_type (NULL, t, context, error);
6645 if (!mono_error_ok (error)) {
6646 return NULL;
6649 if (inflated) {
6650 t = inflated;
6651 *did_inflate = TRUE;
6654 return t;
6658 * mono_class_create_from_typespec
6659 * @image: context where the image is created
6660 * @type_spec: typespec token
6661 * @context: the generic context used to evaluate generic instantiations in
6663 static MonoClass *
6664 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
6666 MonoClass *ret;
6667 gboolean inflated = FALSE;
6668 MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
6669 return_val_if_nok (error, NULL);
6670 ret = mono_class_from_mono_type (t);
6671 if (inflated)
6672 mono_metadata_free_type (t);
6673 return ret;
6677 * mono_bounded_array_class_get:
6678 * @element_class: element class
6679 * @rank: the dimension of the array class
6680 * @bounded: whenever the array has non-zero bounds
6682 * Returns: A class object describing the array with element type @element_type and
6683 * dimension @rank.
6685 MonoClass *
6686 mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
6688 MonoImage *image;
6689 MonoClass *klass;
6690 MonoClass *parent = NULL;
6691 GSList *list, *rootlist = NULL;
6692 int nsize;
6693 char *name;
6695 g_assert (rank <= 255);
6697 if (rank > 1)
6698 /* bounded only matters for one-dimensional arrays */
6699 bounded = FALSE;
6701 image = eclass->image;
6703 if (rank == 1 && !bounded) {
6705 * This case is very frequent not just during compilation because of calls
6706 * from mono_class_from_mono_type (), mono_array_new (),
6707 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
6709 mono_os_mutex_lock (&image->szarray_cache_lock);
6710 if (!image->szarray_cache)
6711 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6712 klass = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
6713 mono_os_mutex_unlock (&image->szarray_cache_lock);
6714 if (klass)
6715 return klass;
6717 mono_loader_lock ();
6718 } else {
6719 mono_loader_lock ();
6721 if (!image->array_cache)
6722 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6724 if ((rootlist = list = (GSList *)g_hash_table_lookup (image->array_cache, eclass))) {
6725 for (; list; list = list->next) {
6726 klass = (MonoClass *)list->data;
6727 if ((klass->rank == rank) && (klass->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
6728 mono_loader_unlock ();
6729 return klass;
6735 parent = mono_defaults.array_class;
6736 if (!parent->inited)
6737 mono_class_init (parent);
6739 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
6741 klass->image = image;
6742 klass->name_space = eclass->name_space;
6743 klass->class_kind = MONO_CLASS_ARRAY;
6745 nsize = strlen (eclass->name);
6746 name = (char *)g_malloc (nsize + 2 + rank + 1);
6747 memcpy (name, eclass->name, nsize);
6748 name [nsize] = '[';
6749 if (rank > 1)
6750 memset (name + nsize + 1, ',', rank - 1);
6751 if (bounded)
6752 name [nsize + rank] = '*';
6753 name [nsize + rank + bounded] = ']';
6754 name [nsize + rank + bounded + 1] = 0;
6755 klass->name = mono_image_strdup (image, name);
6756 g_free (name);
6758 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
6760 classes_size += sizeof (MonoClassArray);
6761 ++class_array_count;
6763 klass->type_token = 0;
6764 klass->parent = parent;
6765 klass->instance_size = mono_class_instance_size (klass->parent);
6767 if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
6768 /*Arrays of those two types are invalid.*/
6769 MonoError prepared_error;
6770 mono_error_init (&prepared_error);
6771 mono_error_set_invalid_program (&prepared_error, "Arrays of void or System.TypedReference types are invalid.");
6772 mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
6773 mono_error_cleanup (&prepared_error);
6774 } else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
6775 guint32 ref_info_handle = mono_class_get_ref_info_handle (eclass);
6776 if (!ref_info_handle || eclass->wastypebuilder) {
6777 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
6778 g_assert (ref_info_handle && !eclass->wastypebuilder);
6780 /* element_size -1 is ok as this is not an instantitable type*/
6781 klass->sizes.element_size = -1;
6782 } else
6783 klass->sizes.element_size = mono_class_array_element_size (eclass);
6785 mono_class_setup_supertypes (klass);
6787 if (mono_class_is_ginst (eclass))
6788 mono_class_init (eclass);
6789 if (!eclass->size_inited)
6790 mono_class_setup_fields (eclass);
6791 mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
6792 /*FIXME we fail the array type, but we have to let other fields be set.*/
6794 klass->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
6796 klass->rank = rank;
6798 if (eclass->enumtype)
6799 klass->cast_class = eclass->element_class;
6800 else
6801 klass->cast_class = eclass;
6803 switch (klass->cast_class->byval_arg.type) {
6804 case MONO_TYPE_I1:
6805 klass->cast_class = mono_defaults.byte_class;
6806 break;
6807 case MONO_TYPE_U2:
6808 klass->cast_class = mono_defaults.int16_class;
6809 break;
6810 case MONO_TYPE_U4:
6811 #if SIZEOF_VOID_P == 4
6812 case MONO_TYPE_I:
6813 case MONO_TYPE_U:
6814 #endif
6815 klass->cast_class = mono_defaults.int32_class;
6816 break;
6817 case MONO_TYPE_U8:
6818 #if SIZEOF_VOID_P == 8
6819 case MONO_TYPE_I:
6820 case MONO_TYPE_U:
6821 #endif
6822 klass->cast_class = mono_defaults.int64_class;
6823 break;
6824 default:
6825 break;
6828 klass->element_class = eclass;
6830 if ((rank > 1) || bounded) {
6831 MonoArrayType *at = (MonoArrayType *)mono_image_alloc0 (image, sizeof (MonoArrayType));
6832 klass->byval_arg.type = MONO_TYPE_ARRAY;
6833 klass->byval_arg.data.array = at;
6834 at->eklass = eclass;
6835 at->rank = rank;
6836 /* FIXME: complete.... */
6837 } else {
6838 klass->byval_arg.type = MONO_TYPE_SZARRAY;
6839 klass->byval_arg.data.klass = eclass;
6841 klass->this_arg = klass->byval_arg;
6842 klass->this_arg.byref = 1;
6844 //WTF was this? it's wrong
6845 // klass->generic_container = eclass->generic_container;
6847 if (rank == 1 && !bounded) {
6848 MonoClass *prev_class;
6850 mono_os_mutex_lock (&image->szarray_cache_lock);
6851 prev_class = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
6852 if (prev_class)
6853 /* Someone got in before us */
6854 klass = prev_class;
6855 else
6856 g_hash_table_insert (image->szarray_cache, eclass, klass);
6857 mono_os_mutex_unlock (&image->szarray_cache_lock);
6858 } else {
6859 list = g_slist_append (rootlist, klass);
6860 g_hash_table_insert (image->array_cache, eclass, list);
6863 mono_loader_unlock ();
6865 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6867 return klass;
6871 * mono_array_class_get:
6872 * @element_class: element class
6873 * @rank: the dimension of the array class
6875 * Returns: A class object describing the array with element type @element_type and
6876 * dimension @rank.
6878 MonoClass *
6879 mono_array_class_get (MonoClass *eclass, guint32 rank)
6881 return mono_bounded_array_class_get (eclass, rank, FALSE);
6885 * mono_class_instance_size:
6886 * @klass: a class
6888 * Use to get the size of a class in bytes.
6890 * Returns: The size of an object instance
6892 gint32
6893 mono_class_instance_size (MonoClass *klass)
6895 if (!klass->size_inited)
6896 mono_class_init (klass);
6898 return klass->instance_size;
6902 * mono_class_min_align:
6903 * @klass: a class
6905 * Use to get the computed minimum alignment requirements for the specified class.
6907 * Returns: minimum alignment requirements
6909 gint32
6910 mono_class_min_align (MonoClass *klass)
6912 if (!klass->size_inited)
6913 mono_class_init (klass);
6915 return klass->min_align;
6919 * mono_class_value_size:
6920 * @klass: a class
6922 * This function is used for value types, and return the
6923 * space and the alignment to store that kind of value object.
6925 * Returns: the size of a value of kind @klass
6927 gint32
6928 mono_class_value_size (MonoClass *klass, guint32 *align)
6930 gint32 size;
6932 /* fixme: check disable, because we still have external revereces to
6933 * mscorlib and Dummy Objects
6935 /*g_assert (klass->valuetype);*/
6937 size = mono_class_instance_size (klass) - sizeof (MonoObject);
6939 if (align)
6940 *align = klass->min_align;
6942 return size;
6946 * mono_class_data_size:
6947 * @klass: a class
6949 * Returns: The size of the static class data
6951 gint32
6952 mono_class_data_size (MonoClass *klass)
6954 if (!klass->inited)
6955 mono_class_init (klass);
6956 /* This can happen with dynamically created types */
6957 if (!klass->fields_inited)
6958 mono_class_setup_fields (klass);
6960 /* in arrays, sizes.class_size is unioned with element_size
6961 * and arrays have no static fields
6963 if (klass->rank)
6964 return 0;
6965 return klass->sizes.class_size;
6969 * Auxiliary routine to mono_class_get_field
6971 * Takes a field index instead of a field token.
6973 static MonoClassField *
6974 mono_class_get_field_idx (MonoClass *klass, int idx)
6976 mono_class_setup_fields (klass);
6977 if (mono_class_has_failure (klass))
6978 return NULL;
6980 while (klass) {
6981 int first_field_idx = mono_class_get_first_field_idx (klass);
6982 int fcount = mono_class_get_field_count (klass);
6983 if (klass->image->uncompressed_metadata) {
6985 * first_field_idx points to the FieldPtr table, while idx points into the
6986 * Field table, so we have to do a search.
6988 /*FIXME this is broken for types with multiple fields with the same name.*/
6989 const char *name = mono_metadata_string_heap (klass->image, mono_metadata_decode_row_col (&klass->image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
6990 int i;
6992 for (i = 0; i < fcount; ++i)
6993 if (mono_field_get_name (&klass->fields [i]) == name)
6994 return &klass->fields [i];
6995 g_assert_not_reached ();
6996 } else {
6997 if (fcount) {
6998 if ((idx >= first_field_idx) && (idx < first_field_idx + fcount)){
6999 return &klass->fields [idx - first_field_idx];
7003 klass = klass->parent;
7005 return NULL;
7009 * mono_class_get_field:
7010 * @class: the class to lookup the field.
7011 * @field_token: the field token
7013 * Returns: A MonoClassField representing the type and offset of
7014 * the field, or a NULL value if the field does not belong to this
7015 * class.
7017 MonoClassField *
7018 mono_class_get_field (MonoClass *klass, guint32 field_token)
7020 int idx = mono_metadata_token_index (field_token);
7022 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
7024 return mono_class_get_field_idx (klass, idx - 1);
7028 * mono_class_get_field_from_name:
7029 * @klass: the class to lookup the field.
7030 * @name: the field name
7032 * Search the class @klass and it's parents for a field with the name @name.
7034 * Returns: The MonoClassField pointer of the named field or NULL
7036 MonoClassField *
7037 mono_class_get_field_from_name (MonoClass *klass, const char *name)
7039 return mono_class_get_field_from_name_full (klass, name, NULL);
7043 * mono_class_get_field_from_name_full:
7044 * @klass: the class to lookup the field.
7045 * @name: the field name
7046 * @type: the type of the fields. This optional.
7048 * Search the class @klass and it's parents for a field with the name @name and type @type.
7050 * If @klass is an inflated generic type, the type comparison is done with the equivalent field
7051 * of its generic type definition.
7053 * Returns: The MonoClassField pointer of the named field or NULL
7055 MonoClassField *
7056 mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
7058 int i;
7060 mono_class_setup_fields (klass);
7061 if (mono_class_has_failure (klass))
7062 return NULL;
7064 while (klass) {
7065 int fcount = mono_class_get_field_count (klass);
7066 for (i = 0; i < fcount; ++i) {
7067 MonoClassField *field = &klass->fields [i];
7069 if (strcmp (name, mono_field_get_name (field)) != 0)
7070 continue;
7072 if (type) {
7073 MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
7074 if (!mono_metadata_type_equal_full (type, field_type, TRUE))
7075 continue;
7077 return field;
7079 klass = klass->parent;
7081 return NULL;
7085 * mono_class_get_field_token:
7086 * @field: the field we need the token of
7088 * Get the token of a field. Note that the tokesn is only valid for the image
7089 * the field was loaded from. Don't use this function for fields in dynamic types.
7091 * Returns: The token representing the field in the image it was loaded from.
7093 guint32
7094 mono_class_get_field_token (MonoClassField *field)
7096 MonoClass *klass = field->parent;
7097 int i;
7099 mono_class_setup_fields (klass);
7101 while (klass) {
7102 if (!klass->fields)
7103 return 0;
7104 int first_field_idx = mono_class_get_first_field_idx (klass);
7105 int fcount = mono_class_get_field_count (klass);
7106 for (i = 0; i < fcount; ++i) {
7107 if (&klass->fields [i] == field) {
7108 int idx = first_field_idx + i + 1;
7110 if (klass->image->uncompressed_metadata)
7111 idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx);
7112 return mono_metadata_make_token (MONO_TABLE_FIELD, idx);
7115 klass = klass->parent;
7118 g_assert_not_reached ();
7119 return 0;
7122 static int
7123 mono_field_get_index (MonoClassField *field)
7125 int index = field - field->parent->fields;
7126 g_assert (index >= 0 && index < mono_class_get_field_count (field->parent));
7128 return index;
7132 * mono_class_get_field_default_value:
7134 * Return the default value of the field as a pointer into the metadata blob.
7136 const char*
7137 mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
7139 guint32 cindex;
7140 guint32 constant_cols [MONO_CONSTANT_SIZE];
7141 int field_index;
7142 MonoClass *klass = field->parent;
7144 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
7146 MonoClassExt *ext = mono_class_get_ext (klass);
7147 if (!ext || !ext->field_def_values) {
7148 MonoFieldDefaultValue *def_values;
7150 mono_class_alloc_ext (klass);
7151 ext = mono_class_get_ext (klass);
7153 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
7155 mono_image_lock (klass->image);
7156 mono_memory_barrier ();
7157 if (!ext->field_def_values)
7158 ext->field_def_values = def_values;
7159 mono_image_unlock (klass->image);
7162 field_index = mono_field_get_index (field);
7164 if (!ext->field_def_values [field_index].data) {
7165 cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
7166 if (!cindex)
7167 return NULL;
7169 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
7171 mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
7172 ext->field_def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
7173 ext->field_def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
7176 *def_type = ext->field_def_values [field_index].def_type;
7177 return ext->field_def_values [field_index].data;
7180 static int
7181 mono_property_get_index (MonoProperty *prop)
7183 MonoClassExt *ext = mono_class_get_ext (prop->parent);
7184 int index = prop - ext->properties;
7186 g_assert (index >= 0 && index < ext->property.count);
7188 return index;
7192 * mono_class_get_property_default_value:
7194 * Return the default value of the field as a pointer into the metadata blob.
7196 const char*
7197 mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type)
7199 guint32 cindex;
7200 guint32 constant_cols [MONO_CONSTANT_SIZE];
7201 MonoClass *klass = property->parent;
7203 g_assert (property->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT);
7205 * We don't cache here because it is not used by C# so it's quite rare, but
7206 * we still do the lookup in klass->ext because that is where the data
7207 * is stored for dynamic assemblies.
7210 if (image_is_dynamic (klass->image)) {
7211 MonoClassExt *ext = mono_class_get_ext (klass);
7212 int prop_index = mono_property_get_index (property);
7213 if (ext->prop_def_values && ext->prop_def_values [prop_index].data) {
7214 *def_type = ext->prop_def_values [prop_index].def_type;
7215 return ext->prop_def_values [prop_index].data;
7217 return NULL;
7219 cindex = mono_metadata_get_constant_index (klass->image, mono_class_get_property_token (property), 0);
7220 if (!cindex)
7221 return NULL;
7223 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
7224 *def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
7225 return (const char *)mono_metadata_blob_heap (klass->image, constant_cols [MONO_CONSTANT_VALUE]);
7228 guint32
7229 mono_class_get_event_token (MonoEvent *event)
7231 MonoClass *klass = event->parent;
7232 int i;
7234 while (klass) {
7235 MonoClassExt *ext = mono_class_get_ext (klass);
7236 if (ext) {
7237 for (i = 0; i < ext->event.count; ++i) {
7238 if (&ext->events [i] == event)
7239 return mono_metadata_make_token (MONO_TABLE_EVENT, ext->event.first + i + 1);
7242 klass = klass->parent;
7245 g_assert_not_reached ();
7246 return 0;
7250 * mono_class_get_property_from_name:
7251 * @klass: a class
7252 * @name: name of the property to lookup in the specified class
7254 * Use this method to lookup a property in a class
7255 * Returns: the MonoProperty with the given name, or NULL if the property
7256 * does not exist on the @klass.
7258 MonoProperty*
7259 mono_class_get_property_from_name (MonoClass *klass, const char *name)
7261 while (klass) {
7262 MonoProperty* p;
7263 gpointer iter = NULL;
7264 while ((p = mono_class_get_properties (klass, &iter))) {
7265 if (! strcmp (name, p->name))
7266 return p;
7268 klass = klass->parent;
7270 return NULL;
7274 * mono_class_get_property_token:
7275 * @prop: MonoProperty to query
7277 * Returns: The ECMA token for the specified property.
7279 guint32
7280 mono_class_get_property_token (MonoProperty *prop)
7282 MonoClass *klass = prop->parent;
7283 while (klass) {
7284 MonoProperty* p;
7285 int i = 0;
7286 gpointer iter = NULL;
7287 MonoClassExt *ext = mono_class_get_ext (klass);
7288 while ((p = mono_class_get_properties (klass, &iter))) {
7289 if (&ext->properties [i] == prop)
7290 return mono_metadata_make_token (MONO_TABLE_PROPERTY, ext->property.first + i + 1);
7292 i ++;
7294 klass = klass->parent;
7297 g_assert_not_reached ();
7298 return 0;
7301 char *
7302 mono_class_name_from_token (MonoImage *image, guint32 type_token)
7304 const char *name, *nspace;
7305 if (image_is_dynamic (image))
7306 return g_strdup_printf ("DynamicType 0x%08x", type_token);
7308 switch (type_token & 0xff000000){
7309 case MONO_TOKEN_TYPE_DEF: {
7310 guint32 cols [MONO_TYPEDEF_SIZE];
7311 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
7312 guint tidx = mono_metadata_token_index (type_token);
7314 if (tidx > tt->rows)
7315 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7317 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
7318 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7319 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7320 if (strlen (nspace) == 0)
7321 return g_strdup_printf ("%s", name);
7322 else
7323 return g_strdup_printf ("%s.%s", nspace, name);
7326 case MONO_TOKEN_TYPE_REF: {
7327 MonoError error;
7328 guint32 cols [MONO_TYPEREF_SIZE];
7329 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
7330 guint tidx = mono_metadata_token_index (type_token);
7332 if (tidx > t->rows)
7333 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7335 if (!mono_verifier_verify_typeref_row (image, tidx - 1, &error)) {
7336 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7337 mono_error_cleanup (&error);
7338 return msg;
7341 mono_metadata_decode_row (t, tidx-1, cols, MONO_TYPEREF_SIZE);
7342 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
7343 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
7344 if (strlen (nspace) == 0)
7345 return g_strdup_printf ("%s", name);
7346 else
7347 return g_strdup_printf ("%s.%s", nspace, name);
7350 case MONO_TOKEN_TYPE_SPEC:
7351 return g_strdup_printf ("Typespec 0x%08x", type_token);
7352 default:
7353 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7357 static char *
7358 mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
7360 if (image_is_dynamic (image))
7361 return g_strdup_printf ("DynamicAssembly %s", image->name);
7363 switch (type_token & 0xff000000){
7364 case MONO_TOKEN_TYPE_DEF:
7365 if (image->assembly)
7366 return mono_stringify_assembly_name (&image->assembly->aname);
7367 else if (image->assembly_name)
7368 return g_strdup (image->assembly_name);
7369 return g_strdup_printf ("%s", image->name ? image->name : "[Could not resolve assembly name");
7370 case MONO_TOKEN_TYPE_REF: {
7371 MonoError error;
7372 MonoAssemblyName aname;
7373 guint32 cols [MONO_TYPEREF_SIZE];
7374 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
7375 guint32 idx = mono_metadata_token_index (type_token);
7377 if (idx > t->rows)
7378 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7380 if (!mono_verifier_verify_typeref_row (image, idx - 1, &error)) {
7381 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7382 mono_error_cleanup (&error);
7383 return msg;
7385 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
7387 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
7388 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
7389 case MONO_RESOLUTION_SCOPE_MODULE:
7390 /* FIXME: */
7391 return g_strdup ("");
7392 case MONO_RESOLUTION_SCOPE_MODULEREF:
7393 /* FIXME: */
7394 return g_strdup ("");
7395 case MONO_RESOLUTION_SCOPE_TYPEREF:
7396 /* FIXME: */
7397 return g_strdup ("");
7398 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
7399 mono_assembly_get_assemblyref (image, idx - 1, &aname);
7400 return mono_stringify_assembly_name (&aname);
7401 default:
7402 g_assert_not_reached ();
7404 break;
7406 case MONO_TOKEN_TYPE_SPEC:
7407 /* FIXME: */
7408 return g_strdup ("");
7409 default:
7410 g_assert_not_reached ();
7413 return NULL;
7417 * mono_class_get_full:
7418 * @image: the image where the class resides
7419 * @type_token: the token for the class
7420 * @context: the generic context used to evaluate generic instantiations in
7421 * @deprecated: Functions that expose MonoGenericContext are going away in mono 4.0
7423 * Returns: The MonoClass that represents @type_token in @image
7425 MonoClass *
7426 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
7428 MonoError error;
7429 MonoClass *klass;
7430 klass = mono_class_get_checked (image, type_token, &error);
7432 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
7433 klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7435 g_assert (mono_error_ok (&error)); /* FIXME deprecate this function and forbit the runtime from using it. */
7436 return klass;
7440 MonoClass *
7441 mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
7443 MonoClass *klass;
7445 mono_error_init (error);
7446 klass = mono_class_get_checked (image, type_token, error);
7448 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
7449 klass = mono_class_inflate_generic_class_checked (klass, context, error);
7451 return klass;
7454 * mono_class_get_checked:
7455 * @image: the image where the class resides
7456 * @type_token: the token for the class
7457 * @error: error object to return any error
7459 * Returns: The MonoClass that represents @type_token in @image, or NULL on error.
7461 MonoClass *
7462 mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
7464 MonoClass *klass = NULL;
7466 mono_error_init (error);
7468 if (image_is_dynamic (image)) {
7469 int table = mono_metadata_token_table (type_token);
7471 if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
7472 mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
7473 return NULL;
7475 klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
7476 goto done;
7479 switch (type_token & 0xff000000){
7480 case MONO_TOKEN_TYPE_DEF:
7481 klass = mono_class_create_from_typedef (image, type_token, error);
7482 break;
7483 case MONO_TOKEN_TYPE_REF:
7484 klass = mono_class_from_typeref_checked (image, type_token, error);
7485 break;
7486 case MONO_TOKEN_TYPE_SPEC:
7487 klass = mono_class_create_from_typespec (image, type_token, NULL, error);
7488 break;
7489 default:
7490 mono_error_set_bad_image (error, image, "Unknown type token %x", type_token & 0xff000000);
7493 done:
7494 /* Generic case, should be avoided for when a better error is possible. */
7495 if (!klass && mono_error_ok (error)) {
7496 char *name = mono_class_name_from_token (image, type_token);
7497 char *assembly = mono_assembly_name_from_token (image, type_token);
7498 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
7501 return klass;
7506 * mono_type_get_checked:
7507 * @image: the image where the type resides
7508 * @type_token: the token for the type
7509 * @context: the generic context used to evaluate generic instantiations in
7510 * @error: Error handling context
7512 * This functions exists to fullfill the fact that sometimes it's desirable to have access to the
7514 * Returns: The MonoType that represents @type_token in @image
7516 MonoType *
7517 mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
7519 MonoType *type = NULL;
7520 gboolean inflated = FALSE;
7522 mono_error_init (error);
7524 //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
7525 if (image_is_dynamic (image)) {
7526 MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
7527 return_val_if_nok (error, NULL);
7528 return mono_class_get_type (klass);
7531 if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
7532 MonoClass *klass = mono_class_get_checked (image, type_token, error);
7534 if (!klass) {
7535 return NULL;
7538 g_assert (klass);
7539 return mono_class_get_type (klass);
7542 type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
7544 if (!type) {
7545 return NULL;
7548 if (inflated) {
7549 MonoType *tmp = type;
7550 type = mono_class_get_type (mono_class_from_mono_type (type));
7551 /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
7552 * A MonoClass::byval_arg of a generic type definion has type CLASS.
7553 * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with byval_arg.
7555 * The long term solution is to chaise this places and make then set MonoType::type correctly.
7556 * */
7557 if (type->type != tmp->type)
7558 type = tmp;
7559 else
7560 mono_metadata_free_type (tmp);
7562 return type;
7566 * mono_class_get:
7567 * @image: image where the class token will be looked up.
7568 * @type_token: a type token from the image
7570 * Returns the MonoClass with the given @type_token on the @image
7572 MonoClass *
7573 mono_class_get (MonoImage *image, guint32 type_token)
7575 return mono_class_get_full (image, type_token, NULL);
7579 * mono_image_init_name_cache:
7581 * Initializes the class name cache stored in image->name_cache.
7583 * LOCKING: Acquires the corresponding image lock.
7585 void
7586 mono_image_init_name_cache (MonoImage *image)
7588 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7589 guint32 cols [MONO_TYPEDEF_SIZE];
7590 const char *name;
7591 const char *nspace;
7592 guint32 i, visib, nspace_index;
7593 GHashTable *name_cache2, *nspace_table, *the_name_cache;
7595 if (image->name_cache)
7596 return;
7598 the_name_cache = g_hash_table_new (g_str_hash, g_str_equal);
7600 if (image_is_dynamic (image)) {
7601 mono_image_lock (image);
7602 if (image->name_cache) {
7603 /* Somebody initialized it before us */
7604 g_hash_table_destroy (the_name_cache);
7605 } else {
7606 mono_atomic_store_release (&image->name_cache, the_name_cache);
7608 mono_image_unlock (image);
7609 return;
7612 /* Temporary hash table to avoid lookups in the nspace_table */
7613 name_cache2 = g_hash_table_new (NULL, NULL);
7615 for (i = 1; i <= t->rows; ++i) {
7616 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7617 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7619 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7620 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7622 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7623 continue;
7624 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7625 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7627 nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
7628 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7629 if (!nspace_table) {
7630 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7631 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
7632 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7633 nspace_table);
7635 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
7638 /* Load type names from EXPORTEDTYPES table */
7640 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7641 guint32 cols [MONO_EXP_TYPE_SIZE];
7642 int i;
7644 for (i = 0; i < t->rows; ++i) {
7645 mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
7647 guint32 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
7648 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_EXP_TYPE)
7649 /* Nested type */
7650 continue;
7652 name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
7653 nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
7655 nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
7656 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7657 if (!nspace_table) {
7658 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7659 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
7660 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7661 nspace_table);
7663 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
7667 g_hash_table_destroy (name_cache2);
7669 mono_image_lock (image);
7670 if (image->name_cache) {
7671 /* Somebody initialized it before us */
7672 g_hash_table_destroy (the_name_cache);
7673 } else {
7674 mono_atomic_store_release (&image->name_cache, the_name_cache);
7676 mono_image_unlock (image);
7679 /*FIXME Only dynamic assemblies should allow this operation.*/
7680 void
7681 mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
7682 const char *name, guint32 index)
7684 GHashTable *nspace_table;
7685 GHashTable *name_cache;
7686 guint32 old_index;
7688 mono_image_init_name_cache (image);
7689 mono_image_lock (image);
7691 name_cache = image->name_cache;
7692 if (!(nspace_table = (GHashTable *)g_hash_table_lookup (name_cache, nspace))) {
7693 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7694 g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
7697 if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
7698 g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
7700 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
7702 mono_image_unlock (image);
7705 typedef struct {
7706 gconstpointer key;
7707 gpointer value;
7708 } FindUserData;
7710 static void
7711 find_nocase (gpointer key, gpointer value, gpointer user_data)
7713 char *name = (char*)key;
7714 FindUserData *data = (FindUserData*)user_data;
7716 if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
7717 data->value = value;
7721 * mono_class_from_name_case:
7722 * @image: The MonoImage where the type is looked up in
7723 * @name_space: the type namespace
7724 * @name: the type short name.
7725 * @deprecated: use the mono_class_from_name_case_checked variant instead.
7727 * Obtains a MonoClass with a given namespace and a given name which
7728 * is located in the given MonoImage. The namespace and name
7729 * lookups are case insensitive.
7731 MonoClass *
7732 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
7734 MonoError error;
7735 MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error);
7736 mono_error_cleanup (&error);
7738 return res;
7742 * mono_class_from_name_case:
7743 * @image: The MonoImage where the type is looked up in
7744 * @name_space: the type namespace
7745 * @name: the type short name.
7746 * @error: if
7748 * Obtains a MonoClass with a given namespace and a given name which
7749 * is located in the given MonoImage. The namespace and name
7750 * lookups are case insensitive.
7752 * Returns: The MonoClass if the given namespace and name were found, or NULL if it
7753 * was not found. The @error object will contain information about the problem
7754 * in that case.
7756 MonoClass *
7757 mono_class_from_name_case_checked (MonoImage *image, const char *name_space, const char *name, MonoError *error)
7759 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7760 guint32 cols [MONO_TYPEDEF_SIZE];
7761 const char *n;
7762 const char *nspace;
7763 guint32 i, visib;
7765 mono_error_init (error);
7767 if (image_is_dynamic (image)) {
7768 guint32 token = 0;
7769 FindUserData user_data;
7771 mono_image_init_name_cache (image);
7772 mono_image_lock (image);
7774 user_data.key = name_space;
7775 user_data.value = NULL;
7776 g_hash_table_foreach (image->name_cache, find_nocase, &user_data);
7778 if (user_data.value) {
7779 GHashTable *nspace_table = (GHashTable*)user_data.value;
7781 user_data.key = name;
7782 user_data.value = NULL;
7784 g_hash_table_foreach (nspace_table, find_nocase, &user_data);
7786 if (user_data.value)
7787 token = GPOINTER_TO_UINT (user_data.value);
7790 mono_image_unlock (image);
7792 if (token)
7793 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | token, error);
7794 else
7795 return NULL;
7799 /* add a cache if needed */
7800 for (i = 1; i <= t->rows; ++i) {
7801 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7802 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7804 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7805 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7807 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7808 continue;
7809 n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7810 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7811 if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
7812 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | i, error);
7814 return NULL;
7817 static MonoClass*
7818 return_nested_in (MonoClass *klass, char *nested)
7820 MonoClass *found;
7821 char *s = strchr (nested, '/');
7822 gpointer iter = NULL;
7824 if (s) {
7825 *s = 0;
7826 s++;
7829 while ((found = mono_class_get_nested_types (klass, &iter))) {
7830 if (strcmp (found->name, nested) == 0) {
7831 if (s)
7832 return return_nested_in (found, s);
7833 return found;
7836 return NULL;
7839 static MonoClass*
7840 search_modules (MonoImage *image, const char *name_space, const char *name, MonoError *error)
7842 MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
7843 MonoImage *file_image;
7844 MonoClass *klass;
7845 int i;
7847 mono_error_init (error);
7850 * The EXPORTEDTYPES table only contains public types, so have to search the
7851 * modules as well.
7852 * Note: image->modules contains the contents of the MODULEREF table, while
7853 * the real module list is in the FILE table.
7855 for (i = 0; i < file_table->rows; i++) {
7856 guint32 cols [MONO_FILE_SIZE];
7857 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
7858 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
7859 continue;
7861 file_image = mono_image_load_file_for_image_checked (image, i + 1, error);
7862 if (file_image) {
7863 klass = mono_class_from_name_checked (file_image, name_space, name, error);
7864 if (klass || !is_ok (error))
7865 return klass;
7869 return NULL;
7872 static MonoClass *
7873 mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, MonoError *error)
7875 GHashTable *nspace_table;
7876 MonoImage *loaded_image;
7877 guint32 token = 0;
7878 int i;
7879 MonoClass *klass;
7880 char *nested;
7881 char buf [1024];
7883 mono_error_init (error);
7885 // Checking visited images avoids stack overflows when cyclic references exist.
7886 if (g_hash_table_lookup (visited_images, image))
7887 return NULL;
7889 g_hash_table_insert (visited_images, image, GUINT_TO_POINTER(1));
7891 if ((nested = strchr (name, '/'))) {
7892 int pos = nested - name;
7893 int len = strlen (name);
7894 if (len > 1023)
7895 return NULL;
7896 memcpy (buf, name, len + 1);
7897 buf [pos] = 0;
7898 nested = buf + pos + 1;
7899 name = buf;
7902 /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */
7903 if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
7904 gboolean res = get_class_from_name (image, name_space, name, &klass);
7905 if (res) {
7906 if (!klass) {
7907 klass = search_modules (image, name_space, name, error);
7908 if (!is_ok (error))
7909 return NULL;
7911 if (nested)
7912 return klass ? return_nested_in (klass, nested) : NULL;
7913 else
7914 return klass;
7918 mono_image_init_name_cache (image);
7919 mono_image_lock (image);
7921 nspace_table = (GHashTable *)g_hash_table_lookup (image->name_cache, name_space);
7923 if (nspace_table)
7924 token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
7926 mono_image_unlock (image);
7928 if (!token && image_is_dynamic (image) && image->modules) {
7929 /* Search modules as well */
7930 for (i = 0; i < image->module_count; ++i) {
7931 MonoImage *module = image->modules [i];
7933 klass = mono_class_from_name_checked (module, name_space, name, error);
7934 if (klass || !is_ok (error))
7935 return klass;
7939 if (!token) {
7940 klass = search_modules (image, name_space, name, error);
7941 if (klass || !is_ok (error))
7942 return klass;
7943 return NULL;
7946 if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
7947 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7948 guint32 cols [MONO_EXP_TYPE_SIZE];
7949 guint32 idx, impl;
7951 idx = mono_metadata_token_index (token);
7953 mono_metadata_decode_row (t, idx - 1, cols, MONO_EXP_TYPE_SIZE);
7955 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
7956 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
7957 loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error);
7958 if (!loaded_image)
7959 return NULL;
7960 klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, error);
7961 if (nested)
7962 return klass ? return_nested_in (klass, nested) : NULL;
7963 return klass;
7964 } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
7965 guint32 assembly_idx;
7967 assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
7969 mono_assembly_load_reference (image, assembly_idx - 1);
7970 g_assert (image->references [assembly_idx - 1]);
7971 if (image->references [assembly_idx - 1] == (gpointer)-1)
7972 return NULL;
7973 klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, error);
7974 if (nested)
7975 return klass ? return_nested_in (klass, nested) : NULL;
7976 return klass;
7977 } else {
7978 g_assert_not_reached ();
7982 token = MONO_TOKEN_TYPE_DEF | token;
7984 klass = mono_class_get_checked (image, token, error);
7985 if (nested)
7986 return return_nested_in (klass, nested);
7987 return klass;
7991 * mono_class_from_name_checked:
7992 * @image: The MonoImage where the type is looked up in
7993 * @name_space: the type namespace
7994 * @name: the type short name.
7996 * Obtains a MonoClass with a given namespace and a given name which
7997 * is located in the given MonoImage.
7999 * Works like mono_class_from_name, but error handling is tricky. It can return NULL and have no error
8000 * set if the class was not found or it will return NULL and set the error if there was a loading error.
8002 MonoClass *
8003 mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
8005 MonoClass *klass;
8006 GHashTable *visited_images;
8008 visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
8010 klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, error);
8012 g_hash_table_destroy (visited_images);
8014 return klass;
8018 * mono_class_from_name:
8019 * @image: The MonoImage where the type is looked up in
8020 * @name_space: the type namespace
8021 * @name: the type short name.
8023 * Obtains a MonoClass with a given namespace and a given name which
8024 * is located in the given MonoImage.
8026 * To reference nested classes, use the "/" character as a separator.
8027 * For example use "Foo/Bar" to reference the class Bar that is nested
8028 * inside Foo, like this: "class Foo { class Bar {} }".
8030 MonoClass *
8031 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
8033 MonoError error;
8034 MonoClass *klass;
8036 klass = mono_class_from_name_checked (image, name_space, name, &error);
8037 mono_error_cleanup (&error); /* FIXME Don't swallow the error */
8039 return klass;
8043 * mono_class_load_from_name:
8044 * @image: The MonoImage where the type is looked up in
8045 * @name_space: the type namespace
8046 * @name: the type short name.
8048 * This function works exactly like mono_class_from_name but it will abort if the class is not found.
8049 * This function should be used by the runtime for critical types to which there's no way to recover but crash
8050 * If they are missing. Thing of System.Object or System.String.
8052 MonoClass *
8053 mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
8055 MonoError error;
8056 MonoClass *klass;
8058 klass = mono_class_from_name_checked (image, name_space, name, &error);
8059 if (!klass)
8060 g_error ("Runtime critical type %s.%s not found", name_space, name);
8061 if (!mono_error_ok (&error))
8062 g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
8063 return klass;
8067 * mono_class_try_load_from_name:
8068 * @image: The MonoImage where the type is looked up in
8069 * @name_space: the type namespace
8070 * @name: the type short name.
8072 * This function tries to load a type, returning the class was found or NULL otherwise.
8073 * This function should be used by the runtime when probing for optional types, those that could have being linked out.
8075 * Big design consideration. This function aborts if there was an error loading the type. This prevents us from missing
8076 * a type that we would otherwise assume to be available but was not due some error.
8079 MonoClass*
8080 mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name)
8082 MonoError error;
8083 MonoClass *klass;
8085 klass = mono_class_from_name_checked (image, name_space, name, &error);
8086 if (!mono_error_ok (&error))
8087 g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
8088 return klass;
8093 * mono_class_is_subclass_of:
8094 * @klass: class to probe if it is a subclass of another one
8095 * @klassc: the class we suspect is the base class
8096 * @check_interfaces: whether we should perform interface checks
8098 * This method determines whether @klass is a subclass of @klassc.
8100 * If the @check_interfaces flag is set, then if @klassc is an interface
8101 * this method return TRUE if the @klass implements the interface or
8102 * if @klass is an interface, if one of its base classes is @klass.
8104 * If @check_interfaces is false then, then if @klass is not an interface
8105 * then it returns TRUE if the @klass is a subclass of @klassc.
8107 * if @klass is an interface and @klassc is System.Object, then this function
8108 * return true.
8111 gboolean
8112 mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
8113 gboolean check_interfaces)
8115 /* FIXME test for interfaces with variant generic arguments */
8116 mono_class_init (klass);
8117 mono_class_init (klassc);
8119 if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
8120 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
8121 return TRUE;
8122 } else if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && MONO_CLASS_IS_INTERFACE (klass)) {
8123 int i;
8125 for (i = 0; i < klass->interface_count; i ++) {
8126 MonoClass *ic = klass->interfaces [i];
8127 if (ic == klassc)
8128 return TRUE;
8130 } else {
8131 if (!MONO_CLASS_IS_INTERFACE (klass) && mono_class_has_parent (klass, klassc))
8132 return TRUE;
8136 * MS.NET thinks interfaces are a subclass of Object, so we think it as
8137 * well.
8139 if (klassc == mono_defaults.object_class)
8140 return TRUE;
8142 return FALSE;
8145 static gboolean
8146 mono_type_is_generic_argument (MonoType *type)
8148 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
8151 gboolean
8152 mono_class_has_variant_generic_params (MonoClass *klass)
8154 int i;
8155 MonoGenericContainer *container;
8157 if (!mono_class_is_ginst (klass))
8158 return FALSE;
8160 container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
8162 for (i = 0; i < container->type_argc; ++i)
8163 if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
8164 return TRUE;
8166 return FALSE;
8169 static gboolean
8170 mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
8172 if (target == candidate)
8173 return TRUE;
8175 if (check_for_reference_conv &&
8176 mono_type_is_generic_argument (&target->byval_arg) &&
8177 mono_type_is_generic_argument (&candidate->byval_arg)) {
8178 MonoGenericParam *gparam = candidate->byval_arg.data.generic_param;
8179 MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
8181 if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
8182 return FALSE;
8184 if (!mono_class_is_assignable_from (target, candidate))
8185 return FALSE;
8186 return TRUE;
8190 * @container the generic container from the GTD
8191 * @klass: the class to be assigned to
8192 * @oklass: the source class
8194 * Both @klass and @oklass must be instances of the same generic interface.
8196 * Returns: TRUE if @klass can be assigned to a @klass variable
8198 gboolean
8199 mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
8201 int j;
8202 MonoType **klass_argv, **oklass_argv;
8203 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
8204 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
8206 if (klass == oklass)
8207 return TRUE;
8209 /*Viable candidates are instances of the same generic interface*/
8210 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
8211 return FALSE;
8213 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
8214 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
8216 for (j = 0; j < container->type_argc; ++j) {
8217 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
8218 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
8220 if (param1_class->valuetype != param2_class->valuetype || (param1_class->valuetype && param1_class != param2_class))
8221 return FALSE;
8224 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
8225 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
8227 if (param1_class != param2_class) {
8228 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
8229 if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
8230 return FALSE;
8231 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
8232 if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
8233 return FALSE;
8234 } else
8235 return FALSE;
8238 return TRUE;
8241 static gboolean
8242 mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
8244 MonoGenericParam *gparam, *ogparam;
8245 MonoGenericParamInfo *tinfo, *cinfo;
8246 MonoClass **candidate_class;
8247 gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
8248 int tmask, cmask;
8250 if (target == candidate)
8251 return TRUE;
8252 if (target->byval_arg.type != candidate->byval_arg.type)
8253 return FALSE;
8255 gparam = target->byval_arg.data.generic_param;
8256 ogparam = candidate->byval_arg.data.generic_param;
8257 tinfo = mono_generic_param_info (gparam);
8258 cinfo = mono_generic_param_info (ogparam);
8260 class_constraint_satisfied = FALSE;
8261 valuetype_constraint_satisfied = FALSE;
8263 /*candidate must have a super set of target's special constraints*/
8264 tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
8265 cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
8267 if (cinfo->constraints) {
8268 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8269 MonoClass *cc = *candidate_class;
8271 if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
8272 class_constraint_satisfied = TRUE;
8273 else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
8274 valuetype_constraint_satisfied = TRUE;
8277 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
8278 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
8280 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
8281 return FALSE;
8282 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
8283 return FALSE;
8284 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
8285 valuetype_constraint_satisfied)) {
8286 return FALSE;
8290 /*candidate type constraints must be a superset of target's*/
8291 if (tinfo->constraints) {
8292 MonoClass **target_class;
8293 for (target_class = tinfo->constraints; *target_class; ++target_class) {
8294 MonoClass *tc = *target_class;
8297 * A constraint from @target might inflate into @candidate itself and in that case we don't need
8298 * check it's constraints since it satisfy the constraint by itself.
8300 if (mono_metadata_type_equal (&tc->byval_arg, &candidate->byval_arg))
8301 continue;
8303 if (!cinfo->constraints)
8304 return FALSE;
8306 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8307 MonoClass *cc = *candidate_class;
8309 if (mono_class_is_assignable_from (tc, cc))
8310 break;
8313 * This happens when we have the following:
8315 * Bar<K> where K : IFace
8316 * Foo<T, U> where T : U where U : IFace
8317 * ...
8318 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
8321 if (mono_type_is_generic_argument (&cc->byval_arg)) {
8322 if (mono_gparam_is_assignable_from (target, cc))
8323 break;
8326 if (!*candidate_class)
8327 return FALSE;
8331 /*candidate itself must have a constraint that satisfy target*/
8332 if (cinfo->constraints) {
8333 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8334 MonoClass *cc = *candidate_class;
8335 if (mono_class_is_assignable_from (target, cc))
8336 return TRUE;
8339 return FALSE;
8343 * mono_class_is_assignable_from:
8344 * @klass: the class to be assigned to
8345 * @oklass: the source class
8347 * Returns: TRUE if an instance of object oklass can be assigned to an
8348 * instance of object @klass
8350 gboolean
8351 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
8353 MonoError error;
8354 /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
8355 if (!klass->inited)
8356 mono_class_init (klass);
8358 if (!oklass->inited)
8359 mono_class_init (oklass);
8361 if (mono_class_has_failure (klass) || mono_class_has_failure (oklass))
8362 return FALSE;
8364 if (mono_type_is_generic_argument (&klass->byval_arg)) {
8365 if (!mono_type_is_generic_argument (&oklass->byval_arg))
8366 return FALSE;
8367 return mono_gparam_is_assignable_from (klass, oklass);
8370 if (MONO_CLASS_IS_INTERFACE (klass)) {
8371 if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
8372 MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
8373 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
8374 int i;
8376 if (constraints) {
8377 for (i = 0; constraints [i]; ++i) {
8378 if (mono_class_is_assignable_from (klass, constraints [i]))
8379 return TRUE;
8383 return FALSE;
8386 /* interface_offsets might not be set for dynamic classes */
8387 if (mono_class_get_ref_info_handle (oklass) && !oklass->interface_bitmap) {
8389 * oklass might be a generic type parameter but they have
8390 * interface_offsets set.
8392 gboolean result = mono_reflection_call_is_assignable_to (oklass, klass, &error);
8393 if (!is_ok (&error)) {
8394 mono_error_cleanup (&error);
8395 return FALSE;
8397 return result;
8399 if (!oklass->interface_bitmap)
8400 /* Happens with generic instances of not-yet created dynamic types */
8401 return FALSE;
8402 if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
8403 return TRUE;
8405 if (mono_class_has_variant_generic_params (klass)) {
8406 int i;
8407 mono_class_setup_interfaces (oklass, &error);
8408 if (!mono_error_ok (&error)) {
8409 mono_error_cleanup (&error);
8410 return FALSE;
8413 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
8414 for (i = 0; i < oklass->interface_offsets_count; ++i) {
8415 MonoClass *iface = oklass->interfaces_packed [i];
8417 if (mono_class_is_variant_compatible (klass, iface, FALSE))
8418 return TRUE;
8421 return FALSE;
8422 } else if (klass->delegate) {
8423 if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE))
8424 return TRUE;
8425 }else if (klass->rank) {
8426 MonoClass *eclass, *eoclass;
8428 if (oklass->rank != klass->rank)
8429 return FALSE;
8431 /* vectors vs. one dimensional arrays */
8432 if (oklass->byval_arg.type != klass->byval_arg.type)
8433 return FALSE;
8435 eclass = klass->cast_class;
8436 eoclass = oklass->cast_class;
8439 * a is b does not imply a[] is b[] when a is a valuetype, and
8440 * b is a reference type.
8443 if (eoclass->valuetype) {
8444 if ((eclass == mono_defaults.enum_class) ||
8445 (eclass == mono_defaults.enum_class->parent) ||
8446 (eclass == mono_defaults.object_class))
8447 return FALSE;
8450 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
8451 } else if (mono_class_is_nullable (klass)) {
8452 if (mono_class_is_nullable (oklass))
8453 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
8454 else
8455 return mono_class_is_assignable_from (klass->cast_class, oklass);
8456 } else if (klass == mono_defaults.object_class)
8457 return TRUE;
8459 return mono_class_has_parent (oklass, klass);
8462 /*Check if @oklass is variant compatible with @klass.*/
8463 static gboolean
8464 mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
8466 int j;
8467 MonoType **klass_argv, **oklass_argv;
8468 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
8469 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
8471 /*Viable candidates are instances of the same generic interface*/
8472 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
8473 return FALSE;
8475 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
8476 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
8478 for (j = 0; j < container->type_argc; ++j) {
8479 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
8480 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
8482 if (param1_class->valuetype != param2_class->valuetype)
8483 return FALSE;
8486 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
8487 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
8489 if (param1_class != param2_class) {
8490 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
8491 if (!mono_class_is_assignable_from_slow (param1_class, param2_class))
8492 return FALSE;
8493 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
8494 if (!mono_class_is_assignable_from_slow (param2_class, param1_class))
8495 return FALSE;
8496 } else
8497 return FALSE;
8500 return TRUE;
8502 /*Check if @candidate implements the interface @target*/
8503 static gboolean
8504 mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
8506 MonoError error;
8507 int i;
8508 gboolean is_variant = mono_class_has_variant_generic_params (target);
8510 if (is_variant && MONO_CLASS_IS_INTERFACE (candidate)) {
8511 if (mono_class_is_variant_compatible_slow (target, candidate))
8512 return TRUE;
8515 do {
8516 if (candidate == target)
8517 return TRUE;
8519 /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
8520 if (image_is_dynamic (candidate->image) && !candidate->wastypebuilder) {
8521 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info (candidate);
8522 int j;
8523 if (tb && tb->interfaces) {
8524 for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
8525 MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
8526 MonoClass *iface_class;
8528 /* we can't realize the type here since it can do pretty much anything. */
8529 if (!iface->type)
8530 continue;
8531 iface_class = mono_class_from_mono_type (iface->type);
8532 if (iface_class == target)
8533 return TRUE;
8534 if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class))
8535 return TRUE;
8536 if (mono_class_implement_interface_slow (target, iface_class))
8537 return TRUE;
8540 } else {
8541 /*setup_interfaces don't mono_class_init anything*/
8542 /*FIXME this doesn't handle primitive type arrays.
8543 ICollection<sbyte> x byte [] won't work because candidate->interfaces, for byte[], won't have IList<sbyte>.
8544 A possible way to fix this would be to move that to setup_interfaces from setup_interface_offsets.
8546 mono_class_setup_interfaces (candidate, &error);
8547 if (!mono_error_ok (&error)) {
8548 mono_error_cleanup (&error);
8549 return FALSE;
8552 for (i = 0; i < candidate->interface_count; ++i) {
8553 if (candidate->interfaces [i] == target)
8554 return TRUE;
8556 if (is_variant && mono_class_is_variant_compatible_slow (target, candidate->interfaces [i]))
8557 return TRUE;
8559 if (mono_class_implement_interface_slow (target, candidate->interfaces [i]))
8560 return TRUE;
8563 candidate = candidate->parent;
8564 } while (candidate);
8566 return FALSE;
8570 * Check if @oklass can be assigned to @klass.
8571 * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context.
8573 gboolean
8574 mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
8576 if (candidate == target)
8577 return TRUE;
8578 if (target == mono_defaults.object_class)
8579 return TRUE;
8581 if (mono_class_has_parent (candidate, target))
8582 return TRUE;
8584 /*If target is not an interface there is no need to check them.*/
8585 if (MONO_CLASS_IS_INTERFACE (target))
8586 return mono_class_implement_interface_slow (target, candidate);
8588 if (target->delegate && mono_class_has_variant_generic_params (target))
8589 return mono_class_is_variant_compatible (target, candidate, FALSE);
8591 if (target->rank) {
8592 MonoClass *eclass, *eoclass;
8594 if (target->rank != candidate->rank)
8595 return FALSE;
8597 /* vectors vs. one dimensional arrays */
8598 if (target->byval_arg.type != candidate->byval_arg.type)
8599 return FALSE;
8601 eclass = target->cast_class;
8602 eoclass = candidate->cast_class;
8605 * a is b does not imply a[] is b[] when a is a valuetype, and
8606 * b is a reference type.
8609 if (eoclass->valuetype) {
8610 if ((eclass == mono_defaults.enum_class) ||
8611 (eclass == mono_defaults.enum_class->parent) ||
8612 (eclass == mono_defaults.object_class))
8613 return FALSE;
8616 return mono_class_is_assignable_from_slow (target->cast_class, candidate->cast_class);
8618 /*FIXME properly handle nullables */
8619 /*FIXME properly handle (M)VAR */
8620 return FALSE;
8624 * mono_class_get_cctor:
8625 * @klass: A MonoClass pointer
8627 * Returns: The static constructor of @klass if it exists, NULL otherwise.
8629 MonoMethod*
8630 mono_class_get_cctor (MonoClass *klass)
8632 MonoCachedClassInfo cached_info;
8634 if (image_is_dynamic (klass->image)) {
8636 * has_cctor is not set for these classes because mono_class_init () is
8637 * not run for them.
8639 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8642 if (!klass->has_cctor)
8643 return NULL;
8645 if (mono_class_get_cached_class_info (klass, &cached_info)) {
8646 MonoError error;
8647 MonoMethod *result = mono_get_method_checked (klass->image, cached_info.cctor_token, klass, NULL, &error);
8648 if (!mono_error_ok (&error))
8649 g_error ("Could not lookup class cctor from cached metadata due to %s", mono_error_get_message (&error));
8650 return result;
8653 if (mono_class_is_ginst (klass) && !klass->methods)
8654 return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class));
8656 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8660 * mono_class_get_finalizer:
8661 * @klass: The MonoClass pointer
8663 * Returns: The finalizer method of @klass if it exists, NULL otherwise.
8665 MonoMethod*
8666 mono_class_get_finalizer (MonoClass *klass)
8668 MonoCachedClassInfo cached_info;
8670 if (!klass->inited)
8671 mono_class_init (klass);
8672 if (!mono_class_has_finalizer (klass))
8673 return NULL;
8675 if (mono_class_get_cached_class_info (klass, &cached_info)) {
8676 MonoError error;
8677 MonoMethod *result = mono_get_method_checked (cached_info.finalize_image, cached_info.finalize_token, NULL, NULL, &error);
8678 if (!mono_error_ok (&error))
8679 g_error ("Could not lookup finalizer from cached metadata due to %s", mono_error_get_message (&error));
8680 return result;
8681 }else {
8682 mono_class_setup_vtable (klass);
8683 return klass->vtable [finalize_slot];
8688 * mono_class_needs_cctor_run:
8689 * @klass: the MonoClass pointer
8690 * @caller: a MonoMethod describing the caller
8692 * Determines whenever the class has a static constructor and whenever it
8693 * needs to be called when executing CALLER.
8695 gboolean
8696 mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
8698 MonoMethod *method;
8700 method = mono_class_get_cctor (klass);
8701 if (method)
8702 return (method == caller) ? FALSE : TRUE;
8703 else
8704 return FALSE;
8708 * mono_class_array_element_size:
8709 * @klass:
8711 * Returns: The number of bytes an element of type @klass
8712 * uses when stored into an array.
8714 gint32
8715 mono_class_array_element_size (MonoClass *klass)
8717 MonoType *type = &klass->byval_arg;
8719 handle_enum:
8720 switch (type->type) {
8721 case MONO_TYPE_I1:
8722 case MONO_TYPE_U1:
8723 case MONO_TYPE_BOOLEAN:
8724 return 1;
8725 case MONO_TYPE_I2:
8726 case MONO_TYPE_U2:
8727 case MONO_TYPE_CHAR:
8728 return 2;
8729 case MONO_TYPE_I4:
8730 case MONO_TYPE_U4:
8731 case MONO_TYPE_R4:
8732 return 4;
8733 case MONO_TYPE_I:
8734 case MONO_TYPE_U:
8735 case MONO_TYPE_PTR:
8736 case MONO_TYPE_CLASS:
8737 case MONO_TYPE_STRING:
8738 case MONO_TYPE_OBJECT:
8739 case MONO_TYPE_SZARRAY:
8740 case MONO_TYPE_ARRAY:
8741 return sizeof (gpointer);
8742 case MONO_TYPE_I8:
8743 case MONO_TYPE_U8:
8744 case MONO_TYPE_R8:
8745 return 8;
8746 case MONO_TYPE_VALUETYPE:
8747 if (type->data.klass->enumtype) {
8748 type = mono_class_enum_basetype (type->data.klass);
8749 klass = klass->element_class;
8750 goto handle_enum;
8752 return mono_class_instance_size (klass) - sizeof (MonoObject);
8753 case MONO_TYPE_GENERICINST:
8754 type = &type->data.generic_class->container_class->byval_arg;
8755 goto handle_enum;
8756 case MONO_TYPE_VAR:
8757 case MONO_TYPE_MVAR: {
8758 int align;
8760 return mono_type_size (type, &align);
8762 case MONO_TYPE_VOID:
8763 return 0;
8765 default:
8766 g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
8768 return -1;
8772 * mono_array_element_size:
8773 * @ac: pointer to a #MonoArrayClass
8775 * Returns: The size of single array element.
8777 gint32
8778 mono_array_element_size (MonoClass *ac)
8780 g_assert (ac->rank);
8781 return ac->sizes.element_size;
8784 gpointer
8785 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
8786 MonoGenericContext *context)
8788 MonoError error;
8789 gpointer res = mono_ldtoken_checked (image, token, handle_class, context, &error);
8790 g_assert (mono_error_ok (&error));
8791 return res;
8794 gpointer
8795 mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
8796 MonoGenericContext *context, MonoError *error)
8798 mono_error_init (error);
8800 if (image_is_dynamic (image)) {
8801 MonoClass *tmp_handle_class;
8802 gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
8804 mono_error_assert_ok (error);
8805 g_assert (tmp_handle_class);
8806 if (handle_class)
8807 *handle_class = tmp_handle_class;
8809 if (tmp_handle_class == mono_defaults.typehandle_class)
8810 return &((MonoClass*)obj)->byval_arg;
8811 else
8812 return obj;
8815 switch (token & 0xff000000) {
8816 case MONO_TOKEN_TYPE_DEF:
8817 case MONO_TOKEN_TYPE_REF:
8818 case MONO_TOKEN_TYPE_SPEC: {
8819 MonoType *type;
8820 if (handle_class)
8821 *handle_class = mono_defaults.typehandle_class;
8822 type = mono_type_get_checked (image, token, context, error);
8823 if (!type)
8824 return NULL;
8826 mono_class_init (mono_class_from_mono_type (type));
8827 /* We return a MonoType* as handle */
8828 return type;
8830 case MONO_TOKEN_FIELD_DEF: {
8831 MonoClass *klass;
8832 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
8833 if (!type) {
8834 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
8835 return NULL;
8837 if (handle_class)
8838 *handle_class = mono_defaults.fieldhandle_class;
8839 klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_DEF | type, context, error);
8840 if (!klass)
8841 return NULL;
8843 mono_class_init (klass);
8844 return mono_class_get_field (klass, token);
8846 case MONO_TOKEN_METHOD_DEF:
8847 case MONO_TOKEN_METHOD_SPEC: {
8848 MonoMethod *meth;
8849 meth = mono_get_method_checked (image, token, NULL, context, error);
8850 if (handle_class)
8851 *handle_class = mono_defaults.methodhandle_class;
8852 if (!meth)
8853 return NULL;
8855 return meth;
8857 case MONO_TOKEN_MEMBER_REF: {
8858 guint32 cols [MONO_MEMBERREF_SIZE];
8859 const char *sig;
8860 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE);
8861 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
8862 mono_metadata_decode_blob_size (sig, &sig);
8863 if (*sig == 0x6) { /* it's a field */
8864 MonoClass *klass;
8865 MonoClassField *field;
8866 field = mono_field_from_token_checked (image, token, &klass, context, error);
8867 if (handle_class)
8868 *handle_class = mono_defaults.fieldhandle_class;
8869 return field;
8870 } else {
8871 MonoMethod *meth;
8872 meth = mono_get_method_checked (image, token, NULL, context, error);
8873 if (handle_class)
8874 *handle_class = mono_defaults.methodhandle_class;
8875 return meth;
8878 default:
8879 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
8881 return NULL;
8884 gpointer
8885 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
8887 MonoClass *handle_class;
8888 mono_error_init (error);
8889 return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
8892 gpointer
8893 mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
8895 return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
8898 static MonoGetCachedClassInfo get_cached_class_info = NULL;
8900 void
8901 mono_install_get_cached_class_info (MonoGetCachedClassInfo func)
8903 get_cached_class_info = func;
8906 static gboolean
8907 mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
8909 if (!get_cached_class_info)
8910 return FALSE;
8911 else
8912 return get_cached_class_info (klass, res);
8915 void
8916 mono_install_get_class_from_name (MonoGetClassFromName func)
8918 get_class_from_name = func;
8922 * mono_class_get_image:
8924 * Use this method to get the `MonoImage*` where this class came from.
8926 * Returns: The image where this class is defined.
8928 MonoImage*
8929 mono_class_get_image (MonoClass *klass)
8931 return klass->image;
8935 * mono_class_get_element_class:
8936 * @klass: the MonoClass to act on
8938 * Use this function to get the element class of an array.
8940 * Returns: The element class of an array.
8942 MonoClass*
8943 mono_class_get_element_class (MonoClass *klass)
8945 return klass->element_class;
8949 * mono_class_is_valuetype:
8950 * @klass: the MonoClass to act on
8952 * Use this method to determine if the provided `MonoClass*` represents a value type,
8953 * or a reference type.
8955 * Returns: TRUE if the MonoClass represents a ValueType, FALSE if it represents a reference type.
8957 gboolean
8958 mono_class_is_valuetype (MonoClass *klass)
8960 return klass->valuetype;
8964 * mono_class_is_enum:
8965 * @klass: the MonoClass to act on
8967 * Use this function to determine if the provided `MonoClass*` represents an enumeration.
8969 * Returns: TRUE if the MonoClass represents an enumeration.
8971 gboolean
8972 mono_class_is_enum (MonoClass *klass)
8974 return klass->enumtype;
8978 * mono_class_enum_basetype:
8979 * @klass: the MonoClass to act on
8981 * Use this function to get the underlying type for an enumeration value.
8983 * Returns: The underlying type representation for an enumeration.
8985 MonoType*
8986 mono_class_enum_basetype (MonoClass *klass)
8988 if (klass->element_class == klass)
8989 /* SRE or broken types */
8990 return NULL;
8991 else
8992 return &klass->element_class->byval_arg;
8996 * mono_class_get_parent
8997 * @klass: the MonoClass to act on
8999 * Returns: The parent class for this class.
9001 MonoClass*
9002 mono_class_get_parent (MonoClass *klass)
9004 return klass->parent;
9008 * mono_class_get_nesting_type:
9009 * @klass: the MonoClass to act on
9011 * Use this function to obtain the class that the provided `MonoClass*` is nested on.
9013 * If the return is NULL, this indicates that this class is not nested.
9015 * Returns: The container type where this type is nested or NULL if this type is not a nested type.
9017 MonoClass*
9018 mono_class_get_nesting_type (MonoClass *klass)
9020 return klass->nested_in;
9024 * mono_class_get_rank:
9025 * @klass: the MonoClass to act on
9027 * Returns: The rank for the array (the number of dimensions).
9030 mono_class_get_rank (MonoClass *klass)
9032 return klass->rank;
9036 * mono_class_get_name
9037 * @klass: the MonoClass to act on
9039 * Returns: The name of the class.
9041 const char*
9042 mono_class_get_name (MonoClass *klass)
9044 return klass->name;
9048 * mono_class_get_namespace:
9049 * @klass: the MonoClass to act on
9051 * Returns: The namespace of the class.
9053 const char*
9054 mono_class_get_namespace (MonoClass *klass)
9056 return klass->name_space;
9060 * mono_class_get_type:
9061 * @klass: the MonoClass to act on
9063 * This method returns the internal Type representation for the class.
9065 * Returns: The MonoType from the class.
9067 MonoType*
9068 mono_class_get_type (MonoClass *klass)
9070 return &klass->byval_arg;
9074 * mono_class_get_type_token:
9075 * @klass: the MonoClass to act on
9077 * This method returns type token for the class.
9079 * Returns: The type token for the class.
9081 guint32
9082 mono_class_get_type_token (MonoClass *klass)
9084 return klass->type_token;
9088 * mono_class_get_byref_type:
9089 * @klass: the MonoClass to act on
9093 MonoType*
9094 mono_class_get_byref_type (MonoClass *klass)
9096 return &klass->this_arg;
9100 * mono_class_num_fields:
9101 * @klass: the MonoClass to act on
9103 * Returns: The number of static and instance fields in the class.
9106 mono_class_num_fields (MonoClass *klass)
9108 return mono_class_get_field_count (klass);
9112 * mono_class_num_methods:
9113 * @klass: the MonoClass to act on
9115 * Returns: The number of methods in the class.
9118 mono_class_num_methods (MonoClass *klass)
9120 return mono_class_get_method_count (klass);
9124 * mono_class_num_properties
9125 * @klass: the MonoClass to act on
9127 * Returns: The number of properties in the class.
9130 mono_class_num_properties (MonoClass *klass)
9132 mono_class_setup_properties (klass);
9134 return mono_class_get_ext (klass)->property.count;
9138 * mono_class_num_events:
9139 * @klass: the MonoClass to act on
9141 * Returns: The number of events in the class.
9144 mono_class_num_events (MonoClass *klass)
9146 mono_class_setup_events (klass);
9148 return mono_class_get_ext (klass)->event.count;
9152 * mono_class_get_fields:
9153 * @klass: the MonoClass to act on
9155 * This routine is an iterator routine for retrieving the fields in a class.
9157 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9158 * iterate over all of the elements. When no more values are
9159 * available, the return value is NULL.
9161 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
9163 MonoClassField*
9164 mono_class_get_fields (MonoClass* klass, gpointer *iter)
9166 MonoClassField* field;
9167 if (!iter)
9168 return NULL;
9169 if (!*iter) {
9170 mono_class_setup_fields (klass);
9171 if (mono_class_has_failure (klass))
9172 return NULL;
9173 /* start from the first */
9174 if (mono_class_get_field_count (klass)) {
9175 *iter = &klass->fields [0];
9176 return &klass->fields [0];
9177 } else {
9178 /* no fields */
9179 return NULL;
9182 field = (MonoClassField *)*iter;
9183 field++;
9184 if (field < &klass->fields [mono_class_get_field_count (klass)]) {
9185 *iter = field;
9186 return field;
9188 return NULL;
9192 * mono_class_get_methods
9193 * @klass: the MonoClass to act on
9195 * This routine is an iterator routine for retrieving the fields in a class.
9197 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9198 * iterate over all of the elements. When no more values are
9199 * available, the return value is NULL.
9201 * Returns: a MonoMethod on each iteration or NULL when no more methods are available.
9203 MonoMethod*
9204 mono_class_get_methods (MonoClass* klass, gpointer *iter)
9206 MonoMethod** method;
9207 if (!iter)
9208 return NULL;
9209 if (!*iter) {
9210 mono_class_setup_methods (klass);
9213 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9214 * FIXME we should better report this error to the caller
9216 if (!klass->methods)
9217 return NULL;
9218 /* start from the first */
9219 if (mono_class_get_method_count (klass)) {
9220 *iter = &klass->methods [0];
9221 return klass->methods [0];
9222 } else {
9223 /* no method */
9224 return NULL;
9227 method = (MonoMethod **)*iter;
9228 method++;
9229 if (method < &klass->methods [mono_class_get_method_count (klass)]) {
9230 *iter = method;
9231 return *method;
9233 return NULL;
9237 * mono_class_get_virtual_methods:
9239 * Iterate over the virtual methods of KLASS.
9241 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
9243 static MonoMethod*
9244 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
9246 MonoMethod** method;
9247 if (!iter)
9248 return NULL;
9249 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
9250 if (!*iter) {
9251 mono_class_setup_methods (klass);
9253 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9254 * FIXME we should better report this error to the caller
9256 if (!klass->methods)
9257 return NULL;
9258 /* start from the first */
9259 method = &klass->methods [0];
9260 } else {
9261 method = (MonoMethod **)*iter;
9262 method++;
9264 int mcount = mono_class_get_method_count (klass);
9265 while (method < &klass->methods [mcount]) {
9266 if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
9267 break;
9268 method ++;
9270 if (method < &klass->methods [mcount]) {
9271 *iter = method;
9272 return *method;
9273 } else {
9274 return NULL;
9276 } else {
9277 /* Search directly in metadata to avoid calling setup_methods () */
9278 MonoMethod *res = NULL;
9279 int i, start_index;
9281 if (!*iter) {
9282 start_index = 0;
9283 } else {
9284 start_index = GPOINTER_TO_UINT (*iter);
9287 int first_idx = mono_class_get_first_method_idx (klass);
9288 int mcount = mono_class_get_method_count (klass);
9289 for (i = start_index; i < mcount; ++i) {
9290 guint32 flags;
9292 /* first_idx points into the methodptr table */
9293 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
9295 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
9296 break;
9299 if (i < mcount) {
9300 MonoError error;
9301 res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
9302 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9304 /* Add 1 here so the if (*iter) check fails */
9305 *iter = GUINT_TO_POINTER (i + 1);
9306 return res;
9307 } else {
9308 return NULL;
9314 * mono_class_get_properties:
9315 * @klass: the MonoClass to act on
9317 * This routine is an iterator routine for retrieving the properties in a class.
9319 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9320 * iterate over all of the elements. When no more values are
9321 * available, the return value is NULL.
9323 * Returns: a @MonoProperty* on each invocation, or NULL when no more are available.
9325 MonoProperty*
9326 mono_class_get_properties (MonoClass* klass, gpointer *iter)
9328 MonoProperty* property;
9329 if (!iter)
9330 return NULL;
9331 if (!*iter) {
9332 mono_class_setup_properties (klass);
9333 MonoClassExt *ext = mono_class_get_ext (klass);
9334 /* start from the first */
9335 if (ext->property.count) {
9336 *iter = &ext->properties [0];
9337 return (MonoProperty *)*iter;
9338 } else {
9339 /* no fields */
9340 return NULL;
9343 property = (MonoProperty *)*iter;
9344 property++;
9345 MonoClassExt *ext = mono_class_get_ext (klass);
9346 if (property < &ext->properties [ext->property.count]) {
9347 *iter = property;
9348 return (MonoProperty *)*iter;
9350 return NULL;
9354 * mono_class_get_events:
9355 * @klass: the MonoClass to act on
9357 * This routine is an iterator routine for retrieving the properties in a class.
9359 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9360 * iterate over all of the elements. When no more values are
9361 * available, the return value is NULL.
9363 * Returns: a @MonoEvent* on each invocation, or NULL when no more are available.
9365 MonoEvent*
9366 mono_class_get_events (MonoClass* klass, gpointer *iter)
9368 MonoEvent* event;
9369 if (!iter)
9370 return NULL;
9371 if (!*iter) {
9372 mono_class_setup_events (klass);
9373 MonoClassExt *ext = mono_class_get_ext (klass);
9374 /* start from the first */
9375 if (ext->event.count) {
9376 *iter = &ext->events [0];
9377 return (MonoEvent *)*iter;
9378 } else {
9379 /* no fields */
9380 return NULL;
9383 event = (MonoEvent *)*iter;
9384 event++;
9385 MonoClassExt *ext = mono_class_get_ext (klass);
9386 if (event < &ext->events [ext->event.count]) {
9387 *iter = event;
9388 return (MonoEvent *)*iter;
9390 return NULL;
9394 * mono_class_get_interfaces
9395 * @klass: the MonoClass to act on
9397 * This routine is an iterator routine for retrieving the interfaces implemented by this class.
9399 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9400 * iterate over all of the elements. When no more values are
9401 * available, the return value is NULL.
9403 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
9405 MonoClass*
9406 mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
9408 MonoError error;
9409 MonoClass** iface;
9410 if (!iter)
9411 return NULL;
9412 if (!*iter) {
9413 if (!klass->inited)
9414 mono_class_init (klass);
9415 if (!klass->interfaces_inited) {
9416 mono_class_setup_interfaces (klass, &error);
9417 if (!mono_error_ok (&error)) {
9418 mono_error_cleanup (&error);
9419 return NULL;
9422 /* start from the first */
9423 if (klass->interface_count) {
9424 *iter = &klass->interfaces [0];
9425 return klass->interfaces [0];
9426 } else {
9427 /* no interface */
9428 return NULL;
9431 iface = (MonoClass **)*iter;
9432 iface++;
9433 if (iface < &klass->interfaces [klass->interface_count]) {
9434 *iter = iface;
9435 return *iface;
9437 return NULL;
9440 static void
9441 setup_nested_types (MonoClass *klass)
9443 MonoError error;
9444 GList *classes, *nested_classes, *l;
9445 int i;
9447 if (klass->nested_classes_inited)
9448 return;
9450 if (!klass->type_token)
9451 klass->nested_classes_inited = TRUE;
9453 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
9454 classes = NULL;
9455 while (i) {
9456 MonoClass* nclass;
9457 guint32 cols [MONO_NESTED_CLASS_SIZE];
9458 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
9459 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error);
9460 if (!mono_error_ok (&error)) {
9461 /*FIXME don't swallow the error message*/
9462 mono_error_cleanup (&error);
9464 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
9465 continue;
9468 classes = g_list_prepend (classes, nclass);
9470 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
9473 mono_class_alloc_ext (klass);
9475 nested_classes = NULL;
9476 for (l = classes; l; l = l->next)
9477 nested_classes = g_list_prepend_image (klass->image, nested_classes, l->data);
9478 g_list_free (classes);
9480 mono_image_lock (klass->image);
9482 mono_memory_barrier ();
9483 if (!klass->nested_classes_inited) {
9484 mono_class_get_ext (klass)->nested_classes = nested_classes;
9485 mono_memory_barrier ();
9486 klass->nested_classes_inited = TRUE;
9489 mono_image_unlock (klass->image);
9493 * mono_class_get_nested_types
9494 * @klass: the MonoClass to act on
9496 * This routine is an iterator routine for retrieving the nested types of a class.
9497 * This works only if @klass is non-generic, or a generic type definition.
9499 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9500 * iterate over all of the elements. When no more values are
9501 * available, the return value is NULL.
9503 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
9505 MonoClass*
9506 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
9508 GList *item;
9510 if (!iter)
9511 return NULL;
9512 if (!klass->nested_classes_inited)
9513 setup_nested_types (klass);
9515 if (!*iter) {
9516 MonoClassExt *ext = mono_class_get_ext (klass);
9517 /* start from the first */
9518 if (ext && ext->nested_classes) {
9519 *iter = ext->nested_classes;
9520 return (MonoClass *)ext->nested_classes->data;
9521 } else {
9522 /* no nested types */
9523 return NULL;
9526 item = (GList *)*iter;
9527 item = item->next;
9528 if (item) {
9529 *iter = item;
9530 return (MonoClass *)item->data;
9532 return NULL;
9537 * mono_class_is_delegate
9538 * @klass: the MonoClass to act on
9540 * Returns: TRUE if the MonoClass represents a System.Delegate.
9542 mono_bool
9543 mono_class_is_delegate (MonoClass *klass)
9545 return klass->delegate;
9549 * mono_class_implements_interface
9550 * @klass: The MonoClass to act on
9551 * @interface: The interface to check if @klass implements.
9553 * Returns: TRUE if @klass implements @interface.
9555 mono_bool
9556 mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
9558 return mono_class_is_assignable_from (iface, klass);
9562 * mono_field_get_name:
9563 * @field: the MonoClassField to act on
9565 * Returns: The name of the field.
9567 const char*
9568 mono_field_get_name (MonoClassField *field)
9570 return field->name;
9574 * mono_field_get_type:
9575 * @field: the MonoClassField to act on
9577 * Returns: MonoType of the field.
9579 MonoType*
9580 mono_field_get_type (MonoClassField *field)
9582 MonoError error;
9583 MonoType *type = mono_field_get_type_checked (field, &error);
9584 if (!mono_error_ok (&error)) {
9585 mono_trace_warning (MONO_TRACE_TYPE, "Could not load field's type due to %s", mono_error_get_message (&error));
9586 mono_error_cleanup (&error);
9588 return type;
9593 * mono_field_get_type_checked:
9594 * @field: the MonoClassField to act on
9595 * @error: used to return any erro found while retrieving @field type
9597 * Returns: MonoType of the field.
9599 MonoType*
9600 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
9602 mono_error_init (error);
9603 if (!field->type)
9604 mono_field_resolve_type (field, error);
9605 return field->type;
9609 * mono_field_get_parent:
9610 * @field: the MonoClassField to act on
9612 * Returns: MonoClass where the field was defined.
9614 MonoClass*
9615 mono_field_get_parent (MonoClassField *field)
9617 return field->parent;
9621 * mono_field_get_flags;
9622 * @field: the MonoClassField to act on
9624 * The metadata flags for a field are encoded using the
9625 * FIELD_ATTRIBUTE_* constants. See the tabledefs.h file for details.
9627 * Returns: The flags for the field.
9629 guint32
9630 mono_field_get_flags (MonoClassField *field)
9632 if (!field->type)
9633 return mono_field_resolve_flags (field);
9634 return field->type->attrs;
9638 * mono_field_get_offset:
9639 * @field: the MonoClassField to act on
9641 * Returns: The field offset.
9643 guint32
9644 mono_field_get_offset (MonoClassField *field)
9646 return field->offset;
9649 static const char *
9650 mono_field_get_rva (MonoClassField *field)
9652 guint32 rva;
9653 int field_index;
9654 MonoClass *klass = field->parent;
9655 MonoFieldDefaultValue *field_def_values;
9657 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
9659 MonoClassExt *ext = mono_class_get_ext (klass);
9660 if (!ext || !ext->field_def_values) {
9661 mono_class_alloc_ext (klass);
9662 ext = mono_class_get_ext (klass);
9664 field_def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
9666 mono_image_lock (klass->image);
9667 if (!ext->field_def_values)
9668 ext->field_def_values = field_def_values;
9669 mono_image_unlock (klass->image);
9672 field_index = mono_field_get_index (field);
9674 if (!ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) {
9675 int first_field_idx = mono_class_get_first_field_idx (klass);
9676 mono_metadata_field_info (field->parent->image, first_field_idx + field_index, NULL, &rva, NULL);
9677 if (!rva)
9678 g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
9679 ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
9682 return ext->field_def_values [field_index].data;
9686 * mono_field_get_data:
9687 * @field: the MonoClassField to act on
9689 * Returns: A pointer to the metadata constant value or to the field
9690 * data if it has an RVA flag.
9692 const char *
9693 mono_field_get_data (MonoClassField *field)
9695 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
9696 MonoTypeEnum def_type;
9698 return mono_class_get_field_default_value (field, &def_type);
9699 } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
9700 return mono_field_get_rva (field);
9701 } else {
9702 return NULL;
9707 * mono_property_get_name:
9708 * @prop: the MonoProperty to act on
9710 * Returns: The name of the property
9712 const char*
9713 mono_property_get_name (MonoProperty *prop)
9715 return prop->name;
9719 * mono_property_get_set_method
9720 * @prop: the MonoProperty to act on.
9722 * Returns: The setter method of the property (A MonoMethod)
9724 MonoMethod*
9725 mono_property_get_set_method (MonoProperty *prop)
9727 return prop->set;
9731 * mono_property_get_get_method
9732 * @prop: the MonoProperty to act on.
9734 * Returns: The setter method of the property (A MonoMethod)
9736 MonoMethod*
9737 mono_property_get_get_method (MonoProperty *prop)
9739 return prop->get;
9743 * mono_property_get_parent:
9744 * @prop: the MonoProperty to act on.
9746 * Returns: The MonoClass where the property was defined.
9748 MonoClass*
9749 mono_property_get_parent (MonoProperty *prop)
9751 return prop->parent;
9755 * mono_property_get_flags:
9756 * @prop: the MonoProperty to act on.
9758 * The metadata flags for a property are encoded using the
9759 * PROPERTY_ATTRIBUTE_* constants. See the tabledefs.h file for details.
9761 * Returns: The flags for the property.
9763 guint32
9764 mono_property_get_flags (MonoProperty *prop)
9766 return prop->attrs;
9770 * mono_event_get_name:
9771 * @event: the MonoEvent to act on
9773 * Returns: The name of the event.
9775 const char*
9776 mono_event_get_name (MonoEvent *event)
9778 return event->name;
9782 * mono_event_get_add_method:
9783 * @event: The MonoEvent to act on.
9785 * Returns: The @add' method for the event (a MonoMethod).
9787 MonoMethod*
9788 mono_event_get_add_method (MonoEvent *event)
9790 return event->add;
9794 * mono_event_get_remove_method:
9795 * @event: The MonoEvent to act on.
9797 * Returns: The @remove method for the event (a MonoMethod).
9799 MonoMethod*
9800 mono_event_get_remove_method (MonoEvent *event)
9802 return event->remove;
9806 * mono_event_get_raise_method:
9807 * @event: The MonoEvent to act on.
9809 * Returns: The @raise method for the event (a MonoMethod).
9811 MonoMethod*
9812 mono_event_get_raise_method (MonoEvent *event)
9814 return event->raise;
9818 * mono_event_get_parent:
9819 * @event: the MonoEvent to act on.
9821 * Returns: The MonoClass where the event is defined.
9823 MonoClass*
9824 mono_event_get_parent (MonoEvent *event)
9826 return event->parent;
9830 * mono_event_get_flags
9831 * @event: the MonoEvent to act on.
9833 * The metadata flags for an event are encoded using the
9834 * EVENT_* constants. See the tabledefs.h file for details.
9836 * Returns: The flags for the event.
9838 guint32
9839 mono_event_get_flags (MonoEvent *event)
9841 return event->attrs;
9845 * mono_class_get_method_from_name:
9846 * @klass: where to look for the method
9847 * @name: name of the method
9848 * @param_count: number of parameters. -1 for any number.
9850 * Obtains a MonoMethod with a given name and number of parameters.
9851 * It only works if there are no multiple signatures for any given method name.
9853 MonoMethod *
9854 mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_count)
9856 return mono_class_get_method_from_name_flags (klass, name, param_count, 0);
9859 static MonoMethod*
9860 find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
9862 MonoMethod *res = NULL;
9863 int i;
9865 /* Search directly in the metadata to avoid calling setup_methods () */
9866 int first_idx = mono_class_get_first_method_idx (klass);
9867 int mcount = mono_class_get_method_count (klass);
9868 for (i = 0; i < mcount; ++i) {
9869 MonoError error;
9870 guint32 cols [MONO_METHOD_SIZE];
9871 MonoMethod *method;
9872 MonoMethodSignature *sig;
9874 /* first_idx points into the methodptr table */
9875 mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE);
9877 if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
9878 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
9879 if (!method) {
9880 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9881 continue;
9883 if (param_count == -1) {
9884 res = method;
9885 break;
9887 sig = mono_method_signature_checked (method, &error);
9888 if (!sig) {
9889 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9890 continue;
9892 if (sig->param_count == param_count) {
9893 res = method;
9894 break;
9899 return res;
9903 * mono_class_get_method_from_name_flags:
9904 * @klass: where to look for the method
9905 * @name_space: name of the method
9906 * @param_count: number of parameters. -1 for any number.
9907 * @flags: flags which must be set in the method
9909 * Obtains a MonoMethod with a given name and number of parameters.
9910 * It only works if there are no multiple signatures for any given method name.
9912 MonoMethod *
9913 mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int param_count, int flags)
9915 MonoMethod *res = NULL;
9916 int i;
9918 mono_class_init (klass);
9920 if (mono_class_is_ginst (klass) && !klass->methods) {
9921 res = mono_class_get_method_from_name_flags (mono_class_get_generic_class (klass)->container_class, name, param_count, flags);
9922 if (res) {
9923 MonoError error;
9924 res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), &error);
9925 if (!mono_error_ok (&error))
9926 mono_error_cleanup (&error); /*FIXME don't swallow the error */
9928 return res;
9931 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
9932 mono_class_setup_methods (klass);
9934 We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9935 See mono/tests/array_load_exception.il
9936 FIXME we should better report this error to the caller
9938 if (!klass->methods)
9939 return NULL;
9940 int mcount = mono_class_get_method_count (klass);
9941 for (i = 0; i < mcount; ++i) {
9942 MonoMethod *method = klass->methods [i];
9944 if (method->name[0] == name [0] &&
9945 !strcmp (name, method->name) &&
9946 (param_count == -1 || mono_method_signature (method)->param_count == param_count) &&
9947 ((method->flags & flags) == flags)) {
9948 res = method;
9949 break;
9953 else {
9954 res = find_method_in_metadata (klass, name, param_count, flags);
9957 return res;
9961 * mono_class_set_failure:
9962 * @klass: class in which the failure was detected
9963 * @ex_type: the kind of exception/error to be thrown (later)
9964 * @ex_data: exception data (specific to each type of exception/error)
9966 * Keep a detected failure informations in the class for later processing.
9967 * Note that only the first failure is kept.
9969 * LOCKING: Acquires the loader lock.
9971 static gboolean
9972 mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error)
9974 g_assert (boxed_error != NULL);
9976 if (mono_class_has_failure (klass))
9977 return FALSE;
9979 mono_loader_lock ();
9980 klass->has_failure = 1;
9981 mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, boxed_error);
9982 mono_loader_unlock ();
9984 return TRUE;
9987 gboolean
9988 mono_class_has_failure (const MonoClass *klass)
9990 g_assert (klass != NULL);
9991 return klass->has_failure != 0;
9996 * mono_class_set_type_load_failure:
9997 * @klass: class in which the failure was detected
9998 * @fmt: Printf-style error message string.
10000 * Collect detected failure informaion in the class for later processing.
10001 * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class ()
10002 * Note that only the first failure is kept.
10004 * Returns FALSE if a failure was already set on the class, or TRUE otherwise.
10006 * LOCKING: Acquires the loader lock.
10008 gboolean
10009 mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
10011 MonoError prepare_error;
10012 va_list args;
10014 if (mono_class_has_failure (klass))
10015 return FALSE;
10017 mono_error_init (&prepare_error);
10019 va_start (args, fmt);
10020 mono_error_vset_type_load_class (&prepare_error, klass, fmt, args);
10021 va_end (args);
10023 MonoErrorBoxed *box = mono_error_box (&prepare_error, klass->image);
10024 mono_error_cleanup (&prepare_error);
10025 return mono_class_set_failure (klass, box);
10029 * mono_class_get_exception_data:
10031 * Return the exception_data property of KLASS.
10033 * LOCKING: Acquires the loader lock.
10035 static gpointer
10036 mono_class_get_exception_data (const MonoClass *klass)
10038 return mono_image_property_lookup (klass->image, (MonoClass*)klass, MONO_CLASS_PROP_EXCEPTION_DATA);
10042 * mono_classes_init:
10044 * Initialize the resources used by this module.
10046 void
10047 mono_classes_init (void)
10049 mono_os_mutex_init (&classes_mutex);
10051 mono_native_tls_alloc (&setup_fields_tls_id, NULL);
10052 mono_native_tls_alloc (&init_pending_tls_id, NULL);
10054 mono_counters_register ("MonoClassDef count",
10055 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
10056 mono_counters_register ("MonoClassGtd count",
10057 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
10058 mono_counters_register ("MonoClassGenericInst count",
10059 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
10060 mono_counters_register ("MonoClassGenericParam count",
10061 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
10062 mono_counters_register ("MonoClassArray count",
10063 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
10064 mono_counters_register ("MonoClassPointer count",
10065 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
10066 mono_counters_register ("Inflated methods size",
10067 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
10068 mono_counters_register ("Inflated classes size",
10069 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
10070 mono_counters_register ("MonoClass size",
10071 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
10072 mono_counters_register ("MonoClassExt size",
10073 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size);
10075 mono_counters_register ("MonoClassExt count",
10076 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_count);
10080 * mono_classes_cleanup:
10082 * Free the resources used by this module.
10084 void
10085 mono_classes_cleanup (void)
10087 mono_native_tls_free (setup_fields_tls_id);
10088 mono_native_tls_free (init_pending_tls_id);
10090 if (global_interface_bitset)
10091 mono_bitset_free (global_interface_bitset);
10092 global_interface_bitset = NULL;
10093 mono_os_mutex_destroy (&classes_mutex);
10097 * mono_class_get_exception_for_failure:
10098 * @klass: class in which the failure was detected
10100 * Return a constructed MonoException than the caller can then throw
10101 * using mono_raise_exception - or NULL if no failure is present (or
10102 * doesn't result in an exception).
10104 MonoException*
10105 mono_class_get_exception_for_failure (MonoClass *klass)
10107 if (!mono_class_has_failure (klass))
10108 return NULL;
10109 MonoError unboxed_error;
10110 mono_error_init (&unboxed_error);
10111 mono_error_set_for_class_failure (&unboxed_error, klass);
10112 return mono_error_convert_to_exception (&unboxed_error);
10115 static gboolean
10116 is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
10118 outer_klass = mono_class_get_generic_type_definition (outer_klass);
10119 inner_klass = mono_class_get_generic_type_definition (inner_klass);
10120 do {
10121 if (outer_klass == inner_klass)
10122 return TRUE;
10123 inner_klass = inner_klass->nested_in;
10124 } while (inner_klass);
10125 return FALSE;
10128 MonoClass *
10129 mono_class_get_generic_type_definition (MonoClass *klass)
10131 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
10132 return gklass ? gklass->container_class : klass;
10136 * Check if @klass is a subtype of @parent ignoring generic instantiations.
10138 * Generic instantiations are ignored for all super types of @klass.
10140 * Visibility checks ignoring generic instantiations.
10142 gboolean
10143 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
10145 int i;
10146 klass = mono_class_get_generic_type_definition (klass);
10147 parent = mono_class_get_generic_type_definition (parent);
10148 mono_class_setup_supertypes (klass);
10150 for (i = 0; i < klass->idepth; ++i) {
10151 if (parent == mono_class_get_generic_type_definition (klass->supertypes [i]))
10152 return TRUE;
10154 return FALSE;
10157 * Subtype can only access parent members with family protection if the site object
10158 * is subclass of Subtype. For example:
10159 * class A { protected int x; }
10160 * class B : A {
10161 * void valid_access () {
10162 * B b;
10163 * b.x = 0;
10165 * void invalid_access () {
10166 * A a;
10167 * a.x = 0;
10170 * */
10171 static gboolean
10172 is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
10174 if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
10175 return FALSE;
10177 if (context_klass == NULL)
10178 return TRUE;
10179 /*if access_klass is not member_klass context_klass must be type compat*/
10180 if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
10181 return FALSE;
10182 return TRUE;
10185 static gboolean
10186 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
10188 GSList *tmp;
10189 if (accessing == accessed)
10190 return TRUE;
10191 if (!accessed || !accessing)
10192 return FALSE;
10194 /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
10195 * anywhere so untrusted friends are not safe to access platform's code internals */
10196 if (mono_security_core_clr_enabled ()) {
10197 if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
10198 return FALSE;
10201 mono_assembly_load_friends (accessed);
10202 for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
10203 MonoAssemblyName *friend_ = (MonoAssemblyName *)tmp->data;
10204 /* Be conservative with checks */
10205 if (!friend_->name)
10206 continue;
10207 if (strcmp (accessing->aname.name, friend_->name))
10208 continue;
10209 if (friend_->public_key_token [0]) {
10210 if (!accessing->aname.public_key_token [0])
10211 continue;
10212 if (!mono_public_tokens_are_equal (friend_->public_key_token, accessing->aname.public_key_token))
10213 continue;
10215 return TRUE;
10217 return FALSE;
10221 * If klass is a generic type or if it is derived from a generic type, return the
10222 * MonoClass of the generic definition
10223 * Returns NULL if not found
10225 static MonoClass*
10226 get_generic_definition_class (MonoClass *klass)
10228 while (klass) {
10229 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
10230 if (gklass && gklass->container_class)
10231 return gklass->container_class;
10232 klass = klass->parent;
10234 return NULL;
10237 static gboolean
10238 can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
10240 int i;
10241 for (i = 0; i < ginst->type_argc; ++i) {
10242 MonoType *type = ginst->type_argv[i];
10243 switch (type->type) {
10244 case MONO_TYPE_SZARRAY:
10245 if (!can_access_type (access_klass, type->data.klass))
10246 return FALSE;
10247 break;
10248 case MONO_TYPE_ARRAY:
10249 if (!can_access_type (access_klass, type->data.array->eklass))
10250 return FALSE;
10251 break;
10252 case MONO_TYPE_PTR:
10253 if (!can_access_type (access_klass, mono_class_from_mono_type (type->data.type)))
10254 return FALSE;
10255 break;
10256 case MONO_TYPE_CLASS:
10257 case MONO_TYPE_VALUETYPE:
10258 case MONO_TYPE_GENERICINST:
10259 if (!can_access_type (access_klass, mono_class_from_mono_type (type)))
10260 return FALSE;
10261 default:
10262 break;
10265 return TRUE;
10268 static gboolean
10269 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
10271 int access_level;
10273 if (access_klass == member_klass)
10274 return TRUE;
10276 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
10277 return TRUE;
10279 if (access_klass->element_class && !access_klass->enumtype)
10280 access_klass = access_klass->element_class;
10282 if (member_klass->element_class && !member_klass->enumtype)
10283 member_klass = member_klass->element_class;
10285 access_level = mono_class_get_flags (member_klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
10287 if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
10288 return TRUE;
10290 if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst))
10291 return FALSE;
10293 if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
10294 return TRUE;
10296 if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
10297 return FALSE;
10299 /*Non nested type with nested visibility. We just fail it.*/
10300 if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL)
10301 return FALSE;
10303 switch (access_level) {
10304 case TYPE_ATTRIBUTE_NOT_PUBLIC:
10305 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10307 case TYPE_ATTRIBUTE_PUBLIC:
10308 return TRUE;
10310 case TYPE_ATTRIBUTE_NESTED_PUBLIC:
10311 return TRUE;
10313 case TYPE_ATTRIBUTE_NESTED_PRIVATE:
10314 return is_nesting_type (member_klass, access_klass);
10316 case TYPE_ATTRIBUTE_NESTED_FAMILY:
10317 return mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10319 case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
10320 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10322 case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
10323 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) &&
10324 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10326 case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
10327 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) ||
10328 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10330 return FALSE;
10333 /* FIXME: check visibility of type, too */
10334 static gboolean
10335 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
10337 MonoClass *member_generic_def;
10338 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
10339 return TRUE;
10341 MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass);
10342 if (((access_gklass && access_gklass->container_class) ||
10343 mono_class_is_gtd (access_klass)) &&
10344 (member_generic_def = get_generic_definition_class (member_klass))) {
10345 MonoClass *access_container;
10347 if (mono_class_is_gtd (access_klass))
10348 access_container = access_klass;
10349 else
10350 access_container = access_gklass->container_class;
10352 if (can_access_member (access_container, member_generic_def, context_klass, access_level))
10353 return TRUE;
10356 /* Partition I 8.5.3.2 */
10357 /* the access level values are the same for fields and methods */
10358 switch (access_level) {
10359 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
10360 /* same compilation unit */
10361 return access_klass->image == member_klass->image;
10362 case FIELD_ATTRIBUTE_PRIVATE:
10363 return access_klass == member_klass;
10364 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
10365 if (is_valid_family_access (access_klass, member_klass, context_klass) &&
10366 can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
10367 return TRUE;
10368 return FALSE;
10369 case FIELD_ATTRIBUTE_ASSEMBLY:
10370 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10371 case FIELD_ATTRIBUTE_FAMILY:
10372 if (is_valid_family_access (access_klass, member_klass, context_klass))
10373 return TRUE;
10374 return FALSE;
10375 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
10376 if (is_valid_family_access (access_klass, member_klass, context_klass))
10377 return TRUE;
10378 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10379 case FIELD_ATTRIBUTE_PUBLIC:
10380 return TRUE;
10382 return FALSE;
10386 * mono_method_can_access_field:
10387 * @method: Method that will attempt to access the field
10388 * @field: the field to access
10390 * Used to determine if a method is allowed to access the specified field.
10392 * Returns: TRUE if the given @method is allowed to access the @field while following
10393 * the accessibility rules of the CLI.
10395 gboolean
10396 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
10398 /* FIXME: check all overlapping fields */
10399 int can = can_access_member (method->klass, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10400 if (!can) {
10401 MonoClass *nested = method->klass->nested_in;
10402 while (nested) {
10403 can = can_access_member (nested, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10404 if (can)
10405 return TRUE;
10406 nested = nested->nested_in;
10409 return can;
10413 * mono_method_can_access_method:
10414 * @method: Method that will attempt to access the other method
10415 * @called: the method that we want to probe for accessibility.
10417 * Used to determine if the @method is allowed to access the specified @called method.
10419 * Returns: TRUE if the given @method is allowed to invoke the @called while following
10420 * the accessibility rules of the CLI.
10422 gboolean
10423 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
10425 method = mono_method_get_method_definition (method);
10426 called = mono_method_get_method_definition (called);
10427 return mono_method_can_access_method_full (method, called, NULL);
10431 * mono_method_can_access_method_full:
10432 * @method: The caller method
10433 * @called: The called method
10434 * @context_klass: The static type on stack of the owner @called object used
10436 * This function must be used with instance calls, as they have more strict family accessibility.
10437 * It can be used with static methods, but context_klass should be NULL.
10439 * Returns: TRUE if caller have proper visibility and acessibility to @called
10441 gboolean
10442 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
10444 /* Wrappers are except from access checks */
10445 if (method->wrapper_type != MONO_WRAPPER_NONE || called->wrapper_type != MONO_WRAPPER_NONE)
10446 return TRUE;
10448 MonoClass *access_class = method->klass;
10449 MonoClass *member_class = called->klass;
10450 int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10451 if (!can) {
10452 MonoClass *nested = access_class->nested_in;
10453 while (nested) {
10454 can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10455 if (can)
10456 break;
10457 nested = nested->nested_in;
10461 if (!can)
10462 return FALSE;
10464 can = can_access_type (access_class, member_class);
10465 if (!can) {
10466 MonoClass *nested = access_class->nested_in;
10467 while (nested) {
10468 can = can_access_type (nested, member_class);
10469 if (can)
10470 break;
10471 nested = nested->nested_in;
10475 if (!can)
10476 return FALSE;
10478 if (called->is_inflated) {
10479 MonoMethodInflated * infl = (MonoMethodInflated*)called;
10480 if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
10481 return FALSE;
10484 return TRUE;
10489 * mono_method_can_access_field_full:
10490 * @method: The caller method
10491 * @field: The accessed field
10492 * @context_klass: The static type on stack of the owner @field object used
10494 * This function must be used with instance fields, as they have more strict family accessibility.
10495 * It can be used with static fields, but context_klass should be NULL.
10497 * Returns: TRUE if caller have proper visibility and acessibility to @field
10499 gboolean
10500 mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
10502 MonoClass *access_class = method->klass;
10503 MonoClass *member_class = field->parent;
10504 /* FIXME: check all overlapping fields */
10505 int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10506 if (!can) {
10507 MonoClass *nested = access_class->nested_in;
10508 while (nested) {
10509 can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10510 if (can)
10511 break;
10512 nested = nested->nested_in;
10516 if (!can)
10517 return FALSE;
10519 can = can_access_type (access_class, member_class);
10520 if (!can) {
10521 MonoClass *nested = access_class->nested_in;
10522 while (nested) {
10523 can = can_access_type (nested, member_class);
10524 if (can)
10525 break;
10526 nested = nested->nested_in;
10530 if (!can)
10531 return FALSE;
10532 return TRUE;
10536 * mono_class_can_access_class:
10537 * @source_class: The source class
10538 * @target_class: The accessed class
10540 * This function returns is @target_class is visible to @source_class
10542 * Returns: TRUE if source have proper visibility and acessibility to target
10544 gboolean
10545 mono_class_can_access_class (MonoClass *source_class, MonoClass *target_class)
10547 return can_access_type (source_class, target_class);
10551 * mono_type_is_valid_enum_basetype:
10552 * @type: The MonoType to check
10554 * Returns: TRUE if the type can be used as the basetype of an enum
10556 gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
10557 switch (type->type) {
10558 case MONO_TYPE_I1:
10559 case MONO_TYPE_U1:
10560 case MONO_TYPE_BOOLEAN:
10561 case MONO_TYPE_I2:
10562 case MONO_TYPE_U2:
10563 case MONO_TYPE_CHAR:
10564 case MONO_TYPE_I4:
10565 case MONO_TYPE_U4:
10566 case MONO_TYPE_I8:
10567 case MONO_TYPE_U8:
10568 case MONO_TYPE_I:
10569 case MONO_TYPE_U:
10570 return TRUE;
10571 default:
10572 return FALSE;
10577 * mono_class_is_valid_enum:
10578 * @klass: An enum class to be validated
10580 * This method verify the required properties an enum should have.
10582 * Returns: TRUE if the informed enum class is valid
10584 * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
10585 * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
10586 * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
10588 gboolean
10589 mono_class_is_valid_enum (MonoClass *klass)
10591 MonoClassField * field;
10592 gpointer iter = NULL;
10593 gboolean found_base_field = FALSE;
10595 g_assert (klass->enumtype);
10596 /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
10597 if (!klass->parent || strcmp (klass->parent->name, "Enum") || strcmp (klass->parent->name_space, "System") ) {
10598 return FALSE;
10601 if (!mono_class_is_auto_layout (klass))
10602 return FALSE;
10604 while ((field = mono_class_get_fields (klass, &iter))) {
10605 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
10606 if (found_base_field)
10607 return FALSE;
10608 found_base_field = TRUE;
10609 if (!mono_type_is_valid_enum_basetype (field->type))
10610 return FALSE;
10614 if (!found_base_field)
10615 return FALSE;
10617 if (mono_class_get_method_count (klass) > 0)
10618 return FALSE;
10620 return TRUE;
10623 gboolean
10624 mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
10626 return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst;
10630 * mono_class_setup_interface_id:
10632 * Initializes MonoClass::interface_id if required.
10634 * LOCKING: Acquires the loader lock.
10636 void
10637 mono_class_setup_interface_id (MonoClass *klass)
10639 mono_loader_lock ();
10640 if (MONO_CLASS_IS_INTERFACE (klass) && !klass->interface_id)
10641 klass->interface_id = mono_get_unique_iid (klass);
10642 mono_loader_unlock ();
10646 * mono_class_alloc_ext:
10648 * Allocate klass->ext if not already done.
10650 void
10651 mono_class_alloc_ext (MonoClass *klass)
10653 MonoClassExt *ext;
10655 if (mono_class_get_ext (klass))
10656 return;
10658 ext = (MonoClassExt *)mono_class_alloc0 (klass, sizeof (MonoClassExt));
10659 mono_image_lock (klass->image);
10660 mono_memory_barrier ();
10661 if (!mono_class_get_ext (klass))
10662 mono_class_set_ext (klass, ext);
10663 class_ext_size += sizeof (MonoClassExt);
10664 ++class_ext_count;
10665 mono_image_unlock (klass->image);
10669 * mono_class_setup_interfaces:
10671 * Initialize klass->interfaces/interfaces_count.
10672 * LOCKING: Acquires the loader lock.
10673 * This function can fail the type.
10675 void
10676 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
10678 int i, interface_count;
10679 MonoClass **interfaces;
10681 mono_error_init (error);
10683 if (klass->interfaces_inited)
10684 return;
10686 if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY) {
10687 MonoType *args [1];
10689 /* generic IList, ICollection, IEnumerable */
10690 interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
10691 interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
10693 args [0] = &klass->element_class->byval_arg;
10694 interfaces [0] = mono_class_bind_generic_parameters (
10695 mono_defaults.generic_ilist_class, 1, args, FALSE);
10696 if (interface_count > 1)
10697 interfaces [1] = mono_class_bind_generic_parameters (
10698 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
10699 } else if (mono_class_is_ginst (klass)) {
10700 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
10702 mono_class_setup_interfaces (gklass, error);
10703 if (!mono_error_ok (error)) {
10704 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
10705 return;
10708 interface_count = gklass->interface_count;
10709 interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
10710 for (i = 0; i < interface_count; i++) {
10711 interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
10712 if (!mono_error_ok (error)) {
10713 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
10714 return;
10717 } else {
10718 interface_count = 0;
10719 interfaces = NULL;
10722 mono_image_lock (klass->image);
10724 if (!klass->interfaces_inited) {
10725 klass->interface_count = interface_count;
10726 klass->interfaces = interfaces;
10728 mono_memory_barrier ();
10730 klass->interfaces_inited = TRUE;
10733 mono_image_unlock (klass->image);
10736 static void
10737 mono_field_resolve_type (MonoClassField *field, MonoError *error)
10739 MonoClass *klass = field->parent;
10740 MonoImage *image = klass->image;
10741 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
10742 MonoType *ftype;
10743 int field_idx = field - klass->fields;
10745 mono_error_init (error);
10747 if (gtd) {
10748 MonoClassField *gfield = &gtd->fields [field_idx];
10749 MonoType *gtype = mono_field_get_type_checked (gfield, error);
10750 if (!mono_error_ok (error)) {
10751 char *full_name = mono_type_get_full_name (gtd);
10752 mono_class_set_type_load_failure (klass, "Could not load generic type of field '%s:%s' (%d) due to: %s", full_name, gfield->name, field_idx, mono_error_get_message (error));
10753 g_free (full_name);
10756 ftype = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
10757 if (!mono_error_ok (error)) {
10758 char *full_name = mono_type_get_full_name (klass);
10759 mono_class_set_type_load_failure (klass, "Could not load instantiated type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
10760 g_free (full_name);
10762 } else {
10763 const char *sig;
10764 guint32 cols [MONO_FIELD_SIZE];
10765 MonoGenericContainer *container = NULL;
10766 int idx = mono_class_get_first_field_idx (klass) + field_idx;
10768 /*FIXME, in theory we do not lazy load SRE fields*/
10769 g_assert (!image_is_dynamic (image));
10771 if (mono_class_is_gtd (klass)) {
10772 container = mono_class_get_generic_container (klass);
10773 } else if (gtd) {
10774 container = mono_class_get_generic_container (gtd);
10775 g_assert (container);
10778 /* first_field_idx and idx points into the fieldptr table */
10779 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
10781 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) {
10782 char *full_name = mono_type_get_full_name (klass);
10783 mono_error_set_type_load_class (error, klass, "Could not verify field '%s:%s' signature", full_name, field->name);;
10784 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
10785 g_free (full_name);
10786 return;
10789 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
10791 mono_metadata_decode_value (sig, &sig);
10792 /* FIELD signature == 0x06 */
10793 g_assert (*sig == 0x06);
10795 ftype = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
10796 if (!ftype) {
10797 char *full_name = mono_type_get_full_name (klass);
10798 mono_class_set_type_load_failure (klass, "Could not load type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
10799 g_free (full_name);
10802 mono_memory_barrier ();
10803 field->type = ftype;
10806 static guint32
10807 mono_field_resolve_flags (MonoClassField *field)
10809 MonoClass *klass = field->parent;
10810 MonoImage *image = klass->image;
10811 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
10812 int field_idx = field - klass->fields;
10815 if (gtd) {
10816 MonoClassField *gfield = &gtd->fields [field_idx];
10817 return mono_field_get_flags (gfield);
10818 } else {
10819 int idx = mono_class_get_first_field_idx (klass) + field_idx;
10821 /*FIXME, in theory we do not lazy load SRE fields*/
10822 g_assert (!image_is_dynamic (image));
10824 return mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_FLAGS);
10829 * mono_class_get_fields_lazy:
10830 * @klass: the MonoClass to act on
10832 * This routine is an iterator routine for retrieving the fields in a class.
10833 * Only minimal information about fields are loaded. Accessors must be used
10834 * for all MonoClassField returned.
10836 * You must pass a gpointer that points to zero and is treated as an opaque handle to
10837 * iterate over all of the elements. When no more values are
10838 * available, the return value is NULL.
10840 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
10842 MonoClassField*
10843 mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
10845 MonoClassField* field;
10846 if (!iter)
10847 return NULL;
10848 if (!*iter) {
10849 mono_class_setup_basic_field_info (klass);
10850 if (!klass->fields)
10851 return NULL;
10852 /* start from the first */
10853 if (mono_class_get_field_count (klass)) {
10854 *iter = &klass->fields [0];
10855 return (MonoClassField *)*iter;
10856 } else {
10857 /* no fields */
10858 return NULL;
10861 field = (MonoClassField *)*iter;
10862 field++;
10863 if (field < &klass->fields [mono_class_get_field_count (klass)]) {
10864 *iter = field;
10865 return (MonoClassField *)*iter;
10867 return NULL;
10870 char*
10871 mono_class_full_name (MonoClass *klass)
10873 return mono_type_full_name (&klass->byval_arg);
10876 /* Declare all shared lazy type lookup functions */
10877 GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle)