[metadata] Fields whose types are gparams with a reference type constraint aren't...
[mono-project.git] / mono / metadata / class.c
blobce3e9fd0ae66e0cf1cec90df8bf078f0e226a48f
1 /**
2 * \file
3 * Class management for the Mono runtime
5 * Author:
6 * Miguel de Icaza (miguel@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 #include <config.h>
14 #ifdef HAVE_ALLOCA_H
15 #include <alloca.h>
16 #endif
17 #include <glib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <mono/metadata/image.h>
22 #include <mono/metadata/image-internals.h>
23 #include <mono/metadata/assembly.h>
24 #include <mono/metadata/assembly-internals.h>
25 #include <mono/metadata/exception-internals.h>
26 #include <mono/metadata/metadata.h>
27 #include <mono/metadata/metadata-internals.h>
28 #include <mono/metadata/profiler-private.h>
29 #include <mono/metadata/tabledefs.h>
30 #include <mono/metadata/tokentype.h>
31 #include <mono/metadata/class-init.h>
32 #include <mono/metadata/class-internals.h>
33 #include <mono/metadata/object.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/mono-endian.h>
36 #include <mono/metadata/debug-helpers.h>
37 #include <mono/metadata/reflection.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/security-manager.h>
40 #include <mono/metadata/security-core-clr.h>
41 #include <mono/metadata/attrdefs.h>
42 #include <mono/metadata/gc-internals.h>
43 #include <mono/metadata/verify-internals.h>
44 #include <mono/metadata/mono-debug.h>
45 #include <mono/utils/mono-counters.h>
46 #include <mono/utils/mono-string.h>
47 #include <mono/utils/mono-error-internals.h>
48 #include <mono/utils/mono-logger-internals.h>
49 #include <mono/utils/mono-memory-model.h>
50 #include <mono/utils/atomic.h>
51 #include <mono/utils/unlocked.h>
52 #include <mono/utils/bsearch.h>
53 #include <mono/utils/checked-build.h>
55 MonoStats mono_stats;
57 /* Statistics */
58 extern gint32 mono_inflated_methods_size;
60 /* Function supplied by the runtime to find classes by name using information from the AOT file */
61 static MonoGetClassFromName get_class_from_name = NULL;
63 static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
65 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
66 static guint32 mono_field_resolve_flags (MonoClassField *field);
68 GENERATE_GET_CLASS_WITH_CACHE (valuetype, "System", "ValueType")
69 GENERATE_TRY_GET_CLASS_WITH_CACHE (handleref, "System.Runtime.InteropServices", "HandleRef")
71 // define to print types whenever custom modifiers are appended during inflation
72 #undef DEBUG_INFLATE_CMODS
74 static
75 MonoImage *
76 mono_method_get_image (MonoMethod *method)
78 return m_class_get_image (method->klass);
81 /**
82 * mono_class_from_typeref:
83 * \param image a MonoImage
84 * \param type_token a TypeRef token
86 * Creates the \c MonoClass* structure representing the type defined by
87 * the typeref token valid inside \p image.
88 * \returns The \c MonoClass* representing the typeref token, or NULL if it could
89 * not be loaded.
91 MonoClass *
92 mono_class_from_typeref (MonoImage *image, guint32 type_token)
94 ERROR_DECL (error);
95 MonoClass *klass = mono_class_from_typeref_checked (image, type_token, error);
96 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
97 return klass;
101 * mono_class_from_typeref_checked:
102 * \param image a MonoImage
103 * \param type_token a TypeRef token
104 * \param error error return code, if any.
106 * Creates the \c MonoClass* structure representing the type defined by
107 * the typeref token valid inside \p image.
109 * \returns The \c MonoClass* representing the typeref token, NULL if it could
110 * not be loaded with the \p error value filled with the information about the
111 * error.
113 MonoClass *
114 mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
116 guint32 cols [MONO_TYPEREF_SIZE];
117 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
118 guint32 idx;
119 const char *name, *nspace;
120 MonoClass *res = NULL;
121 MonoImage *module;
123 error_init (error);
125 if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
126 return NULL;
128 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
130 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
131 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
133 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
134 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
135 case MONO_RESOLUTION_SCOPE_MODULE:
137 LAMESPEC The spec says that a null module resolution scope should go through the exported type table.
138 This is not the observed behavior of existing implementations.
139 The defacto behavior is that it's just a typedef in disguise.
141 /* a typedef in disguise */
142 res = mono_class_from_name_checked (image, nspace, name, error);
143 goto done;
145 case MONO_RESOLUTION_SCOPE_MODULEREF:
146 module = mono_image_load_module_checked (image, idx, error);
147 if (module)
148 res = mono_class_from_name_checked (module, nspace, name, error);
149 goto done;
151 case MONO_RESOLUTION_SCOPE_TYPEREF: {
152 MonoClass *enclosing;
153 GList *tmp;
155 if (idx == mono_metadata_token_index (type_token)) {
156 mono_error_set_bad_image (error, image, "Image with self-referencing typeref token %08x.", type_token);
157 return NULL;
160 enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
161 return_val_if_nok (error, NULL);
163 GList *nested_classes = mono_class_get_nested_classes_property (enclosing);
164 if (m_class_is_nested_classes_inited (enclosing) && nested_classes) {
165 /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
166 for (tmp = nested_classes; tmp; tmp = tmp->next) {
167 res = (MonoClass *)tmp->data;
168 if (strcmp (m_class_get_name (res), name) == 0)
169 return res;
171 } else {
172 MonoImage *enclosing_image = m_class_get_image (enclosing);
173 guint32 enclosing_type_token = m_class_get_type_token (enclosing);
174 /* Don't call mono_class_init_internal as we might've been called by it recursively */
175 int i = mono_metadata_nesting_typedef (enclosing_image, enclosing_type_token, 1);
176 while (i) {
177 guint32 class_nested = mono_metadata_decode_row_col (&enclosing_image->tables [MONO_TABLE_NESTEDCLASS], i - 1, MONO_NESTED_CLASS_NESTED);
178 guint32 string_offset = mono_metadata_decode_row_col (&enclosing_image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
179 const char *nname = mono_metadata_string_heap (enclosing_image, string_offset);
181 if (strcmp (nname, name) == 0)
182 return mono_class_create_from_typedef (enclosing_image, MONO_TOKEN_TYPE_DEF | class_nested, error);
184 i = mono_metadata_nesting_typedef (enclosing_image, enclosing_type_token, i + 1);
187 g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
188 goto done;
190 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
191 break;
194 if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
195 mono_error_set_bad_image (error, image, "Image with invalid assemblyref token %08x.", idx);
196 return NULL;
199 if (!image->references || !image->references [idx - 1])
200 mono_assembly_load_reference (image, idx - 1);
201 g_assert (image->references [idx - 1]);
203 /* If the assembly did not load, register this as a type load exception */
204 if (image->references [idx - 1] == REFERENCE_MISSING){
205 MonoAssemblyName aname;
206 char *human_name;
208 mono_assembly_get_assemblyref (image, idx - 1, &aname);
209 human_name = mono_stringify_assembly_name (&aname);
210 gboolean refonly = FALSE;
211 if (image->assembly)
212 refonly = mono_asmctx_get_kind (&image->assembly->context) == MONO_ASMCTX_REFONLY;
213 mono_error_set_simple_file_not_found (error, human_name, refonly);
214 g_free (human_name);
215 return NULL;
218 res = mono_class_from_name_checked (image->references [idx - 1]->image, nspace, name, error);
220 done:
221 /* Generic case, should be avoided for when a better error is possible. */
222 if (!res && mono_error_ok (error)) {
223 char *name = mono_class_name_from_token (image, type_token);
224 char *assembly = mono_assembly_name_from_token (image, type_token);
225 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x from typeref (expected class '%s' in assembly '%s')", type_token, name, assembly);
227 return res;
231 static void *
232 mono_image_memdup (MonoImage *image, void *data, guint size)
234 void *res = mono_image_alloc (image, size);
235 memcpy (res, data, size);
236 return res;
239 /* Copy everything mono_metadata_free_array free. */
240 MonoArrayType *
241 mono_dup_array_type (MonoImage *image, MonoArrayType *a)
243 if (image) {
244 a = (MonoArrayType *)mono_image_memdup (image, a, sizeof (MonoArrayType));
245 if (a->sizes)
246 a->sizes = (int *)mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
247 if (a->lobounds)
248 a->lobounds = (int *)mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
249 } else {
250 a = (MonoArrayType *)g_memdup (a, sizeof (MonoArrayType));
251 if (a->sizes)
252 a->sizes = (int *)g_memdup (a->sizes, a->numsizes * sizeof (int));
253 if (a->lobounds)
254 a->lobounds = (int *)g_memdup (a->lobounds, a->numlobounds * sizeof (int));
256 return a;
259 /* Copy everything mono_metadata_free_method_signature free. */
260 MonoMethodSignature*
261 mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
263 int i;
265 sig = mono_metadata_signature_dup_full (image, sig);
267 sig->ret = mono_metadata_type_dup (image, sig->ret);
268 for (i = 0; i < sig->param_count; ++i)
269 sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
271 return sig;
274 static void
275 _mono_type_get_assembly_name (MonoClass *klass, GString *str)
277 MonoAssembly *ta = m_class_get_image (klass)->assembly;
278 char *name;
280 name = mono_stringify_assembly_name (&ta->aname);
281 g_string_append_printf (str, ", %s", name);
282 g_free (name);
285 static inline void
286 mono_type_name_check_byref (MonoType *type, GString *str)
288 if (type->byref)
289 g_string_append_c (str, '&');
293 * mono_identifier_escape_type_name_chars:
294 * \param str a destination string
295 * \param identifier an IDENTIFIER in internal form
297 * \returns \p str
299 * The displayed form of the identifier is appended to str.
301 * The displayed form of an identifier has the characters ,+&*[]\
302 * that have special meaning in type names escaped with a preceeding
303 * backslash (\) character.
305 static GString*
306 mono_identifier_escape_type_name_chars (GString* str, const char* identifier)
308 if (!identifier)
309 return str;
311 size_t n = str->len;
312 // reserve space for common case: there will be no escaped characters.
313 g_string_set_size(str, n + strlen(identifier));
314 g_string_set_size(str, n);
316 for (const char* s = identifier; *s != 0 ; s++) {
317 switch (*s) {
318 case ',':
319 case '+':
320 case '&':
321 case '*':
322 case '[':
323 case ']':
324 case '\\':
325 g_string_append_c (str, '\\');
326 g_string_append_c (str, *s);
327 break;
328 default:
329 g_string_append_c (str, *s);
330 break;
333 return str;
336 static void
337 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
338 MonoTypeNameFormat format)
340 MonoClass *klass;
342 switch (type->type) {
343 case MONO_TYPE_ARRAY: {
344 int i, rank = type->data.array->rank;
345 MonoTypeNameFormat nested_format;
347 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
348 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
350 mono_type_get_name_recurse (
351 m_class_get_byval_arg (type->data.array->eklass), str, FALSE, nested_format);
352 g_string_append_c (str, '[');
353 if (rank == 1)
354 g_string_append_c (str, '*');
355 for (i = 1; i < rank; i++)
356 g_string_append_c (str, ',');
357 g_string_append_c (str, ']');
359 mono_type_name_check_byref (type, str);
361 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
362 _mono_type_get_assembly_name (type->data.array->eklass, str);
363 break;
365 case MONO_TYPE_SZARRAY: {
366 MonoTypeNameFormat nested_format;
368 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
369 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
371 mono_type_get_name_recurse (
372 m_class_get_byval_arg (type->data.klass), str, FALSE, nested_format);
373 g_string_append (str, "[]");
375 mono_type_name_check_byref (type, str);
377 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
378 _mono_type_get_assembly_name (type->data.klass, str);
379 break;
381 case MONO_TYPE_PTR: {
382 MonoTypeNameFormat nested_format;
384 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
385 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
387 mono_type_get_name_recurse (
388 type->data.type, str, FALSE, nested_format);
389 g_string_append_c (str, '*');
391 mono_type_name_check_byref (type, str);
393 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
394 _mono_type_get_assembly_name (mono_class_from_mono_type_internal (type->data.type), str);
395 break;
397 case MONO_TYPE_VAR:
398 case MONO_TYPE_MVAR:
399 if (!mono_generic_param_name (type->data.generic_param))
400 g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
401 else
402 g_string_append (str, mono_generic_param_name (type->data.generic_param));
404 mono_type_name_check_byref (type, str);
406 break;
407 default:
408 klass = mono_class_from_mono_type_internal (type);
409 if (m_class_get_nested_in (klass)) {
410 mono_type_get_name_recurse (
411 m_class_get_byval_arg (m_class_get_nested_in (klass)), str, TRUE, format);
412 if (format == MONO_TYPE_NAME_FORMAT_IL)
413 g_string_append_c (str, '.');
414 else
415 g_string_append_c (str, '+');
416 } else if (*m_class_get_name_space (klass)) {
417 const char *klass_name_space = m_class_get_name_space (klass);
418 if (format == MONO_TYPE_NAME_FORMAT_IL)
419 g_string_append (str, klass_name_space);
420 else
421 mono_identifier_escape_type_name_chars (str, klass_name_space);
422 g_string_append_c (str, '.');
424 const char *klass_name = m_class_get_name (klass);
425 if (format == MONO_TYPE_NAME_FORMAT_IL) {
426 const char *s = strchr (klass_name, '`');
427 gssize len = s ? (s - klass_name) : (gssize)strlen (klass_name);
428 g_string_append_len (str, klass_name, len);
429 } else {
430 mono_identifier_escape_type_name_chars (str, klass_name);
432 if (is_recursed)
433 break;
434 if (mono_class_is_ginst (klass)) {
435 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
436 MonoGenericInst *inst = gclass->context.class_inst;
437 MonoTypeNameFormat nested_format;
438 int i;
440 nested_format = format == MONO_TYPE_NAME_FORMAT_FULL_NAME ?
441 MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format;
443 if (format == MONO_TYPE_NAME_FORMAT_IL)
444 g_string_append_c (str, '<');
445 else
446 g_string_append_c (str, '[');
447 for (i = 0; i < inst->type_argc; i++) {
448 MonoType *t = inst->type_argv [i];
450 if (i)
451 g_string_append_c (str, ',');
452 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
453 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
454 g_string_append_c (str, '[');
455 mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
456 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
457 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
458 g_string_append_c (str, ']');
460 if (format == MONO_TYPE_NAME_FORMAT_IL)
461 g_string_append_c (str, '>');
462 else
463 g_string_append_c (str, ']');
464 } else if (mono_class_is_gtd (klass) &&
465 (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
466 (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
467 int i;
469 if (format == MONO_TYPE_NAME_FORMAT_IL)
470 g_string_append_c (str, '<');
471 else
472 g_string_append_c (str, '[');
473 for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) {
474 if (i)
475 g_string_append_c (str, ',');
476 g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name);
478 if (format == MONO_TYPE_NAME_FORMAT_IL)
479 g_string_append_c (str, '>');
480 else
481 g_string_append_c (str, ']');
484 mono_type_name_check_byref (type, str);
486 if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
487 (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
488 _mono_type_get_assembly_name (klass, str);
489 break;
494 * mono_type_get_name_full:
495 * \param type a type
496 * \param format the format for the return string.
499 * \returns The string representation in a number of formats:
501 * if \p format is \c MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
502 * returned in the format required by \c System.Reflection, this is the
503 * inverse of mono_reflection_parse_type().
505 * if \p format is \c MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
506 * be used by the IL assembler.
508 * if \p format is \c MONO_TYPE_NAME_FORMAT_FULL_NAME
510 * if \p format is \c MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
512 char*
513 mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
515 GString* result;
517 result = g_string_new ("");
519 mono_type_get_name_recurse (type, result, FALSE, format);
521 return g_string_free (result, FALSE);
525 * mono_type_get_full_name:
526 * \param class a class
528 * \returns The string representation for type as required by System.Reflection.
529 * The inverse of mono_reflection_parse_type().
531 char *
532 mono_type_get_full_name (MonoClass *klass)
534 return mono_type_get_name_full (m_class_get_byval_arg (klass), MONO_TYPE_NAME_FORMAT_REFLECTION);
538 * mono_type_get_name:
539 * \param type a type
540 * \returns The string representation for type as it would be represented in IL code.
542 char*
543 mono_type_get_name (MonoType *type)
545 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
549 * mono_type_get_underlying_type:
550 * \param type a type
551 * \returns The \c MonoType for the underlying integer type if \p type
552 * is an enum and byref is false, otherwise the type itself.
554 MonoType*
555 mono_type_get_underlying_type (MonoType *type)
557 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass) && !type->byref)
558 return mono_class_enum_basetype_internal (type->data.klass);
559 if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype (type->data.generic_class->container_class) && !type->byref)
560 return mono_class_enum_basetype_internal (type->data.generic_class->container_class);
561 return type;
565 * mono_class_is_open_constructed_type:
566 * \param type a type
568 * \returns TRUE if type represents a generics open constructed type.
569 * IOW, not all type parameters required for the instantiation have
570 * been provided or it's a generic type definition.
572 * An open constructed type means it's a non realizable type. Not to
573 * be mixed up with an abstract type - we can't cast or dispatch to
574 * an open type, for example.
576 gboolean
577 mono_class_is_open_constructed_type (MonoType *t)
579 switch (t->type) {
580 case MONO_TYPE_VAR:
581 case MONO_TYPE_MVAR:
582 return TRUE;
583 case MONO_TYPE_SZARRAY:
584 return mono_class_is_open_constructed_type (m_class_get_byval_arg (t->data.klass));
585 case MONO_TYPE_ARRAY:
586 return mono_class_is_open_constructed_type (m_class_get_byval_arg (t->data.array->eklass));
587 case MONO_TYPE_PTR:
588 return mono_class_is_open_constructed_type (t->data.type);
589 case MONO_TYPE_GENERICINST:
590 return t->data.generic_class->context.class_inst->is_open;
591 case MONO_TYPE_CLASS:
592 case MONO_TYPE_VALUETYPE:
593 return mono_class_is_gtd (t->data.klass);
594 default:
595 return FALSE;
600 This is a simple function to catch the most common bad instances of generic types.
601 Specially those that might lead to further failures in the runtime.
603 gboolean
604 mono_type_is_valid_generic_argument (MonoType *type)
606 switch (type->type) {
607 case MONO_TYPE_VOID:
608 case MONO_TYPE_TYPEDBYREF:
609 return FALSE;
610 case MONO_TYPE_VALUETYPE:
611 return !m_class_is_byreflike (type->data.klass);
612 default:
613 return TRUE;
617 static gboolean
618 can_inflate_gparam_with (MonoGenericParam *gparam, MonoType *type)
620 if (!mono_type_is_valid_generic_argument (type))
621 return FALSE;
622 #if FALSE
623 /* Avoid inflating gparams with valuetype constraints with ref types during gsharing */
624 MonoGenericParamInfo *info = mono_generic_param_info (gparam);
625 if (info && (info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)) {
626 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
627 MonoGenericParam *inst_gparam = type->data.generic_param;
628 if (inst_gparam->gshared_constraint && inst_gparam->gshared_constraint->type == MONO_TYPE_OBJECT)
629 return FALSE;
632 #endif
633 return TRUE;
636 static MonoType*
637 inflate_generic_custom_modifiers (MonoImage *image, const MonoType *type, MonoGenericContext *context, MonoError *error);
639 static MonoType*
640 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
642 gboolean changed = FALSE;
643 error_init (error);
645 /* C++/CLI (and some Roslyn tests) constructs method signatures like:
646 * void .CL1`1.Test(!0 modopt(System.Nullable`1<!0>))
647 * where !0 has a custom modifier which itself mentions the type variable.
648 * So we need to potentially inflate the modifiers.
650 if (type->has_cmods) {
651 MonoType *new_type = inflate_generic_custom_modifiers (image, type, context, error);
652 return_val_if_nok (error, NULL);
653 if (new_type != NULL) {
654 type = new_type;
655 changed = TRUE;
659 switch (type->type) {
660 case MONO_TYPE_MVAR: {
661 MonoType *nt;
662 int num = mono_type_get_generic_param_num (type);
663 MonoGenericInst *inst = context->method_inst;
664 if (!inst) {
665 if (!changed)
666 return NULL;
667 else
668 return type;
670 MonoGenericParam *gparam = type->data.generic_param;
671 if (num >= inst->type_argc) {
672 const char *pname = mono_generic_param_name (gparam);
673 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
674 num, pname ? pname : "", inst->type_argc);
675 return NULL;
678 if (!can_inflate_gparam_with (gparam, inst->type_argv [num])) {
679 const char *pname = mono_generic_param_name (gparam);
680 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
681 num, pname ? pname : "", inst->type_argv [num]->type);
682 return NULL;
685 * Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
686 * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
687 * ->byref and ->attrs from @type are propagated to the returned type.
689 nt = mono_metadata_type_dup_with_cmods (image, inst->type_argv [num], type);
690 nt->byref = type->byref;
691 nt->attrs = type->attrs;
692 return nt;
694 case MONO_TYPE_VAR: {
695 MonoType *nt;
696 int num = mono_type_get_generic_param_num (type);
697 MonoGenericInst *inst = context->class_inst;
698 if (!inst) {
699 if (!changed)
700 return NULL;
701 else
702 return type;
704 MonoGenericParam *gparam = type->data.generic_param;
705 if (num >= inst->type_argc) {
706 const char *pname = mono_generic_param_name (gparam);
707 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
708 num, pname ? pname : "", inst->type_argc);
709 return NULL;
711 if (!can_inflate_gparam_with (gparam, inst->type_argv [num])) {
712 const char *pname = mono_generic_param_name (gparam);
713 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
714 num, pname ? pname : "", inst->type_argv [num]->type);
715 return NULL;
718 #ifdef DEBUG_INFLATE_CMODS
719 gboolean append_cmods;
720 append_cmods = FALSE;
721 if (type->has_cmods && inst->type_argv[num]->has_cmods) {
722 char *tname = mono_type_full_name (type);
723 char *vname = mono_type_full_name (inst->type_argv[num]);
724 printf ("\n\n\tsubstitution for '%s' with '%s' yields...\n", tname, vname);
725 g_free (tname);
726 g_free (vname);
727 append_cmods = TRUE;
729 #endif
731 nt = mono_metadata_type_dup_with_cmods (image, inst->type_argv [num], type);
732 nt->byref = type->byref || inst->type_argv[num]->byref;
733 nt->attrs = type->attrs;
734 #ifdef DEBUG_INFLATE_CMODS
735 if (append_cmods) {
736 char *ntname = mono_type_full_name (nt);
737 printf ("\tyields '%s'\n\n\n", ntname);
738 g_free (ntname);
740 #endif
741 return nt;
743 case MONO_TYPE_SZARRAY: {
744 MonoClass *eclass = type->data.klass;
745 MonoType *nt, *inflated = inflate_generic_type (NULL, m_class_get_byval_arg (eclass), context, error);
746 if ((!inflated && !changed) || !mono_error_ok (error))
747 return NULL;
748 if (!inflated)
749 return type;
750 nt = mono_metadata_type_dup (image, type);
751 nt->data.klass = mono_class_from_mono_type_internal (inflated);
752 mono_metadata_free_type (inflated);
753 return nt;
755 case MONO_TYPE_ARRAY: {
756 MonoClass *eclass = type->data.array->eklass;
757 MonoType *nt, *inflated = inflate_generic_type (NULL, m_class_get_byval_arg (eclass), context, error);
758 if ((!inflated && !changed) || !mono_error_ok (error))
759 return NULL;
760 if (!inflated)
761 return type;
762 nt = mono_metadata_type_dup (image, type);
763 nt->data.array->eklass = mono_class_from_mono_type_internal (inflated);
764 mono_metadata_free_type (inflated);
765 return nt;
767 case MONO_TYPE_GENERICINST: {
768 MonoGenericClass *gclass = type->data.generic_class;
769 MonoGenericInst *inst;
770 MonoType *nt;
771 if (!gclass->context.class_inst->is_open) {
772 if (!changed)
773 return NULL;
774 else
775 return type;
778 inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
779 return_val_if_nok (error, NULL);
781 if (inst != gclass->context.class_inst)
782 gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
784 if (gclass == type->data.generic_class) {
785 if (!changed)
786 return NULL;
787 else
788 return type;
791 nt = mono_metadata_type_dup (image, type);
792 nt->data.generic_class = gclass;
793 return nt;
795 case MONO_TYPE_CLASS:
796 case MONO_TYPE_VALUETYPE: {
797 MonoClass *klass = type->data.klass;
798 MonoGenericContainer *container = mono_class_try_get_generic_container (klass);
799 MonoGenericInst *inst;
800 MonoGenericClass *gclass = NULL;
801 MonoType *nt;
803 if (!container) {
804 if (!changed)
805 return NULL;
806 else
807 return type;
810 /* We can't use context->class_inst directly, since it can have more elements */
811 inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
812 return_val_if_nok (error, NULL);
814 if (inst == container->context.class_inst) {
815 if (!changed)
816 return NULL;
817 else
818 return type;
821 gclass = mono_metadata_lookup_generic_class (klass, inst, image_is_dynamic (m_class_get_image (klass)));
823 nt = mono_metadata_type_dup (image, type);
824 nt->type = MONO_TYPE_GENERICINST;
825 nt->data.generic_class = gclass;
826 return nt;
828 case MONO_TYPE_PTR: {
829 MonoType *nt, *inflated = inflate_generic_type (image, type->data.type, context, error);
830 if ((!inflated && !changed) || !mono_error_ok (error))
831 return NULL;
832 if (!inflated && changed)
833 return type;
834 nt = mono_metadata_type_dup (image, type);
835 nt->data.type = inflated;
836 return nt;
838 default:
839 if (!changed)
840 return NULL;
841 else
842 return type;
844 return NULL;
847 static MonoType*
848 inflate_generic_custom_modifiers (MonoImage *image, const MonoType *type, MonoGenericContext *context, MonoError *error)
850 MonoType *result = NULL;
851 g_assert (type->has_cmods);
852 int count = mono_type_custom_modifier_count (type);
853 gboolean changed = FALSE;
855 /* Try not to blow up the stack. See comment on MONO_MAX_EXPECTED_CMODS. */
856 g_assert (count < MONO_MAX_EXPECTED_CMODS);
857 size_t aggregate_size = mono_sizeof_aggregate_modifiers (count);
858 MonoAggregateModContainer *candidate_mods = g_alloca (aggregate_size);
859 memset (candidate_mods, 0, aggregate_size);
860 candidate_mods->count = count;
862 for (int i = 0; i < count; ++i) {
863 gboolean required;
864 MonoType *cmod_old = mono_type_get_custom_modifier (type, i, &required, error);
865 goto_if_nok (error, leave);
866 MonoType *cmod_new = inflate_generic_type (NULL, cmod_old, context, error);
867 goto_if_nok (error, leave);
868 if (cmod_new)
869 changed = TRUE;
870 candidate_mods->modifiers [i].required = required;
871 candidate_mods->modifiers [i].type = cmod_new;
874 if (changed) {
875 /* if we're going to make a new type, fill in any modifiers that weren't affected by inflation with copies of the original values. */
876 for (int i = 0; i < count; ++i) {
877 if (candidate_mods->modifiers [i].type == NULL) {
878 candidate_mods->modifiers [i].type = mono_metadata_type_dup (NULL, mono_type_get_custom_modifier (type, i, NULL, error));
880 /* it didn't error in the first loop, so should be ok now, too */
881 mono_error_assert_ok (error);
885 #ifdef DEBUG_INFLATE_CMODS
886 if (changed) {
887 char *full_name = mono_type_full_name ((MonoType*)type);
888 printf ("\n\n\tcustom modifier on '%s' affected by subsititution\n\n\n", full_name);
889 g_free (full_name);
891 #endif
892 if (changed) {
893 MonoType *new_type = g_alloca (mono_sizeof_type_with_mods (count, TRUE));
894 /* first init just the non-modifier portion of new_type before populating the
895 * new modifiers */
896 memcpy (new_type, type, MONO_SIZEOF_TYPE);
897 mono_type_with_mods_init (new_type, count, TRUE);
898 mono_type_set_amods (new_type, mono_metadata_get_canonical_aggregate_modifiers (candidate_mods));
899 result = mono_metadata_type_dup (image, new_type);
902 leave:
903 for (int i = 0; i < count; ++i) {
904 if (candidate_mods->modifiers [i].type)
905 mono_metadata_free_type (candidate_mods->modifiers [i].type);
908 return result;
911 MonoGenericContext *
912 mono_generic_class_get_context (MonoGenericClass *gclass)
914 return &gclass->context;
917 MonoGenericContext *
918 mono_class_get_context (MonoClass *klass)
920 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
921 return gklass ? mono_generic_class_get_context (gklass) : NULL;
925 * mono_class_inflate_generic_type_with_mempool:
926 * @mempool: a mempool
927 * @type: a type
928 * @context: a generics context
929 * @error: error context
931 * The same as mono_class_inflate_generic_type, but allocates the MonoType
932 * from mempool if it is non-NULL. If it is NULL, the MonoType is
933 * allocated on the heap and is owned by the caller.
934 * The returned type can potentially be the same as TYPE, so it should not be
935 * modified by the caller, and it should be freed using mono_metadata_free_type ().
937 MonoType*
938 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
940 MonoType *inflated = NULL;
941 error_init (error);
943 if (context)
944 inflated = inflate_generic_type (image, type, context, error);
945 return_val_if_nok (error, NULL);
947 if (!inflated) {
948 MonoType *shared = mono_metadata_get_shared_type (type);
950 if (shared && !type->has_cmods) {
951 return shared;
952 } else {
953 return mono_metadata_type_dup (image, type);
957 UnlockedIncrement (&mono_stats.inflated_type_count);
958 return inflated;
962 * mono_class_inflate_generic_type:
963 * \param type a type
964 * \param context a generics context
965 * \deprecated Please use \c mono_class_inflate_generic_type_checked instead
967 * If \p type is a generic type and \p context is not NULL, instantiate it using the
968 * generics context \p context.
970 * \returns The instantiated type or a copy of \p type. The returned \c MonoType is allocated
971 * on the heap and is owned by the caller. Returns NULL on error.
973 MonoType*
974 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
976 ERROR_DECL (error);
977 MonoType *result;
978 result = mono_class_inflate_generic_type_checked (type, context, error);
979 mono_error_cleanup (error);
980 return result;
984 * mono_class_inflate_generic_type:
985 * @type: a type
986 * @context: a generics context
987 * @error: error context to use
989 * If @type is a generic type and @context is not NULL, instantiate it using the
990 * generics context @context.
992 * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
993 * on the heap and is owned by the caller.
995 MonoType*
996 mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
998 return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
1002 * mono_class_inflate_generic_type_no_copy:
1004 * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
1005 * was done.
1007 static MonoType*
1008 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
1010 MonoType *inflated = NULL;
1012 error_init (error);
1013 if (context) {
1014 inflated = inflate_generic_type (image, type, context, error);
1015 return_val_if_nok (error, NULL);
1018 if (!inflated)
1019 return type;
1021 UnlockedIncrement (&mono_stats.inflated_type_count);
1022 return inflated;
1026 * mono_class_inflate_generic_class:
1028 * Inflate the class @gklass with @context. Set @error on failure.
1030 MonoClass*
1031 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
1033 MonoClass *res;
1034 MonoType *inflated;
1036 inflated = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (gklass), context, error);
1037 return_val_if_nok (error, NULL);
1039 res = mono_class_from_mono_type_internal (inflated);
1040 mono_metadata_free_type (inflated);
1042 return res;
1045 static MonoGenericContext
1046 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
1048 MonoGenericInst *class_inst = NULL;
1049 MonoGenericInst *method_inst = NULL;
1050 MonoGenericContext res = { NULL, NULL };
1052 error_init (error);
1054 if (context->class_inst) {
1055 class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
1056 if (!mono_error_ok (error))
1057 goto fail;
1060 if (context->method_inst) {
1061 method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with, error);
1062 if (!mono_error_ok (error))
1063 goto fail;
1066 res.class_inst = class_inst;
1067 res.method_inst = method_inst;
1068 fail:
1069 return res;
1073 * mono_class_inflate_generic_method:
1074 * \param method a generic method
1075 * \param context a generics context
1077 * Instantiate the generic method \p method using the generics context \p context.
1079 * \returns The new instantiated method
1081 MonoMethod *
1082 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
1084 ERROR_DECL (error);
1085 error_init (error);
1086 MonoMethod *res = mono_class_inflate_generic_method_full_checked (method, NULL, context, error);
1087 mono_error_assert_msg_ok (error, "Could not inflate generic method");
1088 return res;
1091 MonoMethod *
1092 mono_class_inflate_generic_method_checked (MonoMethod *method, MonoGenericContext *context, MonoError *error)
1094 return mono_class_inflate_generic_method_full_checked (method, NULL, context, error);
1098 * mono_class_inflate_generic_method_full_checked:
1099 * Instantiate method \p method with the generic context \p context.
1100 * On failure returns NULL and sets \p error.
1102 * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
1103 * Use mono_method_signature_internal () and mono_method_get_header () to get the correct values.
1105 MonoMethod*
1106 mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error)
1108 MonoMethod *result;
1109 MonoMethodInflated *iresult, *cached;
1110 MonoMethodSignature *sig;
1111 MonoGenericContext tmp_context;
1113 error_init (error);
1115 /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
1116 while (method->is_inflated) {
1117 MonoGenericContext *method_context = mono_method_get_context (method);
1118 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1120 tmp_context = inflate_generic_context (method_context, context, error);
1121 return_val_if_nok (error, NULL);
1123 context = &tmp_context;
1125 if (mono_metadata_generic_context_equal (method_context, context))
1126 return method;
1128 method = imethod->declaring;
1132 * A method only needs to be inflated if the context has argument for which it is
1133 * parametric. Eg:
1135 * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
1136 * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
1139 if (!((method->is_generic && context->method_inst) ||
1140 (mono_class_is_gtd (method->klass) && context->class_inst)))
1141 return method;
1143 iresult = g_new0 (MonoMethodInflated, 1);
1144 iresult->context = *context;
1145 iresult->declaring = method;
1147 if (!context->method_inst && method->is_generic)
1148 iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
1150 if (!context->class_inst) {
1151 g_assert (!mono_class_is_ginst (iresult->declaring->klass));
1152 if (mono_class_is_gtd (iresult->declaring->klass))
1153 iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst;
1155 /* This can happen with some callers like mono_object_get_virtual_method_internal () */
1156 if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass))
1157 iresult->context.class_inst = NULL;
1159 MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
1161 // check cache
1162 mono_image_set_lock (set);
1163 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1164 mono_image_set_unlock (set);
1166 if (cached) {
1167 g_free (iresult);
1168 return (MonoMethod*)cached;
1171 UnlockedIncrement (&mono_stats.inflated_method_count);
1173 UnlockedAdd (&mono_inflated_methods_size, sizeof (MonoMethodInflated));
1175 sig = mono_method_signature_internal (method);
1176 if (!sig) {
1177 char *name = mono_type_get_full_name (method->klass);
1178 mono_error_set_bad_image (error, mono_method_get_image (method), "Could not resolve signature of method %s:%s", name, method->name);
1179 g_free (name);
1180 goto fail;
1183 if (sig->pinvoke) {
1184 memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
1185 } else {
1186 memcpy (&iresult->method.method, method, sizeof (MonoMethod));
1189 result = (MonoMethod *) iresult;
1190 result->is_inflated = TRUE;
1191 result->is_generic = FALSE;
1192 result->sre_method = FALSE;
1193 result->signature = NULL;
1195 if (method->wrapper_type) {
1196 MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
1197 MonoMethodWrapper *resw = (MonoMethodWrapper*)result;
1198 int len = GPOINTER_TO_INT (((void**)mw->method_data) [0]);
1200 resw->method_data = (void **)g_malloc (sizeof (gpointer) * (len + 1));
1201 memcpy (resw->method_data, mw->method_data, sizeof (gpointer) * (len + 1));
1204 if (iresult->context.method_inst) {
1205 MonoGenericInst *method_inst = iresult->context.method_inst;
1206 /* Set the generic_container of the result to the generic_container of method */
1207 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
1209 if (generic_container && method_inst == generic_container->context.method_inst) {
1210 result->is_generic = 1;
1211 mono_method_set_generic_container (result, generic_container);
1214 /* Check that the method is not instantiated with any invalid types */
1215 for (int i = 0; i < method_inst->type_argc; i++) {
1216 if (!mono_type_is_valid_generic_argument (method_inst->type_argv [i])) {
1217 mono_error_set_bad_image (error, mono_method_get_image (method), "MVAR %d cannot be expanded with type 0x%x",
1218 i, method_inst->type_argv [i]->type);
1219 goto fail;
1224 if (klass_hint) {
1225 MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint);
1226 if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst))
1227 klass_hint = NULL;
1230 if (mono_class_is_gtd (method->klass))
1231 result->klass = klass_hint;
1233 if (!result->klass) {
1234 MonoType *inflated = inflate_generic_type (NULL, m_class_get_byval_arg (method->klass), context, error);
1235 if (!mono_error_ok (error))
1236 goto fail;
1238 result->klass = inflated ? mono_class_from_mono_type_internal (inflated) : method->klass;
1239 if (inflated)
1240 mono_metadata_free_type (inflated);
1244 * FIXME: This should hold, but it doesn't:
1246 * if (result->is_inflated && mono_method_get_context (result)->method_inst &&
1247 * mono_method_get_context (result)->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)result)->declaring)->context.method_inst) {
1248 * g_assert (result->is_generic);
1251 * Fixing this here causes other things to break, hence a very
1252 * ugly hack in mini-trampolines.c - see
1253 * is_generic_method_definition().
1256 // check cache
1257 mono_image_set_lock (set);
1258 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1259 if (!cached) {
1260 g_hash_table_insert (set->gmethod_cache, iresult, iresult);
1261 iresult->owner = set;
1262 cached = iresult;
1264 mono_image_set_unlock (set);
1266 return (MonoMethod*)cached;
1268 fail:
1269 g_free (iresult);
1270 return NULL;
1274 * mono_get_inflated_method:
1276 * Obsolete. We keep it around since it's mentioned in the public API.
1278 MonoMethod*
1279 mono_get_inflated_method (MonoMethod *method)
1281 return method;
1285 * mono_method_get_context_general:
1286 * @method: a method
1287 * @uninflated: handle uninflated methods?
1289 * Returns the generic context of a method or NULL if it doesn't have
1290 * one. For an inflated method that's the context stored in the
1291 * method. Otherwise it's in the method's generic container or in the
1292 * generic container of the method's class.
1294 MonoGenericContext*
1295 mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
1297 if (method->is_inflated) {
1298 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1299 return &imethod->context;
1301 if (!uninflated)
1302 return NULL;
1303 if (method->is_generic)
1304 return &(mono_method_get_generic_container (method)->context);
1305 if (mono_class_is_gtd (method->klass))
1306 return &mono_class_get_generic_container (method->klass)->context;
1307 return NULL;
1311 * mono_method_get_context:
1312 * @method: a method
1314 * Returns the generic context for method if it's inflated, otherwise
1315 * NULL.
1317 MonoGenericContext*
1318 mono_method_get_context (MonoMethod *method)
1320 return mono_method_get_context_general (method, FALSE);
1324 * mono_method_get_generic_container:
1326 * Returns the generic container of METHOD, which should be a generic method definition.
1327 * Returns NULL if METHOD is not a generic method definition.
1328 * LOCKING: Acquires the loader lock.
1330 MonoGenericContainer*
1331 mono_method_get_generic_container (MonoMethod *method)
1333 MonoGenericContainer *container;
1335 if (!method->is_generic)
1336 return NULL;
1338 container = (MonoGenericContainer *)mono_image_property_lookup (mono_method_get_image (method), method, MONO_METHOD_PROP_GENERIC_CONTAINER);
1339 g_assert (container);
1341 return container;
1345 * mono_method_set_generic_container:
1347 * Sets the generic container of METHOD to CONTAINER.
1348 * LOCKING: Acquires the image lock.
1350 void
1351 mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
1353 g_assert (method->is_generic);
1355 mono_image_property_insert (mono_method_get_image (method), method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
1358 /**
1359 * mono_class_find_enum_basetype:
1360 * \param class The enum class
1362 * Determine the basetype of an enum by iterating through its fields. We do this
1363 * in a separate function since it is cheaper than calling mono_class_setup_fields.
1365 MonoType*
1366 mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
1368 MonoGenericContainer *container = NULL;
1369 MonoImage *image = m_class_get_image (klass);
1370 const int top = mono_class_get_field_count (klass);
1371 int i, first_field_idx;
1373 g_assert (m_class_is_enumtype (klass));
1375 error_init (error);
1377 container = mono_class_try_get_generic_container (klass);
1378 if (mono_class_is_ginst (klass)) {
1379 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1381 container = mono_class_get_generic_container (gklass);
1382 g_assert (container);
1386 * Fetch all the field information.
1388 first_field_idx = mono_class_get_first_field_idx (klass);
1389 for (i = 0; i < top; i++){
1390 const char *sig;
1391 guint32 cols [MONO_FIELD_SIZE];
1392 int idx = first_field_idx + i;
1393 MonoType *ftype;
1395 /* first_field_idx and idx points into the fieldptr table */
1396 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
1398 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
1399 continue;
1401 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], error))
1402 goto fail;
1404 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
1405 mono_metadata_decode_value (sig, &sig);
1406 /* FIELD signature == 0x06 */
1407 if (*sig != 0x06) {
1408 mono_error_set_bad_image (error, image, "Invalid field signature %x, expected 0x6 but got %x", cols [MONO_FIELD_SIGNATURE], *sig);
1409 goto fail;
1412 ftype = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
1413 if (!ftype)
1414 goto fail;
1416 if (mono_class_is_ginst (klass)) {
1417 //FIXME do we leak here?
1418 ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error);
1419 if (!mono_error_ok (error))
1420 goto fail;
1421 ftype->attrs = cols [MONO_FIELD_FLAGS];
1424 return ftype;
1426 mono_error_set_type_load_class (error, klass, "Could not find base type");
1428 fail:
1429 return NULL;
1433 * Checks for MonoClass::has_failure without resolving all MonoType's into MonoClass'es
1435 gboolean
1436 mono_type_has_exceptions (MonoType *type)
1438 switch (type->type) {
1439 case MONO_TYPE_CLASS:
1440 case MONO_TYPE_VALUETYPE:
1441 case MONO_TYPE_SZARRAY:
1442 return mono_class_has_failure (type->data.klass);
1443 case MONO_TYPE_ARRAY:
1444 return mono_class_has_failure (type->data.array->eklass);
1445 case MONO_TYPE_GENERICINST:
1446 return mono_class_has_failure (mono_class_create_generic_inst (type->data.generic_class));
1447 default:
1448 return FALSE;
1452 void
1453 mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
1455 g_assert (mono_class_has_failure (klass));
1456 MonoErrorBoxed *box = mono_class_get_exception_data ((MonoClass*)klass);
1457 mono_error_set_from_boxed (oerror, box);
1461 * mono_class_alloc:
1463 * Allocate memory for some data belonging to CLASS, either from its image's mempool,
1464 * or from the heap.
1466 gpointer
1467 mono_class_alloc (MonoClass *klass, int size)
1469 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1470 if (gklass)
1471 return mono_image_set_alloc (gklass->owner, size);
1472 else
1473 return mono_image_alloc (m_class_get_image (klass), size);
1476 gpointer
1477 (mono_class_alloc0) (MonoClass *klass, int size)
1479 gpointer res;
1481 res = mono_class_alloc (klass, size);
1482 memset (res, 0, size);
1483 return res;
1486 #define mono_class_new0(klass,struct_type, n_structs) \
1487 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
1490 * mono_class_set_failure_causedby_class:
1491 * \param klass the class that is failing
1492 * \param caused_by the class that caused the failure
1493 * \param msg Why \p klass is failing.
1495 * If \p caused_by has a failure, sets a TypeLoadException failure on
1496 * \p klass with message "\p msg, due to: {\p caused_by message}".
1498 * \returns TRUE if a failiure was set, or FALSE if \p caused_by doesn't have a failure.
1500 gboolean
1501 mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg)
1503 if (mono_class_has_failure (caused_by)) {
1504 ERROR_DECL (cause_error);
1505 mono_error_set_for_class_failure (cause_error, caused_by);
1506 mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (cause_error));
1507 mono_error_cleanup (cause_error);
1508 return TRUE;
1509 } else {
1510 return FALSE;
1516 * mono_type_get_basic_type_from_generic:
1517 * @type: a type
1519 * Returns a closed type corresponding to the possibly open type
1520 * passed to it.
1522 MonoType*
1523 mono_type_get_basic_type_from_generic (MonoType *type)
1525 /* When we do generic sharing we let type variables stand for reference/primitive types. */
1526 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) &&
1527 (!type->data.generic_param->gshared_constraint || type->data.generic_param->gshared_constraint->type == MONO_TYPE_OBJECT))
1528 return mono_get_object_type ();
1529 return type;
1533 * mono_class_get_method_by_index:
1535 * Returns klass->methods [index], initializing klass->methods if neccesary.
1537 * LOCKING: Acquires the loader lock.
1539 MonoMethod*
1540 mono_class_get_method_by_index (MonoClass *klass, int index)
1542 ERROR_DECL (error);
1544 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1545 /* Avoid calling setup_methods () if possible */
1546 if (gklass && !m_class_get_methods (klass)) {
1547 MonoMethod *m;
1549 m = mono_class_inflate_generic_method_full_checked (
1550 m_class_get_methods (gklass->container_class) [index], klass, mono_class_get_context (klass), error);
1551 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
1553 * If setup_methods () is called later for this class, no duplicates are created,
1554 * since inflate_generic_method guarantees that only one instance of a method
1555 * is created for each context.
1558 mono_class_setup_methods (klass);
1559 g_assert (m == klass->methods [index]);
1561 return m;
1562 } else {
1563 mono_class_setup_methods (klass);
1564 if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
1565 return NULL;
1566 g_assert (index >= 0 && index < mono_class_get_method_count (klass));
1567 return m_class_get_methods (klass) [index];
1572 * mono_class_get_inflated_method:
1573 * \param klass an inflated class
1574 * \param method a method of \p klass's generic definition
1575 * \param error set on error
1577 * Given an inflated class \p klass and a method \p method which should be a
1578 * method of \p klass's generic definition, return the inflated method
1579 * corresponding to \p method.
1581 * On failure sets \p error and returns NULL.
1583 MonoMethod*
1584 mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method, MonoError *error)
1586 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1587 int i, mcount;
1589 g_assert (method->klass == gklass);
1591 mono_class_setup_methods (gklass);
1592 if (mono_class_has_failure (gklass)) {
1593 mono_error_set_for_class_failure (error, gklass);
1594 return NULL;
1597 MonoMethod **gklass_methods = m_class_get_methods (gklass);
1598 mcount = mono_class_get_method_count (gklass);
1599 for (i = 0; i < mcount; ++i) {
1600 if (gklass_methods [i] == method) {
1601 MonoMethod *inflated_method = NULL;
1602 MonoMethod **klass_methods = m_class_get_methods (klass);
1603 if (klass_methods) {
1604 inflated_method = klass_methods [i];
1605 } else {
1606 inflated_method = mono_class_inflate_generic_method_full_checked (gklass_methods [i], klass, mono_class_get_context (klass), error);
1607 return_val_if_nok (error, NULL);
1609 g_assert (inflated_method);
1610 return inflated_method;
1614 g_assert_not_reached ();
1618 * mono_class_get_vtable_entry:
1620 * Returns klass->vtable [offset], computing it if neccesary. Returns NULL on failure.
1621 * LOCKING: Acquires the loader lock.
1623 MonoMethod*
1624 mono_class_get_vtable_entry (MonoClass *klass, int offset)
1626 MonoMethod *m;
1628 if (m_class_get_rank (klass) == 1) {
1629 MonoClass *klass_parent = m_class_get_parent (klass);
1631 * szarrays do not overwrite any methods of Array, so we can avoid
1632 * initializing their vtables in some cases.
1634 mono_class_setup_vtable (klass_parent);
1635 if (offset < m_class_get_vtable_size (klass_parent))
1636 return m_class_get_vtable (klass_parent) [offset];
1639 if (mono_class_is_ginst (klass)) {
1640 ERROR_DECL (error);
1641 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1642 mono_class_setup_vtable (gklass);
1643 m = m_class_get_vtable (gklass) [offset];
1645 m = mono_class_inflate_generic_method_full_checked (m, klass, mono_class_get_context (klass), error);
1646 g_assert (mono_error_ok (error)); /* FIXME don't swallow this error */
1647 } else {
1648 mono_class_setup_vtable (klass);
1649 if (mono_class_has_failure (klass))
1650 return NULL;
1651 m = m_class_get_vtable (klass) [offset];
1654 return m;
1658 * mono_class_get_vtable_size:
1660 * Return the vtable size for KLASS.
1663 mono_class_get_vtable_size (MonoClass *klass)
1665 mono_class_setup_vtable (klass);
1667 return m_class_get_vtable_size (klass);
1670 static void
1671 collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, GHashTable **ifaces, MonoError *error)
1673 int i;
1674 MonoClass *ic;
1676 mono_class_setup_interfaces (klass, error);
1677 return_if_nok (error);
1679 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
1680 for (i = 0; i < m_class_get_interface_count (klass); i++) {
1681 ic = klass_interfaces [i];
1683 if (*res == NULL)
1684 *res = g_ptr_array_new ();
1685 if (*ifaces == NULL)
1686 *ifaces = g_hash_table_new (NULL, NULL);
1687 if (g_hash_table_lookup (*ifaces, ic))
1688 continue;
1689 /* A gparam is not an implemented interface for the purposes of
1690 * mono_class_get_implemented_interfaces */
1691 if (mono_class_is_gparam (ic))
1692 continue;
1693 g_ptr_array_add (*res, ic);
1694 g_hash_table_insert (*ifaces, ic, ic);
1695 mono_class_init_internal (ic);
1696 if (mono_class_has_failure (ic)) {
1697 mono_error_set_type_load_class (error, ic, "Error Loading class");
1698 return;
1701 collect_implemented_interfaces_aux (ic, res, ifaces, error);
1702 return_if_nok (error);
1706 GPtrArray*
1707 mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error)
1709 GPtrArray *res = NULL;
1710 GHashTable *ifaces = NULL;
1712 collect_implemented_interfaces_aux (klass, &res, &ifaces, error);
1713 if (ifaces)
1714 g_hash_table_destroy (ifaces);
1715 if (!mono_error_ok (error)) {
1716 if (res)
1717 g_ptr_array_free (res, TRUE);
1718 return NULL;
1720 return res;
1723 static int
1724 compare_interface_ids (const void *p_key, const void *p_element)
1726 MonoClass *key = (MonoClass *)p_key;
1727 MonoClass *element = *(MonoClass **)p_element;
1729 return (m_class_get_interface_id (key) - m_class_get_interface_id (element));
1732 /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/
1734 mono_class_interface_offset (MonoClass *klass, MonoClass *itf)
1736 int i;
1737 MonoClass **klass_interfaces_packed = m_class_get_interfaces_packed (klass);
1738 for (i = m_class_get_interface_offsets_count (klass) -1 ; i >= 0 ; i-- ){
1739 MonoClass *result = klass_interfaces_packed[i];
1740 if (m_class_get_interface_id(result) == m_class_get_interface_id(itf)) {
1741 return m_class_get_interface_offsets_packed (klass) [i];
1744 return -1;
1748 * mono_class_interface_offset_with_variance:
1750 * Return the interface offset of \p itf in \p klass. Sets \p non_exact_match to TRUE if the match required variance check
1751 * If \p itf is an interface with generic variant arguments, try to find the compatible one.
1753 * Note that this function is responsible for resolving ambiguities. Right now we use whatever ordering interfaces_packed gives us.
1755 * FIXME figure out MS disambiguation rules and fix this function.
1758 mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match)
1760 int i = mono_class_interface_offset (klass, itf);
1761 *non_exact_match = FALSE;
1762 if (i >= 0)
1763 return i;
1765 int klass_interface_offsets_count = m_class_get_interface_offsets_count (klass);
1767 if (m_class_is_array_special_interface (itf) && m_class_get_rank (klass) < 2) {
1768 MonoClass *gtd = mono_class_get_generic_type_definition (itf);
1769 int found = -1;
1771 for (i = 0; i < klass_interface_offsets_count; i++) {
1772 if (mono_class_is_variant_compatible (itf, m_class_get_interfaces_packed (klass) [i], FALSE)) {
1773 found = i;
1774 *non_exact_match = TRUE;
1775 break;
1779 if (found != -1)
1780 return m_class_get_interface_offsets_packed (klass) [found];
1782 for (i = 0; i < klass_interface_offsets_count; i++) {
1783 if (mono_class_get_generic_type_definition (m_class_get_interfaces_packed (klass) [i]) == gtd) {
1784 found = i;
1785 *non_exact_match = TRUE;
1786 break;
1790 if (found == -1)
1791 return -1;
1793 return m_class_get_interface_offsets_packed (klass) [found];
1796 if (!mono_class_has_variant_generic_params (itf))
1797 return -1;
1799 for (i = 0; i < klass_interface_offsets_count; i++) {
1800 if (mono_class_is_variant_compatible (itf, m_class_get_interfaces_packed (klass) [i], FALSE)) {
1801 *non_exact_match = TRUE;
1802 return m_class_get_interface_offsets_packed (klass) [i];
1806 return -1;
1811 * mono_method_get_vtable_slot:
1813 * Returns method->slot, computing it if neccesary. Return -1 on failure.
1814 * LOCKING: Acquires the loader lock.
1816 * FIXME Use proper MonoError machinery here.
1819 mono_method_get_vtable_slot (MonoMethod *method)
1821 if (method->slot == -1) {
1822 mono_class_setup_vtable (method->klass);
1823 if (mono_class_has_failure (method->klass))
1824 return -1;
1825 if (method->slot == -1) {
1826 MonoClass *gklass;
1827 int i, mcount;
1829 if (!mono_class_is_ginst (method->klass)) {
1830 g_assert (method->is_inflated);
1831 return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
1834 /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
1835 g_assert (mono_class_is_ginst (method->klass));
1836 gklass = mono_class_get_generic_class (method->klass)->container_class;
1837 mono_class_setup_methods (method->klass);
1838 MonoMethod **klass_methods = m_class_get_methods (method->klass);
1839 g_assert (klass_methods);
1840 mcount = mono_class_get_method_count (method->klass);
1841 for (i = 0; i < mcount; ++i) {
1842 if (klass_methods [i] == method)
1843 break;
1845 g_assert (i < mcount);
1846 g_assert (m_class_get_methods (gklass));
1847 method->slot = m_class_get_methods (gklass) [i]->slot;
1849 g_assert (method->slot != -1);
1851 return method->slot;
1855 * mono_method_get_vtable_index:
1856 * \param method a method
1858 * Returns the index into the runtime vtable to access the method or,
1859 * in the case of a virtual generic method, the virtual generic method
1860 * thunk. Returns -1 on failure.
1862 * FIXME Use proper MonoError machinery here.
1865 mono_method_get_vtable_index (MonoMethod *method)
1867 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
1868 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
1869 if (imethod->declaring->is_generic)
1870 return mono_method_get_vtable_slot (imethod->declaring);
1872 return mono_method_get_vtable_slot (method);
1876 * mono_class_has_finalizer:
1878 * Return whenever KLASS has a finalizer, initializing klass->has_finalizer in the
1879 * process.
1881 * LOCKING: Acquires the loader lock;
1883 gboolean
1884 mono_class_has_finalizer (MonoClass *klass)
1886 if (!m_class_is_has_finalize_inited (klass))
1887 mono_class_setup_has_finalizer (klass);
1889 return m_class_has_finalize (klass);
1892 gboolean
1893 mono_is_corlib_image (MonoImage *image)
1895 return image == mono_defaults.corlib;
1899 /** Is klass a Nullable<T> ginst? */
1900 gboolean
1901 mono_class_is_nullable (MonoClass *klass)
1903 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1904 return gklass && gklass->container_class == mono_defaults.generic_nullable_class;
1907 /** if klass is T? return T */
1908 MonoClass*
1909 mono_class_get_nullable_param_internal (MonoClass *klass)
1911 g_assert (mono_class_is_nullable (klass));
1912 return mono_class_from_mono_type_internal (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
1915 MonoClass*
1916 mono_class_get_nullable_param (MonoClass *klass)
1918 MonoClass *result = NULL;
1919 MONO_ENTER_GC_UNSAFE;
1920 result = mono_class_get_nullable_param_internal (klass);
1921 MONO_EXIT_GC_UNSAFE;
1922 return result;
1925 gboolean
1926 mono_type_is_primitive (MonoType *type)
1928 return (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_R8) ||
1929 type-> type == MONO_TYPE_I || type->type == MONO_TYPE_U;
1932 static MonoImage *
1933 get_image_for_container (MonoGenericContainer *container)
1935 MonoImage *result;
1936 if (container->is_anonymous) {
1937 result = container->owner.image;
1938 } else {
1939 MonoClass *klass;
1940 if (container->is_method) {
1941 MonoMethod *method = container->owner.method;
1942 g_assert_checked (method);
1943 klass = method->klass;
1944 } else {
1945 klass = container->owner.klass;
1947 g_assert_checked (klass);
1948 result = m_class_get_image (klass);
1950 g_assert (result);
1951 return result;
1954 MonoImage *
1955 mono_get_image_for_generic_param (MonoGenericParam *param)
1957 MonoGenericContainer *container = mono_generic_param_owner (param);
1958 g_assert_checked (container);
1959 return get_image_for_container (container);
1962 // Make a string in the designated image consisting of a single integer.
1963 #define INT_STRING_SIZE 16
1964 char *
1965 mono_make_generic_name_string (MonoImage *image, int num)
1967 char *name = (char *)mono_image_alloc0 (image, INT_STRING_SIZE);
1968 g_snprintf (name, INT_STRING_SIZE, "%d", num);
1969 return name;
1973 * mono_class_from_generic_parameter:
1974 * \param param Parameter to find/construct a class for.
1975 * \param arg2 Is ignored.
1976 * \param arg3 Is ignored.
1978 MonoClass *
1979 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GNUC_UNUSED, gboolean arg3 G_GNUC_UNUSED)
1981 return mono_class_create_generic_parameter (param);
1985 * mono_ptr_class_get:
1987 MonoClass *
1988 mono_ptr_class_get (MonoType *type)
1990 return mono_class_create_ptr (type);
1994 * mono_class_from_mono_type:
1995 * \param type describes the type to return
1996 * \returns a \c MonoClass for the specified \c MonoType, the value is never NULL.
1998 MonoClass *
1999 mono_class_from_mono_type (MonoType *type)
2001 MonoClass *result;
2002 MONO_ENTER_GC_UNSAFE;
2003 result = mono_class_from_mono_type_internal (type);
2004 MONO_EXIT_GC_UNSAFE;
2005 return result;
2008 MonoClass *
2009 mono_class_from_mono_type_internal (MonoType *type)
2011 switch (type->type) {
2012 case MONO_TYPE_OBJECT:
2013 return type->data.klass? type->data.klass: mono_defaults.object_class;
2014 case MONO_TYPE_VOID:
2015 return type->data.klass? type->data.klass: mono_defaults.void_class;
2016 case MONO_TYPE_BOOLEAN:
2017 return type->data.klass? type->data.klass: mono_defaults.boolean_class;
2018 case MONO_TYPE_CHAR:
2019 return type->data.klass? type->data.klass: mono_defaults.char_class;
2020 case MONO_TYPE_I1:
2021 return type->data.klass? type->data.klass: mono_defaults.sbyte_class;
2022 case MONO_TYPE_U1:
2023 return type->data.klass? type->data.klass: mono_defaults.byte_class;
2024 case MONO_TYPE_I2:
2025 return type->data.klass? type->data.klass: mono_defaults.int16_class;
2026 case MONO_TYPE_U2:
2027 return type->data.klass? type->data.klass: mono_defaults.uint16_class;
2028 case MONO_TYPE_I4:
2029 return type->data.klass? type->data.klass: mono_defaults.int32_class;
2030 case MONO_TYPE_U4:
2031 return type->data.klass? type->data.klass: mono_defaults.uint32_class;
2032 case MONO_TYPE_I:
2033 return type->data.klass? type->data.klass: mono_defaults.int_class;
2034 case MONO_TYPE_U:
2035 return type->data.klass? type->data.klass: mono_defaults.uint_class;
2036 case MONO_TYPE_I8:
2037 return type->data.klass? type->data.klass: mono_defaults.int64_class;
2038 case MONO_TYPE_U8:
2039 return type->data.klass? type->data.klass: mono_defaults.uint64_class;
2040 case MONO_TYPE_R4:
2041 return type->data.klass? type->data.klass: mono_defaults.single_class;
2042 case MONO_TYPE_R8:
2043 return type->data.klass? type->data.klass: mono_defaults.double_class;
2044 case MONO_TYPE_STRING:
2045 return type->data.klass? type->data.klass: mono_defaults.string_class;
2046 case MONO_TYPE_TYPEDBYREF:
2047 return type->data.klass? type->data.klass: mono_defaults.typed_reference_class;
2048 case MONO_TYPE_ARRAY:
2049 return mono_class_create_bounded_array (type->data.array->eklass, type->data.array->rank, TRUE);
2050 case MONO_TYPE_PTR:
2051 return mono_class_create_ptr (type->data.type);
2052 case MONO_TYPE_FNPTR:
2053 return mono_class_create_fnptr (type->data.method);
2054 case MONO_TYPE_SZARRAY:
2055 return mono_class_create_array (type->data.klass, 1);
2056 case MONO_TYPE_CLASS:
2057 case MONO_TYPE_VALUETYPE:
2058 return type->data.klass;
2059 case MONO_TYPE_GENERICINST:
2060 return mono_class_create_generic_inst (type->data.generic_class);
2061 case MONO_TYPE_MVAR:
2062 case MONO_TYPE_VAR:
2063 return mono_class_create_generic_parameter (type->data.generic_param);
2064 default:
2065 g_warning ("mono_class_from_mono_type_internal: implement me 0x%02x\n", type->type);
2066 g_assert_not_reached ();
2069 // Yes, this returns NULL, even if it is documented as not doing so, but there
2070 // is no way for the code to make it this far, due to the assert above.
2071 return NULL;
2075 * mono_type_retrieve_from_typespec
2076 * \param image context where the image is created
2077 * \param type_spec typespec token
2078 * \param context the generic context used to evaluate generic instantiations in
2080 static MonoType *
2081 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
2083 MonoType *t = mono_type_create_from_typespec_checked (image, type_spec, error);
2085 *did_inflate = FALSE;
2087 if (!t)
2088 return NULL;
2090 if (context && (context->class_inst || context->method_inst)) {
2091 MonoType *inflated = inflate_generic_type (NULL, t, context, error);
2093 if (!mono_error_ok (error)) {
2094 return NULL;
2097 if (inflated) {
2098 t = inflated;
2099 *did_inflate = TRUE;
2102 return t;
2106 * mono_class_create_from_typespec
2107 * \param image context where the image is created
2108 * \param type_spec typespec token
2109 * \param context the generic context used to evaluate generic instantiations in
2111 static MonoClass *
2112 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
2114 MonoClass *ret;
2115 gboolean inflated = FALSE;
2116 MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
2117 return_val_if_nok (error, NULL);
2118 ret = mono_class_from_mono_type_internal (t);
2119 if (inflated)
2120 mono_metadata_free_type (t);
2121 return ret;
2125 * mono_bounded_array_class_get:
2126 * \param element_class element class
2127 * \param rank the dimension of the array class
2128 * \param bounded whenever the array has non-zero bounds
2129 * \returns A class object describing the array with element type \p element_type and
2130 * dimension \p rank.
2132 MonoClass *
2133 mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
2135 return mono_class_create_bounded_array (eclass, rank, bounded);
2139 * mono_array_class_get:
2140 * \param element_class element class
2141 * \param rank the dimension of the array class
2142 * \returns A class object describing the array with element type \p element_type and
2143 * dimension \p rank.
2145 MonoClass *
2146 mono_array_class_get (MonoClass *eclass, guint32 rank)
2148 return mono_class_create_array (eclass, rank);
2152 * mono_class_instance_size:
2153 * \param klass a class
2155 * Use to get the size of a class in bytes.
2157 * \returns The size of an object instance
2159 gint32
2160 mono_class_instance_size (MonoClass *klass)
2162 if (!m_class_is_size_inited (klass))
2163 mono_class_init_internal (klass);
2165 return m_class_get_instance_size (klass);
2169 * mono_class_min_align:
2170 * \param klass a class
2172 * Use to get the computed minimum alignment requirements for the specified class.
2174 * Returns: minimum alignment requirements
2176 gint32
2177 mono_class_min_align (MonoClass *klass)
2179 if (!m_class_is_size_inited (klass))
2180 mono_class_init_internal (klass);
2182 return m_class_get_min_align (klass);
2186 * mono_class_data_size:
2187 * \param klass a class
2189 * \returns The size of the static class data
2191 gint32
2192 mono_class_data_size (MonoClass *klass)
2194 if (!m_class_is_inited (klass))
2195 mono_class_init_internal (klass);
2196 /* This can happen with dynamically created types */
2197 if (!m_class_is_fields_inited (klass))
2198 mono_class_setup_fields (klass);
2200 /* in arrays, sizes.class_size is unioned with element_size
2201 * and arrays have no static fields
2203 if (m_class_get_rank (klass))
2204 return 0;
2205 return m_class_get_sizes (klass).class_size;
2209 * Auxiliary routine to mono_class_get_field
2211 * Takes a field index instead of a field token.
2213 static MonoClassField *
2214 mono_class_get_field_idx (MonoClass *klass, int idx)
2216 mono_class_setup_fields (klass);
2217 if (mono_class_has_failure (klass))
2218 return NULL;
2220 while (klass) {
2221 int first_field_idx = mono_class_get_first_field_idx (klass);
2222 int fcount = mono_class_get_field_count (klass);
2223 MonoImage *klass_image = m_class_get_image (klass);
2224 MonoClassField *klass_fields = m_class_get_fields (klass);
2225 if (klass_image->uncompressed_metadata) {
2227 * first_field_idx points to the FieldPtr table, while idx points into the
2228 * Field table, so we have to do a search.
2230 /*FIXME this is broken for types with multiple fields with the same name.*/
2231 const char *name = mono_metadata_string_heap (klass_image, mono_metadata_decode_row_col (&klass_image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
2232 int i;
2234 for (i = 0; i < fcount; ++i)
2235 if (mono_field_get_name (&klass_fields [i]) == name)
2236 return &klass_fields [i];
2237 g_assert_not_reached ();
2238 } else {
2239 if (fcount) {
2240 if ((idx >= first_field_idx) && (idx < first_field_idx + fcount)){
2241 return &klass_fields [idx - first_field_idx];
2245 klass = m_class_get_parent (klass);
2247 return NULL;
2251 * mono_class_get_field:
2252 * \param class the class to lookup the field.
2253 * \param field_token the field token
2255 * \returns A \c MonoClassField representing the type and offset of
2256 * the field, or a NULL value if the field does not belong to this
2257 * class.
2259 MonoClassField *
2260 mono_class_get_field (MonoClass *klass, guint32 field_token)
2262 int idx = mono_metadata_token_index (field_token);
2264 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
2266 return mono_class_get_field_idx (klass, idx - 1);
2270 * mono_class_get_field_from_name:
2271 * \param klass the class to lookup the field.
2272 * \param name the field name
2274 * Search the class \p klass and its parents for a field with the name \p name.
2276 * \returns The \c MonoClassField pointer of the named field or NULL
2278 MonoClassField *
2279 mono_class_get_field_from_name (MonoClass *klass, const char *name)
2281 MonoClassField *result;
2282 MONO_ENTER_GC_UNSAFE;
2283 result = mono_class_get_field_from_name_full (klass, name, NULL);
2284 MONO_EXIT_GC_UNSAFE;
2285 return result;
2289 * mono_class_get_field_from_name_full:
2290 * \param klass the class to lookup the field.
2291 * \param name the field name
2292 * \param type the type of the fields. This optional.
2294 * Search the class \p klass and it's parents for a field with the name \p name and type \p type.
2296 * If \p klass is an inflated generic type, the type comparison is done with the equivalent field
2297 * of its generic type definition.
2299 * \returns The MonoClassField pointer of the named field or NULL
2301 MonoClassField *
2302 mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
2304 MONO_REQ_GC_UNSAFE_MODE;
2306 int i;
2308 mono_class_setup_fields (klass);
2309 if (mono_class_has_failure (klass))
2310 return NULL;
2312 while (klass) {
2313 int fcount = mono_class_get_field_count (klass);
2314 for (i = 0; i < fcount; ++i) {
2315 MonoClassField *field = &m_class_get_fields (klass) [i];
2317 if (strcmp (name, mono_field_get_name (field)) != 0)
2318 continue;
2320 if (type) {
2321 MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
2322 if (!mono_metadata_type_equal_full (type, field_type, TRUE))
2323 continue;
2325 return field;
2327 klass = m_class_get_parent (klass);
2329 return NULL;
2333 * mono_class_get_field_token:
2334 * \param field the field we need the token of
2336 * Get the token of a field. Note that the tokesn is only valid for the image
2337 * the field was loaded from. Don't use this function for fields in dynamic types.
2339 * \returns The token representing the field in the image it was loaded from.
2341 guint32
2342 mono_class_get_field_token (MonoClassField *field)
2344 MonoClass *klass = field->parent;
2345 int i;
2347 mono_class_setup_fields (klass);
2349 while (klass) {
2350 MonoClassField *klass_fields = m_class_get_fields (klass);
2351 if (!klass_fields)
2352 return 0;
2353 int first_field_idx = mono_class_get_first_field_idx (klass);
2354 int fcount = mono_class_get_field_count (klass);
2355 for (i = 0; i < fcount; ++i) {
2356 if (&klass_fields [i] == field) {
2357 int idx = first_field_idx + i + 1;
2359 if (m_class_get_image (klass)->uncompressed_metadata)
2360 idx = mono_metadata_translate_token_index (m_class_get_image (klass), MONO_TABLE_FIELD, idx);
2361 return mono_metadata_make_token (MONO_TABLE_FIELD, idx);
2364 klass = m_class_get_parent (klass);
2367 g_assert_not_reached ();
2368 return 0;
2371 static int
2372 mono_field_get_index (MonoClassField *field)
2374 int index = field - m_class_get_fields (field->parent);
2375 g_assert (index >= 0 && index < mono_class_get_field_count (field->parent));
2377 return index;
2381 * mono_class_get_field_default_value:
2383 * Return the default value of the field as a pointer into the metadata blob.
2385 const char*
2386 mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
2388 guint32 cindex;
2389 guint32 constant_cols [MONO_CONSTANT_SIZE];
2390 int field_index;
2391 MonoClass *klass = field->parent;
2392 MonoFieldDefaultValue *def_values;
2394 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2396 def_values = mono_class_get_field_def_values (klass);
2397 if (!def_values) {
2398 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
2400 mono_class_set_field_def_values (klass, def_values);
2403 field_index = mono_field_get_index (field);
2405 if (!def_values [field_index].data) {
2406 MonoImage *field_parent_image = m_class_get_image (field->parent);
2407 cindex = mono_metadata_get_constant_index (field_parent_image, mono_class_get_field_token (field), 0);
2408 if (!cindex)
2409 return NULL;
2411 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
2413 mono_metadata_decode_row (&field_parent_image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
2414 def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
2415 mono_memory_barrier ();
2416 def_values [field_index].data = (const char *)mono_metadata_blob_heap (field_parent_image, constant_cols [MONO_CONSTANT_VALUE]);
2419 *def_type = def_values [field_index].def_type;
2420 return def_values [field_index].data;
2423 static int
2424 mono_property_get_index (MonoProperty *prop)
2426 MonoClassPropertyInfo *info = mono_class_get_property_info (prop->parent);
2427 int index = prop - info->properties;
2429 g_assert (index >= 0 && index < info->count);
2431 return index;
2435 * mono_class_get_property_default_value:
2437 * Return the default value of the field as a pointer into the metadata blob.
2439 const char*
2440 mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type)
2442 guint32 cindex;
2443 guint32 constant_cols [MONO_CONSTANT_SIZE];
2444 MonoClass *klass = property->parent;
2445 MonoImage *klass_image = m_class_get_image (klass);
2447 g_assert (property->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT);
2449 * We don't cache here because it is not used by C# so it's quite rare, but
2450 * we still do the lookup in klass->ext because that is where the data
2451 * is stored for dynamic assemblies.
2454 if (image_is_dynamic (klass_image)) {
2455 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
2456 int prop_index = mono_property_get_index (property);
2457 if (info->def_values && info->def_values [prop_index].data) {
2458 *def_type = info->def_values [prop_index].def_type;
2459 return info->def_values [prop_index].data;
2461 return NULL;
2463 cindex = mono_metadata_get_constant_index (klass_image, mono_class_get_property_token (property), 0);
2464 if (!cindex)
2465 return NULL;
2467 mono_metadata_decode_row (&klass_image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
2468 *def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
2469 return (const char *)mono_metadata_blob_heap (klass_image, constant_cols [MONO_CONSTANT_VALUE]);
2473 * mono_class_get_event_token:
2475 guint32
2476 mono_class_get_event_token (MonoEvent *event)
2478 MonoClass *klass = event->parent;
2479 int i;
2481 while (klass) {
2482 MonoClassEventInfo *info = mono_class_get_event_info (klass);
2483 if (info) {
2484 for (i = 0; i < info->count; ++i) {
2485 if (&info->events [i] == event)
2486 return mono_metadata_make_token (MONO_TABLE_EVENT, info->first + i + 1);
2489 klass = m_class_get_parent (klass);
2492 g_assert_not_reached ();
2493 return 0;
2496 MonoProperty*
2497 mono_class_get_property_from_name_internal (MonoClass *klass, const char *name)
2499 MONO_REQ_GC_UNSAFE_MODE;
2500 while (klass) {
2501 MonoProperty* p;
2502 gpointer iter = NULL;
2503 while ((p = mono_class_get_properties (klass, &iter))) {
2504 if (! strcmp (name, p->name))
2505 return p;
2507 klass = m_class_get_parent (klass);
2509 return NULL;
2513 * mono_class_get_property_token:
2514 * \param prop MonoProperty to query
2516 * \returns The ECMA token for the specified property.
2518 guint32
2519 mono_class_get_property_token (MonoProperty *prop)
2521 MonoClass *klass = prop->parent;
2522 while (klass) {
2523 MonoProperty* p;
2524 int i = 0;
2525 gpointer iter = NULL;
2526 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
2527 while ((p = mono_class_get_properties (klass, &iter))) {
2528 if (&info->properties [i] == prop)
2529 return mono_metadata_make_token (MONO_TABLE_PROPERTY, info->first + i + 1);
2531 i ++;
2533 klass = m_class_get_parent (klass);
2536 g_assert_not_reached ();
2537 return 0;
2541 * mono_class_name_from_token:
2543 char *
2544 mono_class_name_from_token (MonoImage *image, guint32 type_token)
2546 const char *name, *nspace;
2547 if (image_is_dynamic (image))
2548 return g_strdup_printf ("DynamicType 0x%08x", type_token);
2550 switch (type_token & 0xff000000){
2551 case MONO_TOKEN_TYPE_DEF: {
2552 guint32 cols [MONO_TYPEDEF_SIZE];
2553 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
2554 guint tidx = mono_metadata_token_index (type_token);
2556 if (tidx > tt->rows)
2557 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2559 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
2560 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2561 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2562 if (strlen (nspace) == 0)
2563 return g_strdup_printf ("%s", name);
2564 else
2565 return g_strdup_printf ("%s.%s", nspace, name);
2568 case MONO_TOKEN_TYPE_REF: {
2569 ERROR_DECL (error);
2570 guint32 cols [MONO_TYPEREF_SIZE];
2571 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2572 guint tidx = mono_metadata_token_index (type_token);
2574 if (tidx > t->rows)
2575 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2577 if (!mono_verifier_verify_typeref_row (image, tidx - 1, error)) {
2578 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (error));
2579 mono_error_cleanup (error);
2580 return msg;
2583 mono_metadata_decode_row (t, tidx-1, cols, MONO_TYPEREF_SIZE);
2584 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2585 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2586 if (strlen (nspace) == 0)
2587 return g_strdup_printf ("%s", name);
2588 else
2589 return g_strdup_printf ("%s.%s", nspace, name);
2592 case MONO_TOKEN_TYPE_SPEC:
2593 return g_strdup_printf ("Typespec 0x%08x", type_token);
2594 default:
2595 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2599 static char *
2600 mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
2602 if (image_is_dynamic (image))
2603 return g_strdup_printf ("DynamicAssembly %s", image->name);
2605 switch (type_token & 0xff000000){
2606 case MONO_TOKEN_TYPE_DEF:
2607 if (image->assembly)
2608 return mono_stringify_assembly_name (&image->assembly->aname);
2609 else if (image->assembly_name)
2610 return g_strdup (image->assembly_name);
2611 return g_strdup_printf ("%s", image->name ? image->name : "[Could not resolve assembly name");
2612 case MONO_TOKEN_TYPE_REF: {
2613 ERROR_DECL (error);
2614 MonoAssemblyName aname;
2615 guint32 cols [MONO_TYPEREF_SIZE];
2616 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2617 guint32 idx = mono_metadata_token_index (type_token);
2619 if (idx > t->rows)
2620 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2622 if (!mono_verifier_verify_typeref_row (image, idx - 1, error)) {
2623 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (error));
2624 mono_error_cleanup (error);
2625 return msg;
2627 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
2629 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
2630 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
2631 case MONO_RESOLUTION_SCOPE_MODULE:
2632 /* FIXME: */
2633 return g_strdup ("");
2634 case MONO_RESOLUTION_SCOPE_MODULEREF:
2635 /* FIXME: */
2636 return g_strdup ("");
2637 case MONO_RESOLUTION_SCOPE_TYPEREF:
2638 /* FIXME: */
2639 return g_strdup ("");
2640 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
2641 mono_assembly_get_assemblyref (image, idx - 1, &aname);
2642 return mono_stringify_assembly_name (&aname);
2643 default:
2644 g_assert_not_reached ();
2646 break;
2648 case MONO_TOKEN_TYPE_SPEC:
2649 /* FIXME: */
2650 return g_strdup ("");
2651 default:
2652 g_assert_not_reached ();
2655 return NULL;
2659 * mono_class_get_full:
2660 * \param image the image where the class resides
2661 * \param type_token the token for the class
2662 * \param context the generic context used to evaluate generic instantiations in
2663 * \deprecated Functions that expose \c MonoGenericContext are going away in mono 4.0
2664 * \returns The \c MonoClass that represents \p type_token in \p image
2666 MonoClass *
2667 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
2669 ERROR_DECL (error);
2670 MonoClass *klass;
2671 klass = mono_class_get_checked (image, type_token, error);
2673 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
2674 klass = mono_class_inflate_generic_class_checked (klass, context, error);
2676 mono_error_assert_ok (error);
2677 return klass;
2681 MonoClass *
2682 mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
2684 MonoClass *klass;
2686 error_init (error);
2687 klass = mono_class_get_checked (image, type_token, error);
2689 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
2690 klass = mono_class_inflate_generic_class_checked (klass, context, error);
2692 return klass;
2695 * mono_class_get_checked:
2696 * \param image the image where the class resides
2697 * \param type_token the token for the class
2698 * \param error error object to return any error
2700 * \returns The MonoClass that represents \p type_token in \p image, or NULL on error.
2702 MonoClass *
2703 mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
2705 MonoClass *klass = NULL;
2707 error_init (error);
2709 if (image_is_dynamic (image)) {
2710 int table = mono_metadata_token_table (type_token);
2712 if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
2713 mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
2714 return NULL;
2716 klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
2717 goto done;
2720 switch (type_token & 0xff000000){
2721 case MONO_TOKEN_TYPE_DEF:
2722 klass = mono_class_create_from_typedef (image, type_token, error);
2723 break;
2724 case MONO_TOKEN_TYPE_REF:
2725 klass = mono_class_from_typeref_checked (image, type_token, error);
2726 break;
2727 case MONO_TOKEN_TYPE_SPEC:
2728 klass = mono_class_create_from_typespec (image, type_token, NULL, error);
2729 break;
2730 default:
2731 mono_error_set_bad_image (error, image, "Unknown type token %x", type_token & 0xff000000);
2734 done:
2735 /* Generic case, should be avoided for when a better error is possible. */
2736 if (!klass && mono_error_ok (error)) {
2737 char *name = mono_class_name_from_token (image, type_token);
2738 char *assembly = mono_assembly_name_from_token (image, type_token);
2739 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x (expected class '%s' in assembly '%s')", type_token, name, assembly);
2742 return klass;
2747 * mono_type_get_checked:
2748 * \param image the image where the type resides
2749 * \param type_token the token for the type
2750 * \param context the generic context used to evaluate generic instantiations in
2751 * \param error Error handling context
2753 * This functions exists to fullfill the fact that sometimes it's desirable to have access to the
2755 * \returns The MonoType that represents \p type_token in \p image
2757 MonoType *
2758 mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
2760 MonoType *type = NULL;
2761 gboolean inflated = FALSE;
2763 error_init (error);
2765 //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
2766 if (image_is_dynamic (image)) {
2767 MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
2768 return_val_if_nok (error, NULL);
2769 return m_class_get_byval_arg (klass);
2772 if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
2773 MonoClass *klass = mono_class_get_checked (image, type_token, error);
2775 if (!klass)
2776 return NULL;
2777 if (m_class_has_failure (klass)) {
2778 mono_error_set_for_class_failure (error, klass);
2779 return NULL;
2781 return m_class_get_byval_arg (klass);
2784 type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
2786 if (!type) {
2787 return NULL;
2790 if (inflated) {
2791 MonoType *tmp = type;
2792 type = m_class_get_byval_arg (mono_class_from_mono_type_internal (type));
2793 /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
2794 * A MonoClass::_byval_arg of a generic type definion has type CLASS.
2795 * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with _byval_arg.
2797 * The long term solution is to chaise this places and make then set MonoType::type correctly.
2798 * */
2799 if (type->type != tmp->type)
2800 type = tmp;
2801 else
2802 mono_metadata_free_type (tmp);
2804 return type;
2808 * mono_class_get:
2809 * \param image image where the class token will be looked up.
2810 * \param type_token a type token from the image
2811 * \returns the \c MonoClass with the given \p type_token on the \p image
2813 MonoClass *
2814 mono_class_get (MonoImage *image, guint32 type_token)
2816 ERROR_DECL (error);
2817 error_init (error);
2818 MonoClass *result = mono_class_get_checked (image, type_token, error);
2819 mono_error_assert_ok (error);
2820 return result;
2824 * mono_image_init_name_cache:
2826 * Initializes the class name cache stored in image->name_cache.
2828 * LOCKING: Acquires the corresponding image lock.
2830 void
2831 mono_image_init_name_cache (MonoImage *image)
2833 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
2834 guint32 cols [MONO_TYPEDEF_SIZE];
2835 const char *name;
2836 const char *nspace;
2837 guint32 i, visib, nspace_index;
2838 GHashTable *name_cache2, *nspace_table, *the_name_cache;
2840 if (image->name_cache)
2841 return;
2843 the_name_cache = g_hash_table_new (g_str_hash, g_str_equal);
2845 if (image_is_dynamic (image)) {
2846 mono_image_lock (image);
2847 if (image->name_cache) {
2848 /* Somebody initialized it before us */
2849 g_hash_table_destroy (the_name_cache);
2850 } else {
2851 mono_atomic_store_release (&image->name_cache, the_name_cache);
2853 mono_image_unlock (image);
2854 return;
2857 /* Temporary hash table to avoid lookups in the nspace_table */
2858 name_cache2 = g_hash_table_new (NULL, NULL);
2860 for (i = 1; i <= t->rows; ++i) {
2861 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
2862 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2864 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
2865 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
2867 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
2868 continue;
2869 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2870 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2872 nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
2873 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
2874 if (!nspace_table) {
2875 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
2876 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
2877 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
2878 nspace_table);
2880 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
2883 /* Load type names from EXPORTEDTYPES table */
2885 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
2886 guint32 cols [MONO_EXP_TYPE_SIZE];
2887 int i;
2889 for (i = 0; i < t->rows; ++i) {
2890 mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
2892 guint32 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
2893 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_EXP_TYPE)
2894 /* Nested type */
2895 continue;
2897 name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
2898 nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
2900 nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
2901 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
2902 if (!nspace_table) {
2903 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
2904 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
2905 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
2906 nspace_table);
2908 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
2912 g_hash_table_destroy (name_cache2);
2914 mono_image_lock (image);
2915 if (image->name_cache) {
2916 /* Somebody initialized it before us */
2917 g_hash_table_destroy (the_name_cache);
2918 } else {
2919 mono_atomic_store_release (&image->name_cache, the_name_cache);
2921 mono_image_unlock (image);
2924 /*FIXME Only dynamic assemblies should allow this operation.*/
2926 * mono_image_add_to_name_cache:
2928 void
2929 mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
2930 const char *name, guint32 index)
2932 GHashTable *nspace_table;
2933 GHashTable *name_cache;
2934 guint32 old_index;
2936 mono_image_init_name_cache (image);
2937 mono_image_lock (image);
2939 name_cache = image->name_cache;
2940 if (!(nspace_table = (GHashTable *)g_hash_table_lookup (name_cache, nspace))) {
2941 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
2942 g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
2945 if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
2946 g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
2948 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
2950 mono_image_unlock (image);
2953 typedef struct {
2954 gconstpointer key;
2955 gpointer value;
2956 } FindUserData;
2958 static void
2959 find_nocase (gpointer key, gpointer value, gpointer user_data)
2961 char *name = (char*)key;
2962 FindUserData *data = (FindUserData*)user_data;
2964 if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
2965 data->value = value;
2969 * mono_class_from_name_case:
2970 * \param image The MonoImage where the type is looked up in
2971 * \param name_space the type namespace
2972 * \param name the type short name.
2973 * \deprecated use the mono_class_from_name_case_checked variant instead.
2975 * Obtains a \c MonoClass with a given namespace and a given name which
2976 * is located in the given \c MonoImage. The namespace and name
2977 * lookups are case insensitive.
2979 MonoClass *
2980 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
2982 ERROR_DECL (error);
2983 MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, error);
2984 mono_error_cleanup (error);
2986 return res;
2990 * mono_class_from_name_case_checked:
2991 * \param image The MonoImage where the type is looked up in
2992 * \param name_space the type namespace
2993 * \param name the type short name.
2994 * \param error if
2996 * Obtains a MonoClass with a given namespace and a given name which
2997 * is located in the given MonoImage. The namespace and name
2998 * lookups are case insensitive.
3000 * \returns The MonoClass if the given namespace and name were found, or NULL if it
3001 * was not found. The \p error object will contain information about the problem
3002 * in that case.
3004 MonoClass *
3005 mono_class_from_name_case_checked (MonoImage *image, const char *name_space, const char *name, MonoError *error)
3007 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
3008 guint32 cols [MONO_TYPEDEF_SIZE];
3009 const char *n;
3010 const char *nspace;
3011 guint32 i, visib;
3013 error_init (error);
3015 if (image_is_dynamic (image)) {
3016 guint32 token = 0;
3017 FindUserData user_data;
3019 mono_image_init_name_cache (image);
3020 mono_image_lock (image);
3022 user_data.key = name_space;
3023 user_data.value = NULL;
3024 g_hash_table_foreach (image->name_cache, find_nocase, &user_data);
3026 if (user_data.value) {
3027 GHashTable *nspace_table = (GHashTable*)user_data.value;
3029 user_data.key = name;
3030 user_data.value = NULL;
3032 g_hash_table_foreach (nspace_table, find_nocase, &user_data);
3034 if (user_data.value)
3035 token = GPOINTER_TO_UINT (user_data.value);
3038 mono_image_unlock (image);
3040 if (token)
3041 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | token, error);
3042 else
3043 return NULL;
3047 /* add a cache if needed */
3048 for (i = 1; i <= t->rows; ++i) {
3049 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
3050 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3052 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
3053 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
3055 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
3056 continue;
3057 n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
3058 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
3059 if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
3060 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | i, error);
3062 return NULL;
3065 static MonoClass*
3066 return_nested_in (MonoClass *klass, char *nested)
3068 MonoClass *found;
3069 char *s = strchr (nested, '/');
3070 gpointer iter = NULL;
3072 if (s) {
3073 *s = 0;
3074 s++;
3077 while ((found = mono_class_get_nested_types (klass, &iter))) {
3078 if (strcmp (m_class_get_name (found), nested) == 0) {
3079 if (s)
3080 return return_nested_in (found, s);
3081 return found;
3084 return NULL;
3087 static MonoClass*
3088 search_modules (MonoImage *image, const char *name_space, const char *name, MonoError *error)
3090 MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
3091 MonoImage *file_image;
3092 MonoClass *klass;
3093 int i;
3095 error_init (error);
3098 * The EXPORTEDTYPES table only contains public types, so have to search the
3099 * modules as well.
3100 * Note: image->modules contains the contents of the MODULEREF table, while
3101 * the real module list is in the FILE table.
3103 for (i = 0; i < file_table->rows; i++) {
3104 guint32 cols [MONO_FILE_SIZE];
3105 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
3106 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
3107 continue;
3109 file_image = mono_image_load_file_for_image_checked (image, i + 1, error);
3110 if (file_image) {
3111 klass = mono_class_from_name_checked (file_image, name_space, name, error);
3112 if (klass || !is_ok (error))
3113 return klass;
3117 return NULL;
3120 static MonoClass *
3121 mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, MonoError *error)
3123 GHashTable *nspace_table;
3124 MonoImage *loaded_image;
3125 guint32 token = 0;
3126 int i;
3127 MonoClass *klass;
3128 char *nested;
3129 char buf [1024];
3131 error_init (error);
3133 // Checking visited images avoids stack overflows when cyclic references exist.
3134 if (g_hash_table_lookup (visited_images, image))
3135 return NULL;
3137 g_hash_table_insert (visited_images, image, GUINT_TO_POINTER(1));
3139 if ((nested = (char*)strchr (name, '/'))) {
3140 int pos = nested - name;
3141 int len = strlen (name);
3142 if (len > 1023)
3143 return NULL;
3144 memcpy (buf, name, len + 1);
3145 buf [pos] = 0;
3146 nested = buf + pos + 1;
3147 name = buf;
3150 /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */
3151 if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
3152 gboolean res = get_class_from_name (image, name_space, name, &klass);
3153 if (res) {
3154 if (!klass) {
3155 klass = search_modules (image, name_space, name, error);
3156 if (!is_ok (error))
3157 return NULL;
3159 if (nested)
3160 return klass ? return_nested_in (klass, nested) : NULL;
3161 else
3162 return klass;
3166 mono_image_init_name_cache (image);
3167 mono_image_lock (image);
3169 nspace_table = (GHashTable *)g_hash_table_lookup (image->name_cache, name_space);
3171 if (nspace_table)
3172 token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
3174 mono_image_unlock (image);
3176 if (!token && image_is_dynamic (image) && image->modules) {
3177 /* Search modules as well */
3178 for (i = 0; i < image->module_count; ++i) {
3179 MonoImage *module = image->modules [i];
3181 klass = mono_class_from_name_checked (module, name_space, name, error);
3182 if (klass || !is_ok (error))
3183 return klass;
3187 if (!token) {
3188 klass = search_modules (image, name_space, name, error);
3189 if (klass || !is_ok (error))
3190 return klass;
3191 return NULL;
3194 if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
3195 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
3196 guint32 cols [MONO_EXP_TYPE_SIZE];
3197 guint32 idx, impl;
3199 idx = mono_metadata_token_index (token);
3201 mono_metadata_decode_row (t, idx - 1, cols, MONO_EXP_TYPE_SIZE);
3203 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
3204 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
3205 loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error);
3206 if (!loaded_image)
3207 return NULL;
3208 klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, error);
3209 if (nested)
3210 return klass ? return_nested_in (klass, nested) : NULL;
3211 return klass;
3212 } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
3213 guint32 assembly_idx;
3215 assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
3217 mono_assembly_load_reference (image, assembly_idx - 1);
3218 g_assert (image->references [assembly_idx - 1]);
3219 if (image->references [assembly_idx - 1] == (gpointer)-1)
3220 return NULL;
3221 klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, error);
3222 if (nested)
3223 return klass ? return_nested_in (klass, nested) : NULL;
3224 return klass;
3225 } else {
3226 g_assert_not_reached ();
3230 token = MONO_TOKEN_TYPE_DEF | token;
3232 klass = mono_class_get_checked (image, token, error);
3233 if (nested)
3234 return return_nested_in (klass, nested);
3235 return klass;
3239 * mono_class_from_name_checked:
3240 * \param image The MonoImage where the type is looked up in
3241 * \param name_space the type namespace
3242 * \param name the type short name.
3244 * Obtains a MonoClass with a given namespace and a given name which
3245 * is located in the given MonoImage.
3247 * Works like mono_class_from_name, but error handling is tricky. It can return NULL and have no error
3248 * set if the class was not found or it will return NULL and set the error if there was a loading error.
3250 MonoClass *
3251 mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
3253 MonoClass *klass;
3254 GHashTable *visited_images;
3256 visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
3258 klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, error);
3260 g_hash_table_destroy (visited_images);
3262 return klass;
3266 * mono_class_from_name:
3267 * \param image The \c MonoImage where the type is looked up in
3268 * \param name_space the type namespace
3269 * \param name the type short name.
3271 * Obtains a \c MonoClass with a given namespace and a given name which
3272 * is located in the given \c MonoImage.
3274 * To reference nested classes, use the "/" character as a separator.
3275 * For example use \c "Foo/Bar" to reference the class \c Bar that is nested
3276 * inside \c Foo, like this: "class Foo { class Bar {} }".
3278 MonoClass *
3279 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
3281 MonoClass *klass;
3282 MONO_ENTER_GC_UNSAFE;
3283 ERROR_DECL (error);
3285 klass = mono_class_from_name_checked (image, name_space, name, error);
3286 mono_error_cleanup (error); /* FIXME Don't swallow the error */
3287 MONO_EXIT_GC_UNSAFE;
3288 return klass;
3292 * mono_class_load_from_name:
3293 * \param image The MonoImage where the type is looked up in
3294 * \param name_space the type namespace
3295 * \param name the type short name.
3297 * This function works exactly like mono_class_from_name but it will abort if the class is not found.
3298 * This function should be used by the runtime for critical types to which there's no way to recover but crash
3299 * If they are missing. Thing of System.Object or System.String.
3301 MonoClass *
3302 mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
3304 ERROR_DECL (error);
3305 MonoClass *klass;
3307 klass = mono_class_from_name_checked (image, name_space, name, error);
3308 if (!klass)
3309 g_error ("Runtime critical type %s.%s not found", name_space, name);
3310 mono_error_assertf_ok (error, "Could not load runtime critical type %s.%s", name_space, name);
3311 return klass;
3315 * mono_class_try_load_from_name:
3316 * \param image The MonoImage where the type is looked up in
3317 * \param name_space the type namespace
3318 * \param name the type short name.
3320 * This function tries to load a type, returning the class was found or NULL otherwise.
3321 * This function should be used by the runtime when probing for optional types, those that could have being linked out.
3323 * Big design consideration. This function aborts if there was an error loading the type. This prevents us from missing
3324 * a type that we would otherwise assume to be available but was not due some error.
3327 MonoClass*
3328 mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name)
3330 ERROR_DECL (error);
3331 MonoClass *klass;
3333 klass = mono_class_from_name_checked (image, name_space, name, error);
3334 mono_error_assertf_ok (error, "Could not load runtime critical type %s.%s", name_space, name);
3335 return klass;
3338 static gboolean
3339 mono_interface_implements_interface (MonoClass *interface_implementer, MonoClass *interface_implemented)
3341 int i;
3342 ERROR_DECL (error);
3343 mono_class_setup_interfaces (interface_implementer, error);
3344 if (!is_ok (error)) {
3345 mono_error_cleanup (error);
3346 return FALSE;
3348 MonoClass **klass_interfaces = m_class_get_interfaces (interface_implementer);
3349 for (i = 0; i < m_class_get_interface_count (interface_implementer); i++) {
3350 MonoClass *ic = klass_interfaces [i];
3351 if (mono_class_is_ginst (ic))
3352 ic = mono_class_get_generic_type_definition (ic);
3353 if (ic == interface_implemented)
3354 return TRUE;
3356 return FALSE;
3359 gboolean
3360 mono_class_is_subclass_of_internal (MonoClass *klass, MonoClass *klassc,
3361 gboolean check_interfaces)
3363 MONO_REQ_GC_UNSAFE_MODE;
3364 /* FIXME test for interfaces with variant generic arguments */
3365 mono_class_init_internal (klass);
3366 mono_class_init_internal (klassc);
3368 if (check_interfaces && MONO_CLASS_IS_INTERFACE_INTERNAL (klassc) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
3369 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, m_class_get_interface_id (klassc)))
3370 return TRUE;
3371 } else if (check_interfaces && MONO_CLASS_IS_INTERFACE_INTERNAL (klassc) && MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
3372 int i;
3374 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
3375 for (i = 0; i < m_class_get_interface_count (klass); i ++) {
3376 MonoClass *ic = klass_interfaces [i];
3377 if (ic == klassc)
3378 return TRUE;
3380 } else {
3381 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) && mono_class_has_parent (klass, klassc))
3382 return TRUE;
3386 * MS.NET thinks interfaces are a subclass of Object, so we think it as
3387 * well.
3389 if (klassc == mono_defaults.object_class)
3390 return TRUE;
3392 return FALSE;
3395 static gboolean
3396 mono_type_is_generic_argument (MonoType *type)
3398 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
3401 gboolean
3402 mono_class_has_variant_generic_params (MonoClass *klass)
3404 int i;
3405 MonoGenericContainer *container;
3407 if (!mono_class_is_ginst (klass))
3408 return FALSE;
3410 container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
3412 for (i = 0; i < container->type_argc; ++i)
3413 if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
3414 return TRUE;
3416 return FALSE;
3419 static gboolean
3420 mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
3422 if (target == candidate)
3423 return TRUE;
3425 if (check_for_reference_conv &&
3426 mono_type_is_generic_argument (m_class_get_byval_arg (target)) &&
3427 mono_type_is_generic_argument (m_class_get_byval_arg (candidate))) {
3428 MonoGenericParam *gparam = m_class_get_byval_arg (candidate)->data.generic_param;
3429 MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
3431 if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
3432 return FALSE;
3434 if (!mono_class_is_assignable_from_internal (target, candidate))
3435 return FALSE;
3436 return TRUE;
3440 * @container the generic container from the GTD
3441 * @klass: the class to be assigned to
3442 * @oklass: the source class
3444 * Both @klass and @oklass must be instances of the same generic interface.
3446 * Returns: TRUE if @klass can be assigned to a @klass variable
3448 gboolean
3449 mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
3451 int j;
3452 MonoType **klass_argv, **oklass_argv;
3453 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
3454 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
3456 if (klass == oklass)
3457 return TRUE;
3459 /*Viable candidates are instances of the same generic interface*/
3460 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
3461 return FALSE;
3463 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
3464 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
3466 for (j = 0; j < container->type_argc; ++j) {
3467 MonoClass *param1_class = mono_class_from_mono_type_internal (klass_argv [j]);
3468 MonoClass *param2_class = mono_class_from_mono_type_internal (oklass_argv [j]);
3470 if (m_class_is_valuetype (param1_class) != m_class_is_valuetype (param2_class) || (m_class_is_valuetype (param1_class) && param1_class != param2_class))
3471 return FALSE;
3474 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
3475 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
3477 if (param1_class != param2_class) {
3478 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
3479 if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
3480 return FALSE;
3481 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
3482 if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
3483 return FALSE;
3484 } else
3485 return FALSE;
3488 return TRUE;
3491 static gboolean
3492 mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
3494 MonoGenericParam *gparam, *ogparam;
3495 MonoGenericParamInfo *tinfo, *cinfo;
3496 MonoClass **candidate_class;
3497 gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
3498 int tmask, cmask;
3500 if (target == candidate)
3501 return TRUE;
3502 MonoType *target_byval_arg = m_class_get_byval_arg (target);
3503 MonoType *candidate_byval_arg = m_class_get_byval_arg (candidate);
3504 if (target_byval_arg->type != candidate_byval_arg->type)
3505 return FALSE;
3507 gparam = target_byval_arg->data.generic_param;
3508 ogparam = candidate_byval_arg->data.generic_param;
3509 tinfo = mono_generic_param_info (gparam);
3510 cinfo = mono_generic_param_info (ogparam);
3512 class_constraint_satisfied = FALSE;
3513 valuetype_constraint_satisfied = FALSE;
3515 /*candidate must have a super set of target's special constraints*/
3516 tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
3517 cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
3519 if (cinfo->constraints) {
3520 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
3521 MonoClass *cc = *candidate_class;
3522 MonoType *cc_byval_arg = m_class_get_byval_arg (cc);
3524 if (mono_type_is_reference (cc_byval_arg) && !MONO_CLASS_IS_INTERFACE_INTERNAL (cc))
3525 class_constraint_satisfied = TRUE;
3526 else if (!mono_type_is_reference (cc_byval_arg) && !MONO_CLASS_IS_INTERFACE_INTERNAL (cc))
3527 valuetype_constraint_satisfied = TRUE;
3530 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
3531 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
3533 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
3534 return FALSE;
3535 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
3536 return FALSE;
3537 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
3538 valuetype_constraint_satisfied)) {
3539 return FALSE;
3543 /*candidate type constraints must be a superset of target's*/
3544 if (tinfo->constraints) {
3545 MonoClass **target_class;
3546 for (target_class = tinfo->constraints; *target_class; ++target_class) {
3547 MonoClass *tc = *target_class;
3548 MonoType *tc_byval_arg = m_class_get_byval_arg (tc);
3551 * A constraint from @target might inflate into @candidate itself and in that case we don't need
3552 * check it's constraints since it satisfy the constraint by itself.
3554 if (mono_metadata_type_equal (tc_byval_arg, candidate_byval_arg))
3555 continue;
3557 if (!cinfo->constraints)
3558 return FALSE;
3560 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
3561 MonoClass *cc = *candidate_class;
3563 if (mono_class_is_assignable_from_internal (tc, cc))
3564 break;
3567 * This happens when we have the following:
3569 * Bar<K> where K : IFace
3570 * Foo<T, U> where T : U where U : IFace
3571 * ...
3572 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
3575 if (mono_type_is_generic_argument (m_class_get_byval_arg (cc))) {
3576 if (mono_gparam_is_assignable_from (target, cc))
3577 break;
3580 if (!*candidate_class)
3581 return FALSE;
3585 /*candidate itself must have a constraint that satisfy target*/
3586 if (cinfo->constraints) {
3587 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
3588 MonoClass *cc = *candidate_class;
3589 if (mono_class_is_assignable_from_internal (target, cc))
3590 return TRUE;
3593 return FALSE;
3597 * mono_class_is_assignable_from_internal:
3598 * \param klass the class to be assigned to
3599 * \param oklass the source class
3601 * \returns TRUE if an instance of class \p oklass can be assigned to an
3602 * instance of class \p klass
3604 gboolean
3605 mono_class_is_assignable_from_internal (MonoClass *klass, MonoClass *oklass)
3607 gboolean result = FALSE;
3608 ERROR_DECL (error);
3609 mono_class_is_assignable_from_checked (klass, oklass, &result, error);
3610 mono_error_cleanup (error);
3611 return result;
3615 * mono_class_is_assignable_from:
3616 * \param klass the class to be assigned to
3617 * \param oklass the source class
3619 * \returns TRUE if an instance of class \p oklass can be assigned to an
3620 * instance of class \p klass
3622 mono_bool
3623 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
3625 gboolean result;
3626 MONO_ENTER_GC_UNSAFE;
3627 result = mono_class_is_assignable_from_internal (klass, oklass);
3628 MONO_EXIT_GC_UNSAFE;
3629 return result;
3633 * mono_class_is_assignable_from_checked:
3634 * \param klass the class to be assigned to
3635 * \param oklass the source class
3636 * \param result set if there was no error
3637 * \param error set if there was an error
3639 * Sets \p result to TRUE if an instance of class \p oklass can be assigned to
3640 * an instance of class \p klass or FALSE if it cannot. On error, no \p error
3641 * is set and \p result is not valid.
3643 void
3644 mono_class_is_assignable_from_checked (MonoClass *klass, MonoClass *oklass, gboolean *result, MonoError *error)
3646 g_assert (result);
3647 if (klass == oklass) {
3648 *result = TRUE;
3649 return;
3652 MONO_REQ_GC_UNSAFE_MODE;
3653 /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
3654 if (!m_class_is_inited (klass))
3655 mono_class_init_internal (klass);
3657 if (!m_class_is_inited (oklass))
3658 mono_class_init_internal (oklass);
3660 if (mono_class_has_failure (klass)) {
3661 mono_error_set_for_class_failure (error, klass);
3662 *result = FALSE;
3663 return;
3666 if (mono_class_has_failure (oklass)) {
3667 mono_error_set_for_class_failure (error, oklass);
3668 *result = FALSE;
3669 return;
3672 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
3673 MonoType *oklass_byval_arg = m_class_get_byval_arg (oklass);
3675 if (mono_type_is_generic_argument (klass_byval_arg)) {
3676 if (!mono_type_is_generic_argument (oklass_byval_arg)) {
3677 *result = FALSE;
3678 return;
3680 *result = mono_gparam_is_assignable_from (klass, oklass);
3681 return;
3684 /* This can happen if oklass is a tyvar that has a constraint which is another tyvar which in turn
3685 * has a constraint which is a class type:
3687 * class Foo { }
3688 * class G<T1, T2> where T1 : T2 where T2 : Foo { }
3690 * In this case, Foo is assignable from T1.
3692 if (mono_type_is_generic_argument (oklass_byval_arg)) {
3693 MonoGenericParam *gparam = oklass_byval_arg->data.generic_param;
3694 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
3695 int i;
3697 if (constraints) {
3698 for (i = 0; constraints [i]; ++i) {
3699 if (mono_class_is_assignable_from_internal (klass, constraints [i])) {
3700 *result = TRUE;
3701 return;
3706 *result = mono_class_has_parent (oklass, klass);
3707 return;
3710 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
3712 /* interface_offsets might not be set for dynamic classes */
3713 if (mono_class_get_ref_info_handle (oklass) && !m_class_get_interface_bitmap (oklass)) {
3715 * oklass might be a generic type parameter but they have
3716 * interface_offsets set.
3718 gboolean assign_result = mono_reflection_call_is_assignable_to (oklass, klass, error);
3719 return_if_nok (error);
3720 *result = assign_result;
3721 return;
3723 if (!m_class_get_interface_bitmap (oklass)) {
3724 /* Happens with generic instances of not-yet created dynamic types */
3725 *result = FALSE;
3726 return;
3728 if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, m_class_get_interface_id (klass))) {
3729 *result = TRUE;
3730 return;
3733 if (m_class_is_array_special_interface (klass) && m_class_get_rank (oklass) == 1) {
3734 if (mono_class_is_gtd (klass)) {
3735 /* klass is an array special gtd like
3736 * IList`1<>, and oklass is X[] for some X.
3737 * Moreover we know that X isn't !0 (the gparam
3738 * of IList`1) because in that case we would
3739 * have returned TRUE for
3740 * MONO_CLASS_IMPLEMENTS_INTERFACE, above.
3742 *result = FALSE;
3743 return;
3745 // FIXME: IEnumerator`1 should not be an array special interface.
3746 // The correct fix is to make
3747 // ((IEnumerable<U>) (new T[] {...})).GetEnumerator()
3748 // return an IEnumerator<U> (like .NET does) instead of IEnumerator<T>
3749 // and to stop marking IEnumerable`1 as an array_special_interface.
3750 if (mono_class_get_generic_type_definition (klass) == mono_defaults.generic_ienumerator_class) {
3751 *result = FALSE;
3752 return;
3755 //XXX we could offset this by having the cast target computed at JIT time
3756 //XXX we could go even further and emit a wrapper that would do the extra type check
3757 MonoClass *iface_klass = mono_class_from_mono_type_internal (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
3758 MonoClass *obj_klass = m_class_get_cast_class (oklass); //This gets us the cast class of element type of the array
3760 // If the target we're trying to cast to is a valuetype, we must account of weird valuetype equivalences such as IntEnum <> int or uint <> int
3761 // We can't apply it for ref types as this would go wrong with arrays - IList<byte[]> would have byte tested
3762 if (!mono_class_is_nullable (iface_klass)) {
3763 if (m_class_is_valuetype (iface_klass))
3764 iface_klass = m_class_get_cast_class (iface_klass);
3766 //array covariant casts only operates on scalar to scalar
3767 //This is so int[] can't be casted to IComparable<int>[]
3768 if (!(m_class_is_valuetype (obj_klass) && !m_class_is_valuetype (iface_klass)) && mono_class_is_assignable_from_internal (iface_klass, obj_klass)) {
3769 *result = TRUE;
3770 return;
3775 if (mono_class_has_variant_generic_params (klass)) {
3776 int i;
3777 mono_class_setup_interfaces (oklass, error);
3778 return_if_nok (error);
3780 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
3781 for (i = 0; i < m_class_get_interface_offsets_count (oklass); ++i) {
3782 MonoClass *iface = m_class_get_interfaces_packed (oklass) [i];
3784 if (mono_class_is_variant_compatible (klass, iface, FALSE)) {
3785 *result = TRUE;
3786 return;
3791 *result = FALSE;
3792 return;
3793 } else if (m_class_is_delegate (klass)) {
3794 if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE)) {
3795 *result = TRUE;
3796 return;
3798 } else if (m_class_get_rank (klass)) {
3799 MonoClass *eclass, *eoclass;
3801 if (m_class_get_rank (oklass) != m_class_get_rank (klass)) {
3802 *result = FALSE;
3803 return;
3806 /* vectors vs. one dimensional arrays */
3807 if (oklass_byval_arg->type != klass_byval_arg->type) {
3808 *result = FALSE;
3809 return;
3812 eclass = m_class_get_cast_class (klass);
3813 eoclass = m_class_get_cast_class (oklass);
3816 * a is b does not imply a[] is b[] when a is a valuetype, and
3817 * b is a reference type.
3820 if (m_class_is_valuetype (eoclass)) {
3821 if ((eclass == mono_defaults.enum_class) ||
3822 (eclass == m_class_get_parent (mono_defaults.enum_class)) ||
3823 (!m_class_is_valuetype (eclass))) {
3824 *result = FALSE;
3825 return;
3830 * a is b does not imply a[] is b[] in the case where b is an interface and
3831 * a is a generic parameter, unless a has an additional class constraint.
3832 * For example (C#):
3833 * ```
3834 * interface I {}
3835 * class G<T> where T : I {}
3836 * class H<U> where U : class, I {}
3837 * public class P {
3838 * public static void Main() {
3839 * var t = typeof(G<>).GetTypeInfo().GenericTypeParameters[0].MakeArrayType();
3840 * var i = typeof(I).MakeArrayType();
3841 * var u = typeof(H<>).GetTypeInfo().GenericTypeParameters[0].MakeArrayType();
3842 * Console.WriteLine("I[] assignable from T[] ? {0}", i.IsAssignableFrom(t));
3843 * Console.WriteLine("I[] assignable from U[] ? {0}", i.IsAssignableFrom(u));
3846 * ```
3847 * This should print:
3848 * I[] assignable from T[] ? False
3849 * I[] assignable from U[] ? True
3852 if (MONO_CLASS_IS_INTERFACE_INTERNAL (eclass)) {
3853 MonoType *eoclass_byval_arg = m_class_get_byval_arg (eoclass);
3854 if (mono_type_is_generic_argument (eoclass_byval_arg)) {
3855 MonoGenericParam *eoparam = eoclass_byval_arg->data.generic_param;
3856 MonoGenericParamInfo *eoinfo = mono_generic_param_info (eoparam);
3857 int eomask = eoinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
3858 // check for class constraint
3859 if ((eomask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0) {
3860 *result = FALSE;
3861 return;
3866 if (mono_class_is_nullable (eclass) ^ mono_class_is_nullable (eoclass)) {
3867 *result = FALSE;
3868 return;
3871 mono_class_is_assignable_from_checked (eclass, eoclass, result, error);
3872 return;
3873 } else if (mono_class_is_nullable (klass)) {
3874 if (mono_class_is_nullable (oklass))
3875 mono_class_is_assignable_from_checked (m_class_get_cast_class (klass), m_class_get_cast_class (oklass), result, error);
3876 else
3877 mono_class_is_assignable_from_checked (m_class_get_cast_class (klass), oklass, result, error);
3878 return;
3879 } else if (klass == mono_defaults.object_class) {
3880 if (m_class_get_class_kind (oklass) == MONO_CLASS_POINTER)
3881 *result = FALSE;
3882 else
3883 *result = TRUE;
3884 return;
3887 *result = mono_class_has_parent (oklass, klass);
3890 /*Check if @oklass is variant compatible with @klass.*/
3891 static gboolean
3892 mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
3894 int j;
3895 MonoType **klass_argv, **oklass_argv;
3896 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
3897 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
3899 /*Viable candidates are instances of the same generic interface*/
3900 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
3901 return FALSE;
3903 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
3904 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
3906 for (j = 0; j < container->type_argc; ++j) {
3907 MonoClass *param1_class = mono_class_from_mono_type_internal (klass_argv [j]);
3908 MonoClass *param2_class = mono_class_from_mono_type_internal (oklass_argv [j]);
3910 if (m_class_is_valuetype (param1_class) != m_class_is_valuetype (param2_class))
3911 return FALSE;
3914 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
3915 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
3917 if (param1_class != param2_class) {
3918 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
3919 if (!mono_class_is_assignable_from_slow (param1_class, param2_class))
3920 return FALSE;
3921 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
3922 if (!mono_class_is_assignable_from_slow (param2_class, param1_class))
3923 return FALSE;
3924 } else
3925 return FALSE;
3928 return TRUE;
3930 /*Check if @candidate implements the interface @target*/
3931 static gboolean
3932 mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
3934 ERROR_DECL (error);
3935 int i;
3936 gboolean is_variant = mono_class_has_variant_generic_params (target);
3938 if (is_variant && MONO_CLASS_IS_INTERFACE_INTERNAL (candidate)) {
3939 if (mono_class_is_variant_compatible_slow (target, candidate))
3940 return TRUE;
3943 do {
3944 if (candidate == target)
3945 return TRUE;
3947 /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
3948 if (image_is_dynamic (m_class_get_image (candidate)) && !m_class_was_typebuilder (candidate)) {
3949 MonoReflectionTypeBuilder *tb = mono_class_get_ref_info_raw (candidate); /* FIXME use handles */
3950 int j;
3951 if (tb && tb->interfaces) {
3952 for (j = mono_array_length_internal (tb->interfaces) - 1; j >= 0; --j) {
3953 MonoReflectionType *iface = mono_array_get_internal (tb->interfaces, MonoReflectionType*, j);
3954 MonoClass *iface_class;
3956 /* we can't realize the type here since it can do pretty much anything. */
3957 if (!iface->type)
3958 continue;
3959 iface_class = mono_class_from_mono_type_internal (iface->type);
3960 if (iface_class == target)
3961 return TRUE;
3962 if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class))
3963 return TRUE;
3964 if (mono_class_implement_interface_slow (target, iface_class))
3965 return TRUE;
3968 } else {
3969 /*setup_interfaces don't mono_class_init_internal anything*/
3970 /*FIXME this doesn't handle primitive type arrays.
3971 ICollection<sbyte> x byte [] won't work because candidate->interfaces, for byte[], won't have IList<sbyte>.
3972 A possible way to fix this would be to move that to setup_interfaces from setup_interface_offsets.
3974 mono_class_setup_interfaces (candidate, error);
3975 if (!mono_error_ok (error)) {
3976 mono_error_cleanup (error);
3977 return FALSE;
3980 int candidate_interface_count = m_class_get_interface_count (candidate);
3981 MonoClass **candidate_interfaces = m_class_get_interfaces (candidate);
3982 for (i = 0; i < candidate_interface_count; ++i) {
3983 if (candidate_interfaces [i] == target)
3984 return TRUE;
3986 if (is_variant && mono_class_is_variant_compatible_slow (target, candidate_interfaces [i]))
3987 return TRUE;
3989 if (mono_class_implement_interface_slow (target, candidate_interfaces [i]))
3990 return TRUE;
3993 candidate = m_class_get_parent (candidate);
3994 } while (candidate);
3996 return FALSE;
4000 * Check if @oklass can be assigned to @klass.
4001 * This function does the same as mono_class_is_assignable_from_internal but is safe to be used from mono_class_init_internal context.
4003 gboolean
4004 mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
4006 if (candidate == target)
4007 return TRUE;
4008 if (target == mono_defaults.object_class)
4009 return TRUE;
4011 if (mono_class_has_parent (candidate, target))
4012 return TRUE;
4014 /*If target is not an interface there is no need to check them.*/
4015 if (MONO_CLASS_IS_INTERFACE_INTERNAL (target))
4016 return mono_class_implement_interface_slow (target, candidate);
4018 if (m_class_is_delegate (target) && mono_class_has_variant_generic_params (target))
4019 return mono_class_is_variant_compatible (target, candidate, FALSE);
4021 if (m_class_get_rank (target)) {
4022 MonoClass *eclass, *eoclass;
4024 if (m_class_get_rank (target) != m_class_get_rank (candidate))
4025 return FALSE;
4027 /* vectors vs. one dimensional arrays */
4028 if (m_class_get_byval_arg (target)->type != m_class_get_byval_arg (candidate)->type)
4029 return FALSE;
4031 eclass = m_class_get_cast_class (target);
4032 eoclass = m_class_get_cast_class (candidate);
4035 * a is b does not imply a[] is b[] when a is a valuetype, and
4036 * b is a reference type.
4039 if (m_class_is_valuetype (eoclass)) {
4040 if ((eclass == mono_defaults.enum_class) ||
4041 (eclass == m_class_get_parent (mono_defaults.enum_class)) ||
4042 (eclass == mono_defaults.object_class))
4043 return FALSE;
4046 return mono_class_is_assignable_from_slow (eclass, eoclass);
4048 /*FIXME properly handle nullables */
4049 /*FIXME properly handle (M)VAR */
4050 return FALSE;
4054 * mono_generic_param_get_base_type:
4056 * Return the base type of the given generic parameter from its constraints.
4058 * Could be another generic parameter, or it could be Object or ValueType.
4060 MonoClass*
4061 mono_generic_param_get_base_type (MonoClass *klass)
4063 MonoType *type = m_class_get_byval_arg (klass);
4064 g_assert (mono_type_is_generic_argument (type));
4066 MonoGenericParam *gparam = type->data.generic_param;
4068 g_assert (gparam->owner && !gparam->owner->is_anonymous);
4070 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
4072 MonoClass *base_class = mono_defaults.object_class;
4074 if (constraints) {
4075 int i;
4076 for (i = 0; constraints [i]; ++i) {
4077 MonoClass *constraint = constraints[i];
4079 if (MONO_CLASS_IS_INTERFACE_INTERNAL (constraint))
4080 continue;
4082 MonoType *constraint_type = m_class_get_byval_arg (constraint);
4083 if (mono_type_is_generic_argument (constraint_type)) {
4084 MonoGenericParam *constraint_param = constraint_type->data.generic_param;
4085 MonoGenericParamInfo *constraint_info = mono_generic_param_info (constraint_param);
4086 if ((constraint_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0 &&
4087 (constraint_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) == 0)
4088 continue;
4091 base_class = constraint;
4096 if (base_class == mono_defaults.object_class)
4098 MonoGenericParamInfo *gparam_info = mono_generic_param_info (gparam);
4099 if ((gparam_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0) {
4100 base_class = mono_class_get_valuetype_class ();
4104 return base_class;
4108 * mono_class_get_cctor:
4109 * \param klass A MonoClass pointer
4111 * \returns The static constructor of \p klass if it exists, NULL otherwise.
4113 MonoMethod*
4114 mono_class_get_cctor (MonoClass *klass)
4116 MonoMethod *result = NULL;
4117 ERROR_DECL (error);
4118 MonoCachedClassInfo cached_info;
4120 if (image_is_dynamic (m_class_get_image (klass))) {
4122 * has_cctor is not set for these classes because mono_class_init_internal () is
4123 * not run for them.
4125 result = mono_class_get_method_from_name_checked (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME, error);
4126 mono_error_assert_msg_ok (error, "Could not lookup class cctor in dynamic image");
4127 return result;
4130 mono_class_init_internal (klass);
4132 if (!m_class_has_cctor (klass))
4133 return result;
4135 if (mono_class_is_ginst (klass) && !m_class_get_methods (klass)) {
4136 result = mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class), error);
4137 mono_error_assert_msg_ok (error, "Could not lookup inflated class cctor"); /* FIXME do proper error handling */
4138 return result;
4141 if (mono_class_get_cached_class_info (klass, &cached_info)) {
4142 result = mono_get_method_checked (m_class_get_image (klass), cached_info.cctor_token, klass, NULL, error);
4143 mono_error_assert_msg_ok (error, "Could not lookup class cctor from cached metadata");
4144 return result;
4147 result = mono_class_get_method_from_name_checked (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME, error);
4148 mono_error_assert_msg_ok (error, "Could not lookup class cctor");
4149 return result;
4153 * mono_class_get_finalizer:
4154 * \param klass: The MonoClass pointer
4156 * \returns The finalizer method of \p klass if it exists, NULL otherwise.
4158 MonoMethod*
4159 mono_class_get_finalizer (MonoClass *klass)
4161 MonoCachedClassInfo cached_info;
4163 if (!m_class_is_inited (klass))
4164 mono_class_init_internal (klass);
4165 if (!mono_class_has_finalizer (klass))
4166 return NULL;
4168 if (mono_class_get_cached_class_info (klass, &cached_info)) {
4169 ERROR_DECL (error);
4170 MonoMethod *result = mono_get_method_checked (cached_info.finalize_image, cached_info.finalize_token, NULL, NULL, error);
4171 mono_error_assert_msg_ok (error, "Could not lookup finalizer from cached metadata");
4172 return result;
4173 }else {
4174 mono_class_setup_vtable (klass);
4175 return m_class_get_vtable (klass) [mono_class_get_object_finalize_slot ()];
4180 * mono_class_needs_cctor_run:
4181 * \param klass the MonoClass pointer
4182 * \param caller a MonoMethod describing the caller
4184 * Determines whenever the class has a static constructor and whenever it
4185 * needs to be called when executing CALLER.
4187 gboolean
4188 mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
4190 MonoMethod *method;
4192 method = mono_class_get_cctor (klass);
4193 if (method)
4194 return (method == caller) ? FALSE : TRUE;
4195 else
4196 return FALSE;
4200 * mono_class_array_element_size:
4201 * \param klass
4203 * \returns The number of bytes an element of type \p klass uses when stored into an array.
4205 gint32
4206 mono_class_array_element_size (MonoClass *klass)
4208 MonoType *type = m_class_get_byval_arg (klass);
4210 handle_enum:
4211 switch (type->type) {
4212 case MONO_TYPE_I1:
4213 case MONO_TYPE_U1:
4214 case MONO_TYPE_BOOLEAN:
4215 return 1;
4216 case MONO_TYPE_I2:
4217 case MONO_TYPE_U2:
4218 case MONO_TYPE_CHAR:
4219 return 2;
4220 case MONO_TYPE_I4:
4221 case MONO_TYPE_U4:
4222 case MONO_TYPE_R4:
4223 return 4;
4224 case MONO_TYPE_I:
4225 case MONO_TYPE_U:
4226 case MONO_TYPE_PTR:
4227 case MONO_TYPE_CLASS:
4228 case MONO_TYPE_STRING:
4229 case MONO_TYPE_OBJECT:
4230 case MONO_TYPE_SZARRAY:
4231 case MONO_TYPE_ARRAY:
4232 return TARGET_SIZEOF_VOID_P;
4233 case MONO_TYPE_I8:
4234 case MONO_TYPE_U8:
4235 case MONO_TYPE_R8:
4236 return 8;
4237 case MONO_TYPE_VALUETYPE:
4238 if (m_class_is_enumtype (type->data.klass)) {
4239 type = mono_class_enum_basetype_internal (type->data.klass);
4240 klass = m_class_get_element_class (klass);
4241 goto handle_enum;
4243 return mono_class_value_size (klass, NULL);
4244 case MONO_TYPE_GENERICINST:
4245 type = m_class_get_byval_arg (type->data.generic_class->container_class);
4246 goto handle_enum;
4247 case MONO_TYPE_VAR:
4248 case MONO_TYPE_MVAR: {
4249 int align;
4251 return mono_type_size (type, &align);
4253 case MONO_TYPE_VOID:
4254 return 0;
4256 default:
4257 g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
4259 return -1;
4263 * mono_array_element_size:
4264 * \param ac pointer to a \c MonoArrayClass
4266 * \returns The size of single array element.
4268 * LOCKING: Acquires the loader lock.
4270 gint32
4271 mono_array_element_size (MonoClass *ac)
4273 g_assert (m_class_get_rank (ac));
4274 if (G_UNLIKELY (!m_class_is_size_inited (ac))) {
4275 mono_class_setup_fields (ac);
4277 return m_class_get_sizes (ac).element_size;
4281 * mono_ldtoken:
4283 gpointer
4284 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
4285 MonoGenericContext *context)
4287 ERROR_DECL (error);
4288 gpointer res = mono_ldtoken_checked (image, token, handle_class, context, error);
4289 mono_error_assert_ok (error);
4290 return res;
4293 gpointer
4294 mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
4295 MonoGenericContext *context, MonoError *error)
4297 error_init (error);
4299 if (image_is_dynamic (image)) {
4300 MonoClass *tmp_handle_class;
4301 gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
4303 mono_error_assert_ok (error);
4304 g_assert (tmp_handle_class);
4305 if (handle_class)
4306 *handle_class = tmp_handle_class;
4308 if (tmp_handle_class == mono_defaults.typehandle_class)
4309 return m_class_get_byval_arg ((MonoClass*)obj);
4310 else
4311 return obj;
4314 switch (token & 0xff000000) {
4315 case MONO_TOKEN_TYPE_DEF:
4316 case MONO_TOKEN_TYPE_REF:
4317 case MONO_TOKEN_TYPE_SPEC: {
4318 MonoType *type;
4319 if (handle_class)
4320 *handle_class = mono_defaults.typehandle_class;
4321 type = mono_type_get_checked (image, token, context, error);
4322 if (!type)
4323 return NULL;
4325 mono_class_init_internal (mono_class_from_mono_type_internal (type));
4326 /* We return a MonoType* as handle */
4327 return type;
4329 case MONO_TOKEN_FIELD_DEF: {
4330 MonoClass *klass;
4331 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
4332 if (!type) {
4333 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
4334 return NULL;
4336 if (handle_class)
4337 *handle_class = mono_defaults.fieldhandle_class;
4338 klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_DEF | type, context, error);
4339 if (!klass)
4340 return NULL;
4342 mono_class_init_internal (klass);
4343 return mono_class_get_field (klass, token);
4345 case MONO_TOKEN_METHOD_DEF:
4346 case MONO_TOKEN_METHOD_SPEC: {
4347 MonoMethod *meth;
4348 meth = mono_get_method_checked (image, token, NULL, context, error);
4349 if (handle_class)
4350 *handle_class = mono_defaults.methodhandle_class;
4351 if (!meth)
4352 return NULL;
4354 return meth;
4356 case MONO_TOKEN_MEMBER_REF: {
4357 guint32 cols [MONO_MEMBERREF_SIZE];
4358 const char *sig;
4359 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE);
4360 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
4361 mono_metadata_decode_blob_size (sig, &sig);
4362 if (*sig == 0x6) { /* it's a field */
4363 MonoClass *klass;
4364 MonoClassField *field;
4365 field = mono_field_from_token_checked (image, token, &klass, context, error);
4366 if (handle_class)
4367 *handle_class = mono_defaults.fieldhandle_class;
4368 return field;
4369 } else {
4370 MonoMethod *meth;
4371 meth = mono_get_method_checked (image, token, NULL, context, error);
4372 if (handle_class)
4373 *handle_class = mono_defaults.methodhandle_class;
4374 return meth;
4377 default:
4378 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
4380 return NULL;
4383 gpointer
4384 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
4386 MonoClass *handle_class;
4387 error_init (error);
4388 return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
4391 gpointer
4392 mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
4394 return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
4397 static MonoGetCachedClassInfo get_cached_class_info = NULL;
4399 void
4400 mono_install_get_cached_class_info (MonoGetCachedClassInfo func)
4402 get_cached_class_info = func;
4405 gboolean
4406 mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
4408 if (!get_cached_class_info)
4409 return FALSE;
4410 else
4411 return get_cached_class_info (klass, res);
4414 void
4415 mono_install_get_class_from_name (MonoGetClassFromName func)
4417 get_class_from_name = func;
4421 * mono_class_get_image:
4423 * Use this method to get the \c MonoImage* where this class came from.
4425 * \returns The image where this class is defined.
4427 MonoImage*
4428 mono_class_get_image (MonoClass *klass)
4430 return m_class_get_image (klass);
4434 * mono_class_get_element_class:
4435 * \param klass the \c MonoClass to act on
4437 * Use this function to get the element class of an array.
4439 * \returns The element class of an array.
4441 MonoClass*
4442 mono_class_get_element_class (MonoClass *klass)
4444 MonoClass *result;
4445 MONO_ENTER_GC_UNSAFE;
4446 result = m_class_get_element_class (klass);
4447 MONO_EXIT_GC_UNSAFE;
4448 return result;
4452 * mono_class_is_valuetype:
4453 * \param klass the \c MonoClass to act on
4455 * Use this method to determine if the provided \c MonoClass* represents a value type,
4456 * or a reference type.
4458 * \returns TRUE if the \c MonoClass represents a \c ValueType, FALSE if it represents a reference type.
4460 gboolean
4461 mono_class_is_valuetype (MonoClass *klass)
4463 gboolean result;
4464 MONO_ENTER_GC_UNSAFE;
4465 result = m_class_is_valuetype (klass);
4466 MONO_EXIT_GC_UNSAFE;
4467 return result;
4471 * mono_class_is_enum:
4472 * \param klass the \c MonoClass to act on
4474 * Use this function to determine if the provided \c MonoClass* represents an enumeration.
4476 * \returns TRUE if the \c MonoClass represents an enumeration.
4478 gboolean
4479 mono_class_is_enum (MonoClass *klass)
4481 gboolean result;
4482 MONO_ENTER_GC_UNSAFE;
4483 result = m_class_is_enumtype (klass);
4484 MONO_EXIT_GC_UNSAFE;
4485 return result;
4489 * mono_class_enum_basetype_internal:
4490 * \param klass the \c MonoClass to act on
4492 * Use this function to get the underlying type for an enumeration value.
4494 * \returns The underlying type representation for an enumeration.
4496 MonoType*
4497 mono_class_enum_basetype_internal (MonoClass *klass)
4499 if (m_class_get_element_class (klass) == klass)
4500 /* SRE or broken types */
4501 return NULL;
4502 return m_class_get_byval_arg (m_class_get_element_class (klass));
4506 * mono_class_enum_basetype:
4507 * \param klass the \c MonoClass to act on
4509 * Use this function to get the underlying type for an enumeration value.
4511 * \returns The underlying type representation for an enumeration.
4513 MonoType*
4514 mono_class_enum_basetype (MonoClass *klass)
4516 MonoType *res;
4517 MONO_ENTER_GC_UNSAFE;
4518 res = mono_class_enum_basetype_internal (klass);
4519 MONO_EXIT_GC_UNSAFE;
4520 return res;
4524 * mono_class_get_parent
4525 * \param klass the \c MonoClass to act on
4527 * \returns The parent class for this class.
4529 MonoClass*
4530 mono_class_get_parent (MonoClass *klass)
4532 MonoClass *result;
4533 MONO_ENTER_GC_UNSAFE;
4534 result = m_class_get_parent (klass);
4535 MONO_EXIT_GC_UNSAFE;
4536 return result;
4540 * mono_class_get_nesting_type:
4541 * \param klass the \c MonoClass to act on
4543 * Use this function to obtain the class that the provided \c MonoClass* is nested on.
4545 * If the return is NULL, this indicates that this class is not nested.
4547 * \returns The container type where this type is nested or NULL if this type is not a nested type.
4549 MonoClass*
4550 mono_class_get_nesting_type (MonoClass *klass)
4552 return m_class_get_nested_in (klass);
4556 * mono_class_get_rank:
4557 * \param klass the MonoClass to act on
4559 * \returns The rank for the array (the number of dimensions).
4562 mono_class_get_rank (MonoClass *klass)
4564 return m_class_get_rank (klass);
4568 * mono_class_get_name
4569 * \param klass the \c MonoClass to act on
4571 * \returns The name of the class.
4573 const char*
4574 mono_class_get_name (MonoClass *klass)
4576 const char *result;
4577 MONO_ENTER_GC_UNSAFE;
4578 result = m_class_get_name (klass);
4579 MONO_EXIT_GC_UNSAFE;
4580 return result;
4584 * mono_class_get_namespace:
4585 * \param klass the \c MonoClass to act on
4587 * \returns The namespace of the class.
4589 const char*
4590 mono_class_get_namespace (MonoClass *klass)
4592 const char *result;
4593 MONO_ENTER_GC_UNSAFE;
4594 result = m_class_get_name_space (klass);
4595 MONO_EXIT_GC_UNSAFE;
4596 return result;
4600 * mono_class_get_type:
4601 * \param klass the \c MonoClass to act on
4603 * This method returns the internal \c MonoType representation for the class.
4605 * \returns The \c MonoType from the class.
4607 MonoType*
4608 mono_class_get_type (MonoClass *klass)
4610 return m_class_get_byval_arg (klass);
4614 * mono_class_get_type_token:
4615 * \param klass the \c MonoClass to act on
4617 * This method returns type token for the class.
4619 * \returns The type token for the class.
4621 guint32
4622 mono_class_get_type_token (MonoClass *klass)
4624 return m_class_get_type_token (klass);
4628 * mono_class_get_byref_type:
4629 * \param klass the \c MonoClass to act on
4633 MonoType*
4634 mono_class_get_byref_type (MonoClass *klass)
4636 return m_class_get_this_arg (klass);
4640 * mono_class_num_fields:
4641 * \param klass the \c MonoClass to act on
4643 * \returns The number of static and instance fields in the class.
4646 mono_class_num_fields (MonoClass *klass)
4648 return mono_class_get_field_count (klass);
4652 * mono_class_num_methods:
4653 * \param klass the \c MonoClass to act on
4655 * \returns The number of methods in the class.
4658 mono_class_num_methods (MonoClass *klass)
4660 return mono_class_get_method_count (klass);
4664 * mono_class_num_properties
4665 * \param klass the \c MonoClass to act on
4667 * \returns The number of properties in the class.
4670 mono_class_num_properties (MonoClass *klass)
4672 mono_class_setup_properties (klass);
4674 return mono_class_get_property_info (klass)->count;
4678 * mono_class_num_events:
4679 * \param klass the \c MonoClass to act on
4681 * \returns The number of events in the class.
4684 mono_class_num_events (MonoClass *klass)
4686 mono_class_setup_events (klass);
4688 return mono_class_get_event_info (klass)->count;
4692 * mono_class_get_fields:
4693 * \param klass the \c MonoClass to act on
4695 * This routine is an iterator routine for retrieving the fields in a class.
4697 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4698 * iterate over all of the elements. When no more values are
4699 * available, the return value is NULL.
4701 * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
4703 MonoClassField*
4704 mono_class_get_fields (MonoClass* klass, gpointer *iter)
4706 MonoClassField *result;
4707 MONO_ENTER_GC_UNSAFE;
4708 result = mono_class_get_fields_internal (klass, iter);
4709 MONO_EXIT_GC_UNSAFE;
4710 return result;
4713 MonoClassField*
4714 mono_class_get_fields_internal (MonoClass *klass, gpointer *iter)
4716 MonoClassField* field;
4717 if (!iter)
4718 return NULL;
4719 if (!*iter) {
4720 mono_class_setup_fields (klass);
4721 if (mono_class_has_failure (klass))
4722 return NULL;
4723 /* start from the first */
4724 if (mono_class_get_field_count (klass)) {
4725 MonoClassField *klass_fields = m_class_get_fields (klass);
4726 *iter = &klass_fields [0];
4727 return &klass_fields [0];
4728 } else {
4729 /* no fields */
4730 return NULL;
4733 field = (MonoClassField *)*iter;
4734 field++;
4735 if (field < &m_class_get_fields (klass) [mono_class_get_field_count (klass)]) {
4736 *iter = field;
4737 return field;
4739 return NULL;
4743 * mono_class_get_methods:
4744 * \param klass the \c MonoClass to act on
4746 * This routine is an iterator routine for retrieving the fields in a class.
4748 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4749 * iterate over all of the elements. When no more values are
4750 * available, the return value is NULL.
4752 * \returns a \c MonoMethod on each iteration or NULL when no more methods are available.
4754 MonoMethod*
4755 mono_class_get_methods (MonoClass* klass, gpointer *iter)
4757 MonoMethod** method;
4758 if (!iter)
4759 return NULL;
4760 if (!*iter) {
4761 mono_class_setup_methods (klass);
4763 MonoMethod **klass_methods = m_class_get_methods (klass);
4765 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
4766 * FIXME we should better report this error to the caller
4768 if (!klass_methods)
4769 return NULL;
4770 /* start from the first */
4771 if (mono_class_get_method_count (klass)) {
4772 *iter = &klass_methods [0];
4773 return klass_methods [0];
4774 } else {
4775 /* no method */
4776 return NULL;
4779 method = (MonoMethod **)*iter;
4780 method++;
4781 if (method < &m_class_get_methods (klass) [mono_class_get_method_count (klass)]) {
4782 *iter = method;
4783 return *method;
4785 return NULL;
4789 * mono_class_get_properties:
4790 * \param klass the \c MonoClass to act on
4792 * This routine is an iterator routine for retrieving the properties in a class.
4794 * You must pass a gpointer that points to zero and is treated as an opaque handle to
4795 * iterate over all of the elements. When no more values are
4796 * available, the return value is NULL.
4798 * Returns: a \c MonoProperty* on each invocation, or NULL when no more are available.
4800 MonoProperty*
4801 mono_class_get_properties (MonoClass* klass, gpointer *iter)
4803 MonoProperty* property;
4804 if (!iter)
4805 return NULL;
4806 if (!*iter) {
4807 mono_class_setup_properties (klass);
4808 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
4809 /* start from the first */
4810 if (info->count) {
4811 *iter = &info->properties [0];
4812 return (MonoProperty *)*iter;
4813 } else {
4814 /* no fields */
4815 return NULL;
4818 property = (MonoProperty *)*iter;
4819 property++;
4820 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
4821 if (property < &info->properties [info->count]) {
4822 *iter = property;
4823 return (MonoProperty *)*iter;
4825 return NULL;
4829 * mono_class_get_events:
4830 * \param klass the \c MonoClass to act on
4832 * This routine is an iterator routine for retrieving the properties in a class.
4834 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4835 * iterate over all of the elements. When no more values are
4836 * available, the return value is NULL.
4838 * \returns a \c MonoEvent* on each invocation, or NULL when no more are available.
4840 MonoEvent*
4841 mono_class_get_events (MonoClass* klass, gpointer *iter)
4843 MonoEvent* event;
4844 if (!iter)
4845 return NULL;
4846 if (!*iter) {
4847 mono_class_setup_events (klass);
4848 MonoClassEventInfo *info = mono_class_get_event_info (klass);
4849 /* start from the first */
4850 if (info->count) {
4851 *iter = &info->events [0];
4852 return (MonoEvent *)*iter;
4853 } else {
4854 /* no fields */
4855 return NULL;
4858 event = (MonoEvent *)*iter;
4859 event++;
4860 MonoClassEventInfo *info = mono_class_get_event_info (klass);
4861 if (event < &info->events [info->count]) {
4862 *iter = event;
4863 return (MonoEvent *)*iter;
4865 return NULL;
4869 * mono_class_get_interfaces
4870 * \param klass the \c MonoClass to act on
4872 * This routine is an iterator routine for retrieving the interfaces implemented by this class.
4874 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4875 * iterate over all of the elements. When no more values are
4876 * available, the return value is NULL.
4878 * \returns a \c MonoClass* on each invocation, or NULL when no more are available.
4880 MonoClass*
4881 mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
4883 ERROR_DECL (error);
4884 MonoClass** iface;
4885 if (!iter)
4886 return NULL;
4887 if (!*iter) {
4888 if (!m_class_is_inited (klass))
4889 mono_class_init_internal (klass);
4890 if (!m_class_is_interfaces_inited (klass)) {
4891 mono_class_setup_interfaces (klass, error);
4892 if (!mono_error_ok (error)) {
4893 mono_error_cleanup (error);
4894 return NULL;
4897 /* start from the first */
4898 if (m_class_get_interface_count (klass)) {
4899 *iter = &m_class_get_interfaces (klass) [0];
4900 return m_class_get_interfaces (klass) [0];
4901 } else {
4902 /* no interface */
4903 return NULL;
4906 iface = (MonoClass **)*iter;
4907 iface++;
4908 if (iface < &m_class_get_interfaces (klass) [m_class_get_interface_count (klass)]) {
4909 *iter = iface;
4910 return *iface;
4912 return NULL;
4916 * mono_class_get_nested_types
4917 * \param klass the \c MonoClass to act on
4919 * This routine is an iterator routine for retrieving the nested types of a class.
4920 * This works only if \p klass is non-generic, or a generic type definition.
4922 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4923 * iterate over all of the elements. When no more values are
4924 * available, the return value is NULL.
4926 * \returns a \c Monoclass* on each invocation, or NULL when no more are available.
4928 MonoClass*
4929 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
4931 GList *item;
4933 if (!iter)
4934 return NULL;
4935 if (!m_class_is_nested_classes_inited (klass))
4936 mono_class_setup_nested_types (klass);
4938 if (!*iter) {
4939 GList *nested_classes = mono_class_get_nested_classes_property (klass);
4940 /* start from the first */
4941 if (nested_classes) {
4942 *iter = nested_classes;
4943 return (MonoClass *)nested_classes->data;
4944 } else {
4945 /* no nested types */
4946 return NULL;
4949 item = (GList *)*iter;
4950 item = item->next;
4951 if (item) {
4952 *iter = item;
4953 return (MonoClass *)item->data;
4955 return NULL;
4960 * mono_class_is_delegate
4961 * \param klass the \c MonoClass to act on
4963 * \returns TRUE if the \c MonoClass represents a \c System.Delegate.
4965 mono_bool
4966 mono_class_is_delegate (MonoClass *klass)
4968 mono_bool result;
4969 MONO_ENTER_GC_UNSAFE;
4970 result = m_class_is_delegate (klass);
4971 MONO_EXIT_GC_UNSAFE;
4972 return result;
4976 * mono_class_implements_interface
4977 * \param klass The MonoClass to act on
4978 * \param interface The interface to check if \p klass implements.
4980 * \returns TRUE if \p klass implements \p interface.
4982 mono_bool
4983 mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
4985 return mono_class_is_assignable_from_internal (iface, klass);
4988 static mono_bool
4989 class_implements_interface_ignore_generics (MonoClass* klass, MonoClass* iface)
4991 int i;
4992 ERROR_DECL (error);
4993 if (mono_class_is_ginst (iface))
4994 iface = mono_class_get_generic_type_definition (iface);
4995 while (klass != NULL) {
4996 if (mono_class_is_assignable_from_internal (iface, klass))
4997 return TRUE;
4998 mono_class_setup_interfaces (klass, error);
4999 if (!is_ok (error)) {
5000 mono_error_cleanup (error);
5001 return FALSE;
5003 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
5004 for (i = 0; i < m_class_get_interface_count (klass); i++) {
5005 MonoClass *ic = klass_interfaces [i];
5006 if (mono_class_is_ginst (ic))
5007 ic = mono_class_get_generic_type_definition (ic);
5008 if (ic == iface) {
5009 return TRUE;
5012 klass = m_class_get_parent (klass);
5014 return FALSE;
5019 * mono_field_get_name:
5020 * \param field the \c MonoClassField to act on
5022 * \returns The name of the field.
5024 const char*
5025 mono_field_get_name (MonoClassField *field)
5027 return field->name;
5031 * mono_field_get_type_internal:
5032 * \param field the \c MonoClassField to act on
5033 * \returns \c MonoType of the field.
5035 MonoType*
5036 mono_field_get_type_internal (MonoClassField *field)
5038 MonoType *type = field->type;
5039 if (type)
5040 return type;
5042 ERROR_DECL (error);
5043 type = mono_field_get_type_checked (field, error);
5044 if (!mono_error_ok (error)) {
5045 mono_trace_warning (MONO_TRACE_TYPE, "Could not load field's type due to %s", mono_error_get_message (error));
5046 mono_error_cleanup (error);
5048 return type;
5052 * mono_field_get_type:
5053 * \param field the \c MonoClassField to act on
5054 * \returns \c MonoType of the field.
5056 MonoType*
5057 mono_field_get_type (MonoClassField *field)
5059 MonoType *type = field->type;
5060 if (type)
5061 return type;
5063 MONO_ENTER_GC_UNSAFE;
5064 type = mono_field_get_type_internal (field);
5065 MONO_EXIT_GC_UNSAFE;
5066 return type;
5070 * mono_field_get_type_checked:
5071 * \param field the \c MonoClassField to act on
5072 * \param error used to return any error found while retrieving \p field type
5074 * \returns \c MonoType of the field.
5076 MonoType*
5077 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
5079 error_init (error);
5080 MonoType *type = field->type;
5081 if (type)
5082 return type;
5083 mono_field_resolve_type (field, error);
5084 return field->type;
5088 * mono_field_get_parent:
5089 * \param field the \c MonoClassField to act on
5091 * \returns \c MonoClass where the field was defined.
5093 MonoClass*
5094 mono_field_get_parent (MonoClassField *field)
5096 return field->parent;
5100 * mono_field_get_flags;
5101 * \param field the \c MonoClassField to act on
5103 * The metadata flags for a field are encoded using the
5104 * \c FIELD_ATTRIBUTE_* constants. See the \c tabledefs.h file for details.
5106 * \returns The flags for the field.
5108 guint32
5109 mono_field_get_flags (MonoClassField *field)
5111 if (!field->type)
5112 return mono_field_resolve_flags (field);
5113 return field->type->attrs;
5117 * mono_field_get_offset:
5118 * \param field the \c MonoClassField to act on
5120 * \returns The field offset.
5122 guint32
5123 mono_field_get_offset (MonoClassField *field)
5125 mono_class_setup_fields(field->parent);
5126 return field->offset;
5129 static const char *
5130 mono_field_get_rva (MonoClassField *field)
5132 guint32 rva;
5133 int field_index;
5134 MonoClass *klass = field->parent;
5135 MonoFieldDefaultValue *def_values;
5137 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
5139 def_values = mono_class_get_field_def_values (klass);
5140 if (!def_values) {
5141 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
5143 mono_class_set_field_def_values (klass, def_values);
5146 field_index = mono_field_get_index (field);
5148 if (!def_values [field_index].data && !image_is_dynamic (m_class_get_image (klass))) {
5149 int first_field_idx = mono_class_get_first_field_idx (klass);
5150 mono_metadata_field_info (m_class_get_image (field->parent), first_field_idx + field_index, NULL, &rva, NULL);
5151 if (!rva)
5152 g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), m_class_get_name (field->parent));
5153 def_values [field_index].data = mono_image_rva_map (m_class_get_image (field->parent), rva);
5156 return def_values [field_index].data;
5160 * mono_field_get_data:
5161 * \param field the \c MonoClassField to act on
5163 * \returns A pointer to the metadata constant value or to the field
5164 * data if it has an RVA flag.
5166 const char *
5167 mono_field_get_data (MonoClassField *field)
5169 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
5170 MonoTypeEnum def_type;
5172 return mono_class_get_field_default_value (field, &def_type);
5173 } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
5174 return mono_field_get_rva (field);
5175 } else {
5176 return NULL;
5181 * mono_property_get_name:
5182 * \param prop the \c MonoProperty to act on
5183 * \returns The name of the property
5185 const char*
5186 mono_property_get_name (MonoProperty *prop)
5188 return prop->name;
5192 * mono_property_get_set_method
5193 * \param prop the \c MonoProperty to act on.
5194 * \returns The setter method of the property, a \c MonoMethod.
5196 MonoMethod*
5197 mono_property_get_set_method (MonoProperty *prop)
5199 return prop->set;
5203 * mono_property_get_get_method
5204 * \param prop the MonoProperty to act on.
5205 * \returns The getter method of the property (A \c MonoMethod)
5207 MonoMethod*
5208 mono_property_get_get_method (MonoProperty *prop)
5210 return prop->get;
5214 * mono_property_get_parent:
5215 * \param prop the \c MonoProperty to act on.
5216 * \returns The \c MonoClass where the property was defined.
5218 MonoClass*
5219 mono_property_get_parent (MonoProperty *prop)
5221 return prop->parent;
5225 * mono_property_get_flags:
5226 * \param prop the \c MonoProperty to act on.
5228 * The metadata flags for a property are encoded using the
5229 * \c PROPERTY_ATTRIBUTE_* constants. See the \c tabledefs.h file for details.
5231 * \returns The flags for the property.
5233 guint32
5234 mono_property_get_flags (MonoProperty *prop)
5236 return prop->attrs;
5240 * mono_event_get_name:
5241 * \param event the MonoEvent to act on
5242 * \returns The name of the event.
5244 const char*
5245 mono_event_get_name (MonoEvent *event)
5247 return event->name;
5251 * mono_event_get_add_method:
5252 * \param event The \c MonoEvent to act on.
5253 * \returns The \c add method for the event, a \c MonoMethod.
5255 MonoMethod*
5256 mono_event_get_add_method (MonoEvent *event)
5258 return event->add;
5262 * mono_event_get_remove_method:
5263 * \param event The \c MonoEvent to act on.
5264 * \returns The \c remove method for the event, a \c MonoMethod.
5266 MonoMethod*
5267 mono_event_get_remove_method (MonoEvent *event)
5269 return event->remove;
5273 * mono_event_get_raise_method:
5274 * \param event The \c MonoEvent to act on.
5275 * \returns The \c raise method for the event, a \c MonoMethod.
5277 MonoMethod*
5278 mono_event_get_raise_method (MonoEvent *event)
5280 return event->raise;
5284 * mono_event_get_parent:
5285 * \param event the MonoEvent to act on.
5286 * \returns The \c MonoClass where the event is defined.
5288 MonoClass*
5289 mono_event_get_parent (MonoEvent *event)
5291 return event->parent;
5295 * mono_event_get_flags
5296 * \param event the \c MonoEvent to act on.
5298 * The metadata flags for an event are encoded using the
5299 * \c EVENT_* constants. See the \c tabledefs.h file for details.
5301 * \returns The flags for the event.
5303 guint32
5304 mono_event_get_flags (MonoEvent *event)
5306 return event->attrs;
5310 * mono_class_get_method_from_name:
5311 * \param klass where to look for the method
5312 * \param name name of the method
5313 * \param param_count number of parameters. -1 for any number.
5315 * Obtains a \c MonoMethod with a given name and number of parameters.
5316 * It only works if there are no multiple signatures for any given method name.
5318 MonoMethod *
5319 mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_count)
5321 MonoMethod *result;
5322 MONO_ENTER_GC_UNSAFE;
5323 ERROR_DECL (error);
5324 result = mono_class_get_method_from_name_checked (klass, name, param_count, 0, error);
5325 mono_error_cleanup (error);
5326 MONO_EXIT_GC_UNSAFE;
5327 return result;
5330 MonoMethod*
5331 mono_find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
5333 MonoImage *klass_image = m_class_get_image (klass);
5334 MonoMethod *res = NULL;
5335 int i;
5337 /* Search directly in the metadata to avoid calling setup_methods () */
5338 int first_idx = mono_class_get_first_method_idx (klass);
5339 int mcount = mono_class_get_method_count (klass);
5340 for (i = 0; i < mcount; ++i) {
5341 ERROR_DECL (error);
5342 guint32 cols [MONO_METHOD_SIZE];
5343 MonoMethod *method;
5344 MonoMethodSignature *sig;
5346 /* first_idx points into the methodptr table */
5347 mono_metadata_decode_table_row (klass_image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE);
5349 if (!strcmp (mono_metadata_string_heap (klass_image, cols [MONO_METHOD_NAME]), name)) {
5350 method = mono_get_method_checked (klass_image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error);
5351 if (!method) {
5352 mono_error_cleanup (error); /* FIXME don't swallow the error */
5353 continue;
5355 if (param_count == -1) {
5356 res = method;
5357 break;
5359 sig = mono_method_signature_checked (method, error);
5360 if (!sig) {
5361 mono_error_cleanup (error); /* FIXME don't swallow the error */
5362 continue;
5364 if (sig->param_count == param_count) {
5365 res = method;
5366 break;
5371 return res;
5375 * mono_class_get_method_from_name_flags:
5376 * \param klass where to look for the method
5377 * \param name_space name of the method
5378 * \param param_count number of parameters. -1 for any number.
5379 * \param flags flags which must be set in the method
5381 * Obtains a \c MonoMethod with a given name and number of parameters.
5382 * It only works if there are no multiple signatures for any given method name.
5384 MonoMethod *
5385 mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int param_count, int flags)
5387 MonoMethod *method;
5388 MONO_ENTER_GC_UNSAFE;
5389 ERROR_DECL (error);
5390 method = mono_class_get_method_from_name_checked (klass, name, param_count, flags, error);
5391 mono_error_cleanup (error);
5392 MONO_EXIT_GC_UNSAFE;
5393 return method;
5397 * mono_class_get_method_from_name_checked:
5398 * \param klass where to look for the method
5399 * \param name_space name of the method
5400 * \param param_count number of parameters. -1 for any number.
5401 * \param flags flags which must be set in the method
5402 * \param error
5404 * Obtains a \c MonoMethod with a given name and number of parameters.
5405 * It only works if there are no multiple signatures for any given method name.
5407 MonoMethod *
5408 mono_class_get_method_from_name_checked (MonoClass *klass, const char *name,
5409 int param_count, int flags, MonoError *error)
5411 MonoMethod *res = NULL;
5412 int i;
5414 mono_class_init_internal (klass);
5416 if (mono_class_is_ginst (klass) && !m_class_get_methods (klass)) {
5417 res = mono_class_get_method_from_name_checked (mono_class_get_generic_class (klass)->container_class, name, param_count, flags, error);
5419 if (res)
5420 res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), error);
5422 return res;
5425 if (m_class_get_methods (klass) || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
5426 mono_class_setup_methods (klass);
5428 We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
5429 See mono/tests/array_load_exception.il
5430 FIXME we should better report this error to the caller
5432 MonoMethod **klass_methods = m_class_get_methods (klass);
5433 if (!klass_methods)
5434 return NULL;
5435 int mcount = mono_class_get_method_count (klass);
5436 for (i = 0; i < mcount; ++i) {
5437 MonoMethod *method = klass_methods [i];
5439 if (method->name[0] == name [0] &&
5440 !strcmp (name, method->name) &&
5441 (param_count == -1 || mono_method_signature_internal (method)->param_count == param_count) &&
5442 ((method->flags & flags) == flags)) {
5443 res = method;
5444 break;
5448 else {
5449 res = mono_find_method_in_metadata (klass, name, param_count, flags);
5452 return res;
5455 gboolean
5456 mono_class_has_failure (const MonoClass *klass)
5458 g_assert (klass != NULL);
5459 return m_class_has_failure ((MonoClass*)klass) != 0;
5464 * mono_class_set_type_load_failure:
5465 * \param klass class in which the failure was detected
5466 * \param fmt \c printf -style error message string.
5468 * Collect detected failure informaion in the class for later processing.
5469 * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class()
5470 * Note that only the first failure is kept.
5472 * LOCKING: Acquires the loader lock.
5474 * \returns FALSE if a failure was already set on the class, or TRUE otherwise.
5476 gboolean
5477 mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
5479 ERROR_DECL (prepare_error);
5480 va_list args;
5482 if (mono_class_has_failure (klass))
5483 return FALSE;
5485 va_start (args, fmt);
5486 mono_error_vset_type_load_class (prepare_error, klass, fmt, args);
5487 va_end (args);
5489 MonoErrorBoxed *box = mono_error_box (prepare_error, m_class_get_image (klass));
5490 mono_error_cleanup (prepare_error);
5491 return mono_class_set_failure (klass, box);
5495 * mono_class_get_exception_for_failure:
5496 * \param klass class in which the failure was detected
5498 * \returns a constructed MonoException than the caller can then throw
5499 * using mono_raise_exception - or NULL if no failure is present (or
5500 * doesn't result in an exception).
5502 MonoException*
5503 mono_class_get_exception_for_failure (MonoClass *klass)
5505 if (!mono_class_has_failure (klass))
5506 return NULL;
5507 ERROR_DECL (unboxed_error);
5508 mono_error_set_for_class_failure (unboxed_error, klass);
5509 return mono_error_convert_to_exception (unboxed_error);
5512 static gboolean
5513 is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
5515 outer_klass = mono_class_get_generic_type_definition (outer_klass);
5516 inner_klass = mono_class_get_generic_type_definition (inner_klass);
5517 do {
5518 if (outer_klass == inner_klass)
5519 return TRUE;
5520 inner_klass = m_class_get_nested_in (inner_klass);
5521 } while (inner_klass);
5522 return FALSE;
5525 MonoClass *
5526 mono_class_get_generic_type_definition (MonoClass *klass)
5528 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
5529 return gklass ? gklass->container_class : klass;
5533 * Check if @klass is a subtype of @parent ignoring generic instantiations.
5535 * Generic instantiations are ignored for all super types of @klass.
5537 * Visibility checks ignoring generic instantiations.
5539 * Class implementing interface visibility checks ignore generic instantiations
5541 gboolean
5542 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
5544 int i;
5545 klass = mono_class_get_generic_type_definition (klass);
5546 parent = mono_class_get_generic_type_definition (parent);
5547 mono_class_setup_supertypes (klass);
5549 for (i = 0; i < m_class_get_idepth (klass); ++i) {
5550 if (parent == mono_class_get_generic_type_definition (m_class_get_supertypes (klass) [i]))
5551 return TRUE;
5554 if (MONO_CLASS_IS_INTERFACE_INTERNAL (parent) && class_implements_interface_ignore_generics (klass, parent))
5555 return TRUE;
5557 return FALSE;
5560 * Subtype can only access parent members with family protection if the site object
5561 * is subclass of Subtype. For example:
5562 * class A { protected int x; }
5563 * class B : A {
5564 * void valid_access () {
5565 * B b;
5566 * b.x = 0;
5568 * void invalid_access () {
5569 * A a;
5570 * a.x = 0;
5573 * */
5574 static gboolean
5575 is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
5577 if (MONO_CLASS_IS_INTERFACE_INTERNAL (member_klass) && !MONO_CLASS_IS_INTERFACE_INTERNAL (access_klass)) {
5578 /* Can happen with default interface methods */
5579 if (!class_implements_interface_ignore_generics (access_klass, member_klass))
5580 return FALSE;
5581 } else if (member_klass != access_klass && MONO_CLASS_IS_INTERFACE_INTERNAL (member_klass) && MONO_CLASS_IS_INTERFACE_INTERNAL (access_klass)) {
5582 /* Can happen with default interface methods */
5583 if (!mono_interface_implements_interface (access_klass, member_klass))
5584 return FALSE;
5585 } else {
5586 if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
5587 return FALSE;
5590 if (context_klass == NULL)
5591 return TRUE;
5592 /*if access_klass is not member_klass context_klass must be type compat*/
5593 if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
5594 return FALSE;
5595 return TRUE;
5598 static gboolean
5599 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
5601 GSList *tmp;
5602 if (accessing == accessed)
5603 return TRUE;
5604 if (!accessed || !accessing)
5605 return FALSE;
5607 /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
5608 * anywhere so untrusted friends are not safe to access platform's code internals */
5609 if (mono_security_core_clr_enabled ()) {
5610 if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
5611 return FALSE;
5614 mono_assembly_load_friends (accessed);
5615 for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
5616 MonoAssemblyName *friend_ = (MonoAssemblyName *)tmp->data;
5617 /* Be conservative with checks */
5618 if (!friend_->name)
5619 continue;
5620 if (g_ascii_strcasecmp (accessing->aname.name, friend_->name))
5621 continue;
5622 if (friend_->public_key_token [0]) {
5623 if (!accessing->aname.public_key_token [0])
5624 continue;
5625 if (!mono_public_tokens_are_equal (friend_->public_key_token, accessing->aname.public_key_token))
5626 continue;
5628 return TRUE;
5630 return FALSE;
5634 * If klass is a generic type or if it is derived from a generic type, return the
5635 * MonoClass of the generic definition
5636 * Returns NULL if not found
5638 static MonoClass*
5639 get_generic_definition_class (MonoClass *klass)
5641 while (klass) {
5642 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
5643 if (gklass && gklass->container_class)
5644 return gklass->container_class;
5645 klass = m_class_get_parent (klass);
5647 return NULL;
5650 static gboolean
5651 can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
5653 int i;
5654 for (i = 0; i < ginst->type_argc; ++i) {
5655 MonoType *type = ginst->type_argv[i];
5656 switch (type->type) {
5657 case MONO_TYPE_SZARRAY:
5658 if (!can_access_type (access_klass, type->data.klass))
5659 return FALSE;
5660 break;
5661 case MONO_TYPE_ARRAY:
5662 if (!can_access_type (access_klass, type->data.array->eklass))
5663 return FALSE;
5664 break;
5665 case MONO_TYPE_PTR:
5666 if (!can_access_type (access_klass, mono_class_from_mono_type_internal (type->data.type)))
5667 return FALSE;
5668 break;
5669 case MONO_TYPE_CLASS:
5670 case MONO_TYPE_VALUETYPE:
5671 case MONO_TYPE_GENERICINST:
5672 if (!can_access_type (access_klass, mono_class_from_mono_type_internal (type)))
5673 return FALSE;
5674 default:
5675 break;
5678 return TRUE;
5681 static gboolean
5682 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
5684 int access_level;
5686 if (access_klass == member_klass)
5687 return TRUE;
5689 MonoAssembly *access_klass_assembly = m_class_get_image (access_klass)->assembly;
5690 MonoAssembly *member_klass_assembly = m_class_get_image (member_klass)->assembly;
5692 if (access_klass_assembly && m_class_get_image (access_klass)->assembly->corlib_internal)
5693 return TRUE;
5695 if (m_class_get_element_class (access_klass) && !m_class_is_enumtype (access_klass)) {
5696 access_klass = m_class_get_element_class (access_klass);
5697 access_klass_assembly = m_class_get_image (access_klass)->assembly;
5700 if (m_class_get_element_class (member_klass) && !m_class_is_enumtype (member_klass)) {
5701 member_klass = m_class_get_element_class (member_klass);
5702 member_klass_assembly = m_class_get_image (member_klass)->assembly;
5705 access_level = mono_class_get_flags (member_klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
5707 if (mono_type_is_generic_argument (m_class_get_byval_arg (member_klass)))
5708 return TRUE;
5710 if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst))
5711 return FALSE;
5713 if (is_nesting_type (access_klass, member_klass) || (m_class_get_nested_in (access_klass) && is_nesting_type (m_class_get_nested_in (access_klass), member_klass)))
5714 return TRUE;
5716 /*Non nested type with nested visibility. We just fail it.*/
5717 if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && m_class_get_nested_in (member_klass) == NULL)
5718 return FALSE;
5720 MonoClass *member_klass_nested_in = m_class_get_nested_in (member_klass);
5721 switch (access_level) {
5722 case TYPE_ATTRIBUTE_NOT_PUBLIC:
5723 return can_access_internals (access_klass_assembly, member_klass_assembly);
5725 case TYPE_ATTRIBUTE_PUBLIC:
5726 return TRUE;
5728 case TYPE_ATTRIBUTE_NESTED_PUBLIC:
5729 return member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
5731 case TYPE_ATTRIBUTE_NESTED_PRIVATE:
5732 return is_nesting_type (member_klass, access_klass) && member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
5734 case TYPE_ATTRIBUTE_NESTED_FAMILY:
5735 return mono_class_has_parent_and_ignore_generics (access_klass, m_class_get_nested_in (member_klass));
5737 case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
5738 return can_access_internals (access_klass_assembly, member_klass_assembly) && member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
5740 case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
5741 return can_access_internals (access_klass_assembly, m_class_get_image (member_klass_nested_in)->assembly) &&
5742 mono_class_has_parent_and_ignore_generics (access_klass, member_klass_nested_in);
5744 case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
5745 return can_access_internals (access_klass_assembly, m_class_get_image (member_klass_nested_in)->assembly) ||
5746 mono_class_has_parent_and_ignore_generics (access_klass, member_klass_nested_in);
5748 return FALSE;
5751 /* FIXME: check visibility of type, too */
5752 static gboolean
5753 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
5755 MonoClass *member_generic_def;
5756 MonoAssembly *access_klass_assembly = m_class_get_image (access_klass)->assembly;
5757 if (access_klass_assembly && access_klass_assembly->corlib_internal)
5758 return TRUE;
5760 MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass);
5761 if (((access_gklass && access_gklass->container_class) ||
5762 mono_class_is_gtd (access_klass)) &&
5763 (member_generic_def = get_generic_definition_class (member_klass))) {
5764 MonoClass *access_container;
5766 if (mono_class_is_gtd (access_klass))
5767 access_container = access_klass;
5768 else
5769 access_container = access_gklass->container_class;
5771 if (can_access_member (access_container, member_generic_def, context_klass, access_level))
5772 return TRUE;
5775 MonoImage *member_klass_image = m_class_get_image (member_klass);
5776 /* Partition I 8.5.3.2 */
5777 /* the access level values are the same for fields and methods */
5778 switch (access_level) {
5779 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
5780 /* same compilation unit */
5781 return m_class_get_image (access_klass) == member_klass_image;
5782 case FIELD_ATTRIBUTE_PRIVATE:
5783 return access_klass == member_klass;
5784 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
5785 if (is_valid_family_access (access_klass, member_klass, context_klass) &&
5786 can_access_internals (access_klass_assembly, member_klass_image->assembly))
5787 return TRUE;
5788 return FALSE;
5789 case FIELD_ATTRIBUTE_ASSEMBLY:
5790 return can_access_internals (access_klass_assembly, member_klass_image->assembly);
5791 case FIELD_ATTRIBUTE_FAMILY:
5792 if (is_valid_family_access (access_klass, member_klass, context_klass))
5793 return TRUE;
5794 return FALSE;
5795 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
5796 if (is_valid_family_access (access_klass, member_klass, context_klass))
5797 return TRUE;
5798 return can_access_internals (access_klass_assembly, member_klass_image->assembly);
5799 case FIELD_ATTRIBUTE_PUBLIC:
5800 return TRUE;
5802 return FALSE;
5806 * mono_method_can_access_field:
5807 * \param method Method that will attempt to access the field
5808 * \param field the field to access
5810 * Used to determine if a method is allowed to access the specified field.
5812 * \returns TRUE if the given \p method is allowed to access the \p field while following
5813 * the accessibility rules of the CLI.
5815 gboolean
5816 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
5818 /* FIXME: check all overlapping fields */
5819 int can = can_access_member (method->klass, field->parent, NULL, mono_field_get_type_internal (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5820 if (!can) {
5821 MonoClass *nested = m_class_get_nested_in (method->klass);
5822 while (nested) {
5823 can = can_access_member (nested, field->parent, NULL, mono_field_get_type_internal (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5824 if (can)
5825 return TRUE;
5826 nested = m_class_get_nested_in (nested);
5829 return can;
5832 static MonoMethod*
5833 mono_method_get_method_definition (MonoMethod *method)
5835 while (method->is_inflated)
5836 method = ((MonoMethodInflated*)method)->declaring;
5837 return method;
5841 * mono_method_can_access_method:
5842 * \param method Method that will attempt to access the other method
5843 * \param called the method that we want to probe for accessibility.
5845 * Used to determine if the \p method is allowed to access the specified \p called method.
5847 * \returns TRUE if the given \p method is allowed to invoke the \p called while following
5848 * the accessibility rules of the CLI.
5850 gboolean
5851 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
5853 method = mono_method_get_method_definition (method);
5854 called = mono_method_get_method_definition (called);
5855 return mono_method_can_access_method_full (method, called, NULL);
5859 * mono_method_can_access_method_full:
5860 * @method: The caller method
5861 * @called: The called method
5862 * @context_klass: The static type on stack of the owner @called object used
5864 * This function must be used with instance calls, as they have more strict family accessibility.
5865 * It can be used with static methods, but context_klass should be NULL.
5867 * Returns: TRUE if caller have proper visibility and acessibility to @called
5869 gboolean
5870 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
5872 /* Wrappers are except from access checks */
5873 if (method->wrapper_type != MONO_WRAPPER_NONE || called->wrapper_type != MONO_WRAPPER_NONE)
5874 return TRUE;
5876 MonoClass *access_class = method->klass;
5877 MonoClass *member_class = called->klass;
5878 int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
5879 if (!can) {
5880 MonoClass *nested = m_class_get_nested_in (access_class);
5881 while (nested) {
5882 can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
5883 if (can)
5884 break;
5885 nested = m_class_get_nested_in (nested);
5889 if (!can)
5890 return FALSE;
5892 can = can_access_type (access_class, member_class);
5893 if (!can) {
5894 MonoClass *nested = m_class_get_nested_in (access_class);
5895 while (nested) {
5896 can = can_access_type (nested, member_class);
5897 if (can)
5898 break;
5899 nested = m_class_get_nested_in (nested);
5903 if (!can)
5904 return FALSE;
5906 if (called->is_inflated) {
5907 MonoMethodInflated * infl = (MonoMethodInflated*)called;
5908 if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
5909 return FALSE;
5912 return TRUE;
5917 * mono_method_can_access_field_full:
5918 * @method: The caller method
5919 * @field: The accessed field
5920 * @context_klass: The static type on stack of the owner @field object used
5922 * This function must be used with instance fields, as they have more strict family accessibility.
5923 * It can be used with static fields, but context_klass should be NULL.
5925 * Returns: TRUE if caller have proper visibility and acessibility to @field
5927 gboolean
5928 mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
5930 MonoClass *access_class = method->klass;
5931 MonoClass *member_class = field->parent;
5932 /* FIXME: check all overlapping fields */
5933 int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5934 if (!can) {
5935 MonoClass *nested = m_class_get_nested_in (access_class);
5936 while (nested) {
5937 can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5938 if (can)
5939 break;
5940 nested = m_class_get_nested_in (nested);
5944 if (!can)
5945 return FALSE;
5947 can = can_access_type (access_class, member_class);
5948 if (!can) {
5949 MonoClass *nested = m_class_get_nested_in (access_class);
5950 while (nested) {
5951 can = can_access_type (nested, member_class);
5952 if (can)
5953 break;
5954 nested = m_class_get_nested_in (nested);
5958 if (!can)
5959 return FALSE;
5960 return TRUE;
5964 * mono_class_can_access_class:
5965 * @source_class: The source class
5966 * @target_class: The accessed class
5968 * This function returns is @target_class is visible to @source_class
5970 * Returns: TRUE if source have proper visibility and acessibility to target
5972 gboolean
5973 mono_class_can_access_class (MonoClass *source_class, MonoClass *target_class)
5975 return can_access_type (source_class, target_class);
5979 * mono_type_is_valid_enum_basetype:
5980 * \param type The MonoType to check
5981 * \returns TRUE if the type can be used as the basetype of an enum
5983 gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
5984 switch (type->type) {
5985 case MONO_TYPE_I1:
5986 case MONO_TYPE_U1:
5987 case MONO_TYPE_BOOLEAN:
5988 case MONO_TYPE_I2:
5989 case MONO_TYPE_U2:
5990 case MONO_TYPE_CHAR:
5991 case MONO_TYPE_I4:
5992 case MONO_TYPE_U4:
5993 case MONO_TYPE_I8:
5994 case MONO_TYPE_U8:
5995 case MONO_TYPE_I:
5996 case MONO_TYPE_U:
5997 #if ENABLE_NETCORE
5998 case MONO_TYPE_R8:
5999 case MONO_TYPE_R4:
6000 #endif
6001 return TRUE;
6002 default:
6003 return FALSE;
6008 * mono_class_is_valid_enum:
6009 * \param klass An enum class to be validated
6011 * This method verify the required properties an enum should have.
6013 * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
6014 * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
6015 * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
6017 * \returns TRUE if the informed enum class is valid
6019 gboolean
6020 mono_class_is_valid_enum (MonoClass *klass)
6022 MonoClassField * field;
6023 gpointer iter = NULL;
6024 gboolean found_base_field = FALSE;
6026 g_assert (m_class_is_enumtype (klass));
6027 MonoClass *klass_parent = m_class_get_parent (klass);
6028 /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
6029 if (!klass_parent || strcmp (m_class_get_name (klass_parent), "Enum") || strcmp (m_class_get_name_space (klass_parent), "System") ) {
6030 return FALSE;
6033 if (!mono_class_is_auto_layout (klass))
6034 return FALSE;
6036 while ((field = mono_class_get_fields_internal (klass, &iter))) {
6037 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
6038 if (found_base_field)
6039 return FALSE;
6040 found_base_field = TRUE;
6041 if (!mono_type_is_valid_enum_basetype (field->type))
6042 return FALSE;
6046 if (!found_base_field)
6047 return FALSE;
6049 if (mono_class_get_method_count (klass) > 0)
6050 return FALSE;
6052 return TRUE;
6055 gboolean
6056 mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
6058 return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst;
6061 void
6062 mono_field_resolve_type (MonoClassField *field, MonoError *error)
6064 MonoClass *klass = field->parent;
6065 MonoImage *image = m_class_get_image (klass);
6066 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
6067 MonoType *ftype;
6068 int field_idx = field - m_class_get_fields (klass);
6070 error_init (error);
6072 if (gtd) {
6073 MonoClassField *gfield = &m_class_get_fields (gtd) [field_idx];
6074 MonoType *gtype = mono_field_get_type_checked (gfield, error);
6075 if (!mono_error_ok (error)) {
6076 char *full_name = mono_type_get_full_name (gtd);
6077 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));
6078 g_free (full_name);
6081 ftype = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
6082 if (!mono_error_ok (error)) {
6083 char *full_name = mono_type_get_full_name (klass);
6084 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));
6085 g_free (full_name);
6087 } else {
6088 const char *sig;
6089 guint32 cols [MONO_FIELD_SIZE];
6090 MonoGenericContainer *container = NULL;
6091 int idx = mono_class_get_first_field_idx (klass) + field_idx;
6093 /*FIXME, in theory we do not lazy load SRE fields*/
6094 g_assert (!image_is_dynamic (image));
6096 if (mono_class_is_gtd (klass)) {
6097 container = mono_class_get_generic_container (klass);
6098 } else if (gtd) {
6099 container = mono_class_get_generic_container (gtd);
6100 g_assert (container);
6103 /* first_field_idx and idx points into the fieldptr table */
6104 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
6106 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], error)) {
6107 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
6108 return;
6111 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
6113 mono_metadata_decode_value (sig, &sig);
6114 /* FIELD signature == 0x06 */
6115 g_assert (*sig == 0x06);
6117 ftype = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
6118 if (!ftype) {
6119 char *full_name = mono_type_get_full_name (klass);
6120 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));
6121 g_free (full_name);
6124 mono_memory_barrier ();
6125 field->type = ftype;
6128 static guint32
6129 mono_field_resolve_flags (MonoClassField *field)
6131 MonoClass *klass = field->parent;
6132 MonoImage *image = m_class_get_image (klass);
6133 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
6134 int field_idx = field - m_class_get_fields (klass);
6136 if (gtd) {
6137 MonoClassField *gfield = &m_class_get_fields (gtd) [field_idx];
6138 return mono_field_get_flags (gfield);
6139 } else {
6140 int idx = mono_class_get_first_field_idx (klass) + field_idx;
6142 /*FIXME, in theory we do not lazy load SRE fields*/
6143 g_assert (!image_is_dynamic (image));
6145 return mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_FLAGS);
6150 * mono_class_get_fields_lazy:
6151 * \param klass the MonoClass to act on
6153 * This routine is an iterator routine for retrieving the fields in a class.
6154 * Only minimal information about fields are loaded. Accessors must be used
6155 * for all MonoClassField returned.
6157 * You must pass a gpointer that points to zero and is treated as an opaque handle to
6158 * iterate over all of the elements. When no more values are
6159 * available, the return value is NULL.
6161 * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
6163 MonoClassField*
6164 mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
6166 MonoClassField* field;
6167 if (!iter)
6168 return NULL;
6169 if (!*iter) {
6170 mono_class_setup_basic_field_info (klass);
6171 MonoClassField *klass_fields = m_class_get_fields (klass);
6172 if (!klass_fields)
6173 return NULL;
6174 /* start from the first */
6175 if (mono_class_get_field_count (klass)) {
6176 *iter = &klass_fields [0];
6177 return (MonoClassField *)*iter;
6178 } else {
6179 /* no fields */
6180 return NULL;
6183 field = (MonoClassField *)*iter;
6184 field++;
6185 if (field < &m_class_get_fields (klass) [mono_class_get_field_count (klass)]) {
6186 *iter = field;
6187 return (MonoClassField *)*iter;
6189 return NULL;
6192 char*
6193 mono_class_full_name (MonoClass *klass)
6195 return mono_type_full_name (m_class_get_byval_arg (klass));
6198 /* Declare all shared lazy type lookup functions */
6199 GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, "System.Runtime.InteropServices", "SafeHandle")
6202 * mono_method_get_base_method:
6203 * \param method a method
6204 * \param definition if true, get the definition
6205 * \param error set on failure
6207 * Given a virtual method associated with a subclass, return the corresponding
6208 * method from an ancestor. If \p definition is FALSE, returns the method in the
6209 * superclass of the given method. If \p definition is TRUE, return the method
6210 * in the ancestor class where it was first declared. The type arguments will
6211 * be inflated in the ancestor classes. If the method is not associated with a
6212 * class, or isn't virtual, returns the method itself. On failure returns NULL
6213 * and sets \p error.
6215 MonoMethod*
6216 mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error)
6218 MonoClass *klass, *parent;
6219 MonoGenericContext *generic_inst = NULL;
6220 MonoMethod *result = NULL;
6221 int slot;
6223 if (method->klass == NULL)
6224 return method;
6226 if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
6227 MONO_CLASS_IS_INTERFACE_INTERNAL (method->klass) ||
6228 method->flags & METHOD_ATTRIBUTE_NEW_SLOT)
6229 return method;
6231 slot = mono_method_get_vtable_slot (method);
6232 if (slot == -1)
6233 return method;
6235 klass = method->klass;
6236 if (mono_class_is_ginst (klass)) {
6237 generic_inst = mono_class_get_context (klass);
6238 klass = mono_class_get_generic_class (klass)->container_class;
6241 retry:
6242 if (definition) {
6243 /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */
6244 for (parent = m_class_get_parent (klass); parent != NULL; parent = m_class_get_parent (parent)) {
6245 /* on entry, klass is either a plain old non-generic class and generic_inst == NULL
6246 or klass is the generic container class and generic_inst is the instantiation.
6248 when we go to the parent, if the parent is an open constructed type, we need to
6249 replace the type parameters by the definitions from the generic_inst, and then take it
6250 apart again into the klass and the generic_inst.
6252 For cases like this:
6253 class C<T> : B<T, int> {
6254 public override void Foo () { ... }
6256 class B<U,V> : A<HashMap<U,V>> {
6257 public override void Foo () { ... }
6259 class A<X> {
6260 public virtual void Foo () { ... }
6263 if at each iteration the parent isn't open, we can skip inflating it. if at some
6264 iteration the parent isn't generic (after possible inflation), we set generic_inst to
6265 NULL;
6267 MonoGenericContext *parent_inst = NULL;
6268 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (parent))) {
6269 parent = mono_class_inflate_generic_class_checked (parent, generic_inst, error);
6270 return_val_if_nok (error, NULL);
6272 if (mono_class_is_ginst (parent)) {
6273 parent_inst = mono_class_get_context (parent);
6274 parent = mono_class_get_generic_class (parent)->container_class;
6277 mono_class_setup_vtable (parent);
6278 if (m_class_get_vtable_size (parent) <= slot)
6279 break;
6280 klass = parent;
6281 generic_inst = parent_inst;
6283 } else {
6284 klass = m_class_get_parent (klass);
6285 if (!klass)
6286 return method;
6287 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (klass))) {
6288 klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
6289 return_val_if_nok (error, NULL);
6291 generic_inst = NULL;
6293 if (mono_class_is_ginst (klass)) {
6294 generic_inst = mono_class_get_context (klass);
6295 klass = mono_class_get_generic_class (klass)->container_class;
6300 if (generic_inst) {
6301 klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
6302 return_val_if_nok (error, NULL);
6305 if (klass == method->klass)
6306 return method;
6308 /*This is possible if definition == FALSE.
6309 * Do it here to be really sure we don't read invalid memory.
6311 if (slot >= m_class_get_vtable_size (klass))
6312 return method;
6314 mono_class_setup_vtable (klass);
6316 result = m_class_get_vtable (klass) [slot];
6317 if (result == NULL) {
6318 /* It is an abstract method */
6319 gboolean found = FALSE;
6320 gpointer iter = NULL;
6321 while ((result = mono_class_get_methods (klass, &iter))) {
6322 if (result->slot == slot) {
6323 found = TRUE;
6324 break;
6327 /* found might be FALSE if we looked in an abstract class
6328 * that doesn't override an abstract method of its
6329 * parent:
6330 * abstract class Base {
6331 * public abstract void Foo ();
6333 * abstract class Derived : Base { }
6334 * class Child : Derived {
6335 * public override void Foo () { }
6338 * if m was Child.Foo and we ask for the base method,
6339 * then we get here with klass == Derived and found == FALSE
6341 /* but it shouldn't be the case that if we're looking
6342 * for the definition and didn't find a result; the
6343 * loop above should've taken us as far as we could
6344 * go! */
6345 g_assert (!(definition && !found));
6346 if (!found)
6347 goto retry;
6350 g_assert (result != NULL);
6351 return result;