[2020-02] Fix leak in assembly-specific dllmap lookups (#21053)
[mono-project.git] / mono / metadata / class.c
blob91d88dd8b3dd27957db18aa8edff700aa80d45da
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 static MonoClass *
69 mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, gboolean case_sensitive, MonoError *error);
71 GENERATE_GET_CLASS_WITH_CACHE (valuetype, "System", "ValueType")
72 GENERATE_TRY_GET_CLASS_WITH_CACHE (handleref, "System.Runtime.InteropServices", "HandleRef")
74 #define CTOR_REQUIRED_FLAGS (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME)
75 #define CTOR_INVALID_FLAGS (METHOD_ATTRIBUTE_STATIC)
77 // define to print types whenever custom modifiers are appended during inflation
78 #undef DEBUG_INFLATE_CMODS
80 static
81 MonoImage *
82 mono_method_get_image (MonoMethod *method)
84 return m_class_get_image (method->klass);
87 /**
88 * mono_class_from_typeref:
89 * \param image a MonoImage
90 * \param type_token a TypeRef token
92 * Creates the \c MonoClass* structure representing the type defined by
93 * the typeref token valid inside \p image.
94 * \returns The \c MonoClass* representing the typeref token, or NULL if it could
95 * not be loaded.
97 MonoClass *
98 mono_class_from_typeref (MonoImage *image, guint32 type_token)
100 ERROR_DECL (error);
101 MonoClass *klass = mono_class_from_typeref_checked (image, type_token, error);
102 g_assert (is_ok (error)); /*FIXME proper error handling*/
103 return klass;
107 * mono_class_from_typeref_checked:
108 * \param image a MonoImage
109 * \param type_token a TypeRef token
110 * \param error error return code, if any.
112 * Creates the \c MonoClass* structure representing the type defined by
113 * the typeref token valid inside \p image.
115 * \returns The \c MonoClass* representing the typeref token, NULL if it could
116 * not be loaded with the \p error value filled with the information about the
117 * error.
119 MonoClass *
120 mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
122 guint32 cols [MONO_TYPEREF_SIZE];
123 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
124 guint32 idx;
125 const char *name, *nspace;
126 MonoClass *res = NULL;
127 MonoImage *module;
129 error_init (error);
131 if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
132 return NULL;
134 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
136 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
137 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
139 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
140 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
141 case MONO_RESOLUTION_SCOPE_MODULE:
143 LAMESPEC The spec says that a null module resolution scope should go through the exported type table.
144 This is not the observed behavior of existing implementations.
145 The defacto behavior is that it's just a typedef in disguise.
147 /* a typedef in disguise */
148 res = mono_class_from_name_checked (image, nspace, name, error);
149 goto done;
151 case MONO_RESOLUTION_SCOPE_MODULEREF:
152 module = mono_image_load_module_checked (image, idx, error);
153 if (module)
154 res = mono_class_from_name_checked (module, nspace, name, error);
155 goto done;
157 case MONO_RESOLUTION_SCOPE_TYPEREF: {
158 MonoClass *enclosing;
159 GList *tmp;
161 if (idx == mono_metadata_token_index (type_token)) {
162 mono_error_set_bad_image (error, image, "Image with self-referencing typeref token %08x.", type_token);
163 return NULL;
166 enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
167 return_val_if_nok (error, NULL);
169 GList *nested_classes = mono_class_get_nested_classes_property (enclosing);
170 if (m_class_is_nested_classes_inited (enclosing) && nested_classes) {
171 /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
172 for (tmp = nested_classes; tmp; tmp = tmp->next) {
173 res = (MonoClass *)tmp->data;
174 if (strcmp (m_class_get_name (res), name) == 0)
175 return res;
177 } else {
178 MonoImage *enclosing_image = m_class_get_image (enclosing);
179 guint32 enclosing_type_token = m_class_get_type_token (enclosing);
180 /* Don't call mono_class_init_internal as we might've been called by it recursively */
181 int i = mono_metadata_nesting_typedef (enclosing_image, enclosing_type_token, 1);
182 while (i) {
183 guint32 class_nested = mono_metadata_decode_row_col (&enclosing_image->tables [MONO_TABLE_NESTEDCLASS], i - 1, MONO_NESTED_CLASS_NESTED);
184 guint32 string_offset = mono_metadata_decode_row_col (&enclosing_image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
185 const char *nname = mono_metadata_string_heap (enclosing_image, string_offset);
187 if (strcmp (nname, name) == 0)
188 return mono_class_create_from_typedef (enclosing_image, MONO_TOKEN_TYPE_DEF | class_nested, error);
190 i = mono_metadata_nesting_typedef (enclosing_image, enclosing_type_token, i + 1);
193 g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
194 goto done;
196 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
197 break;
200 if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
201 mono_error_set_bad_image (error, image, "Image with invalid assemblyref token %08x.", idx);
202 return NULL;
205 if (!image->references || !image->references [idx - 1])
206 mono_assembly_load_reference (image, idx - 1);
207 g_assert (image->references [idx - 1]);
209 /* If the assembly did not load, register this as a type load exception */
210 if (image->references [idx - 1] == REFERENCE_MISSING){
211 MonoAssemblyName aname;
212 char *human_name;
214 mono_assembly_get_assemblyref (image, idx - 1, &aname);
215 human_name = mono_stringify_assembly_name (&aname);
216 gboolean refonly = FALSE;
217 if (image->assembly)
218 refonly = mono_asmctx_get_kind (&image->assembly->context) == MONO_ASMCTX_REFONLY;
219 mono_error_set_simple_file_not_found (error, human_name, refonly);
220 g_free (human_name);
221 return NULL;
224 res = mono_class_from_name_checked (image->references [idx - 1]->image, nspace, name, error);
226 done:
227 /* Generic case, should be avoided for when a better error is possible. */
228 if (!res && is_ok (error)) {
229 char *name = mono_class_name_from_token (image, type_token);
230 char *assembly = mono_assembly_name_from_token (image, type_token);
231 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);
233 return res;
237 static void *
238 mono_image_memdup (MonoImage *image, void *data, guint size)
240 void *res = mono_image_alloc (image, size);
241 memcpy (res, data, size);
242 return res;
245 /* Copy everything mono_metadata_free_array free. */
246 MonoArrayType *
247 mono_dup_array_type (MonoImage *image, MonoArrayType *a)
249 if (image) {
250 a = (MonoArrayType *)mono_image_memdup (image, a, sizeof (MonoArrayType));
251 if (a->sizes)
252 a->sizes = (int *)mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
253 if (a->lobounds)
254 a->lobounds = (int *)mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
255 } else {
256 a = (MonoArrayType *)g_memdup (a, sizeof (MonoArrayType));
257 if (a->sizes)
258 a->sizes = (int *)g_memdup (a->sizes, a->numsizes * sizeof (int));
259 if (a->lobounds)
260 a->lobounds = (int *)g_memdup (a->lobounds, a->numlobounds * sizeof (int));
262 return a;
265 /* Copy everything mono_metadata_free_method_signature free. */
266 MonoMethodSignature*
267 mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
269 int i;
271 sig = mono_metadata_signature_dup_full (image, sig);
273 sig->ret = mono_metadata_type_dup (image, sig->ret);
274 for (i = 0; i < sig->param_count; ++i)
275 sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
277 return sig;
280 static void
281 _mono_type_get_assembly_name (MonoClass *klass, GString *str)
283 MonoAssembly *ta = m_class_get_image (klass)->assembly;
284 char *name;
286 name = mono_stringify_assembly_name (&ta->aname);
287 g_string_append_printf (str, ", %s", name);
288 g_free (name);
291 static void
292 mono_type_name_check_byref (MonoType *type, GString *str)
294 if (type->byref)
295 g_string_append_c (str, '&');
298 static char*
299 escape_special_chars (const char* identifier)
301 size_t id_len = strlen (identifier);
302 // Assume the worst case, and thus only allocate once
303 char *res = g_malloc (id_len * 2 + 1);
304 char *res_ptr = res;
305 for (const char *s = identifier; *s != 0; s++) {
306 switch (*s) {
307 case ',':
308 case '+':
309 case '&':
310 case '*':
311 case '[':
312 case ']':
313 case '\\':
314 *res_ptr++ = '\\';
315 break;
317 *res_ptr++ = *s;
319 *res_ptr = '\0';
320 return res;
324 * mono_identifier_escape_type_name_chars:
325 * \param identifier the display name of a mono type
327 * \returns The name in external form, that is with escaping backslashes.
329 * The displayed form of an identifier has the characters ,+&*[]\
330 * that have special meaning in type names escaped with a preceeding
331 * backslash (\) character.
333 char*
334 mono_identifier_escape_type_name_chars (const char* identifier)
336 if (!identifier)
337 return NULL;
339 // If the string has any special characters escape the whole thing, otherwise just return the input
340 for (const char *s = identifier; *s != 0; s++) {
341 switch (*s) {
342 case ',':
343 case '+':
344 case '&':
345 case '*':
346 case '[':
347 case ']':
348 case '\\':
349 return escape_special_chars (identifier);
353 return g_strdup (identifier);
356 static void
357 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
358 MonoTypeNameFormat format)
360 MonoClass *klass;
362 switch (type->type) {
363 case MONO_TYPE_ARRAY: {
364 int i, rank = type->data.array->rank;
365 MonoTypeNameFormat nested_format;
367 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
368 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
370 mono_type_get_name_recurse (
371 m_class_get_byval_arg (type->data.array->eklass), str, FALSE, nested_format);
372 g_string_append_c (str, '[');
373 if (rank == 1)
374 g_string_append_c (str, '*');
375 for (i = 1; i < rank; i++)
376 g_string_append_c (str, ',');
377 g_string_append_c (str, ']');
379 mono_type_name_check_byref (type, str);
381 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
382 _mono_type_get_assembly_name (type->data.array->eklass, str);
383 break;
385 case MONO_TYPE_SZARRAY: {
386 MonoTypeNameFormat nested_format;
388 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
389 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
391 mono_type_get_name_recurse (
392 m_class_get_byval_arg (type->data.klass), str, FALSE, nested_format);
393 g_string_append (str, "[]");
395 mono_type_name_check_byref (type, str);
397 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
398 _mono_type_get_assembly_name (type->data.klass, str);
399 break;
401 case MONO_TYPE_PTR: {
402 MonoTypeNameFormat nested_format;
404 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
405 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
407 mono_type_get_name_recurse (
408 type->data.type, str, FALSE, nested_format);
409 g_string_append_c (str, '*');
411 mono_type_name_check_byref (type, str);
413 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
414 _mono_type_get_assembly_name (mono_class_from_mono_type_internal (type->data.type), str);
415 break;
417 case MONO_TYPE_VAR:
418 case MONO_TYPE_MVAR:
419 if (!mono_generic_param_name (type->data.generic_param))
420 g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
421 else
422 g_string_append (str, mono_generic_param_name (type->data.generic_param));
424 mono_type_name_check_byref (type, str);
426 break;
427 default:
428 klass = mono_class_from_mono_type_internal (type);
429 if (m_class_get_nested_in (klass)) {
430 mono_type_get_name_recurse (
431 m_class_get_byval_arg (m_class_get_nested_in (klass)), str, TRUE, format);
432 if (format == MONO_TYPE_NAME_FORMAT_IL)
433 g_string_append_c (str, '.');
434 else
435 g_string_append_c (str, '+');
436 } else if (*m_class_get_name_space (klass)) {
437 const char *klass_name_space = m_class_get_name_space (klass);
438 if (format == MONO_TYPE_NAME_FORMAT_IL)
439 g_string_append (str, klass_name_space);
440 else {
441 char *escaped = mono_identifier_escape_type_name_chars (klass_name_space);
442 g_string_append (str, escaped);
443 g_free (escaped);
445 g_string_append_c (str, '.');
447 const char *klass_name = m_class_get_name (klass);
448 if (format == MONO_TYPE_NAME_FORMAT_IL) {
449 const char *s = strchr (klass_name, '`');
450 gssize len = s ? (s - klass_name) : (gssize)strlen (klass_name);
451 g_string_append_len (str, klass_name, len);
452 } else {
453 char *escaped = mono_identifier_escape_type_name_chars (klass_name);
454 g_string_append (str, escaped);
455 g_free (escaped);
457 if (is_recursed)
458 break;
459 if (mono_class_is_ginst (klass)) {
460 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
461 MonoGenericInst *inst = gclass->context.class_inst;
462 MonoTypeNameFormat nested_format;
463 int i;
465 nested_format = format == MONO_TYPE_NAME_FORMAT_FULL_NAME ?
466 MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format;
468 if (format == MONO_TYPE_NAME_FORMAT_IL)
469 g_string_append_c (str, '<');
470 else
471 g_string_append_c (str, '[');
472 for (i = 0; i < inst->type_argc; i++) {
473 MonoType *t = inst->type_argv [i];
475 if (i)
476 g_string_append_c (str, ',');
477 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
478 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
479 g_string_append_c (str, '[');
480 mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
481 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
482 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
483 g_string_append_c (str, ']');
485 if (format == MONO_TYPE_NAME_FORMAT_IL)
486 g_string_append_c (str, '>');
487 else
488 g_string_append_c (str, ']');
489 } else if (mono_class_is_gtd (klass) &&
490 (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
491 (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
492 int i;
494 if (format == MONO_TYPE_NAME_FORMAT_IL)
495 g_string_append_c (str, '<');
496 else
497 g_string_append_c (str, '[');
498 for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) {
499 if (i)
500 g_string_append_c (str, ',');
501 g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name);
503 if (format == MONO_TYPE_NAME_FORMAT_IL)
504 g_string_append_c (str, '>');
505 else
506 g_string_append_c (str, ']');
509 mono_type_name_check_byref (type, str);
511 if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
512 (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
513 _mono_type_get_assembly_name (klass, str);
514 break;
519 * mono_type_get_name_full:
520 * \param type a type
521 * \param format the format for the return string.
524 * \returns The string representation in a number of formats:
526 * if \p format is \c MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
527 * returned in the format required by \c System.Reflection, this is the
528 * inverse of mono_reflection_parse_type().
530 * if \p format is \c MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
531 * be used by the IL assembler.
533 * if \p format is \c MONO_TYPE_NAME_FORMAT_FULL_NAME
535 * if \p format is \c MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
537 char*
538 mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
540 GString* result;
542 result = g_string_new ("");
544 mono_type_get_name_recurse (type, result, FALSE, format);
546 return g_string_free (result, FALSE);
550 * mono_type_get_full_name:
551 * \param class a class
553 * \returns The string representation for type as required by System.Reflection.
554 * The inverse of mono_reflection_parse_type().
556 char *
557 mono_type_get_full_name (MonoClass *klass)
559 return mono_type_get_name_full (m_class_get_byval_arg (klass), MONO_TYPE_NAME_FORMAT_REFLECTION);
563 * mono_type_get_name:
564 * \param type a type
565 * \returns The string representation for type as it would be represented in IL code.
567 char*
568 mono_type_get_name (MonoType *type)
570 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
574 * mono_type_get_underlying_type:
575 * \param type a type
576 * \returns The \c MonoType for the underlying integer type if \p type
577 * is an enum and byref is false, otherwise the type itself.
579 MonoType*
580 mono_type_get_underlying_type (MonoType *type)
582 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass) && !type->byref)
583 return mono_class_enum_basetype_internal (type->data.klass);
584 if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype (type->data.generic_class->container_class) && !type->byref)
585 return mono_class_enum_basetype_internal (type->data.generic_class->container_class);
586 return type;
590 * mono_class_is_open_constructed_type:
591 * \param type a type
593 * \returns TRUE if type represents a generics open constructed type.
594 * IOW, not all type parameters required for the instantiation have
595 * been provided or it's a generic type definition.
597 * An open constructed type means it's a non realizable type. Not to
598 * be mixed up with an abstract type - we can't cast or dispatch to
599 * an open type, for example.
601 gboolean
602 mono_class_is_open_constructed_type (MonoType *t)
604 switch (t->type) {
605 case MONO_TYPE_VAR:
606 case MONO_TYPE_MVAR:
607 return TRUE;
608 case MONO_TYPE_SZARRAY:
609 return mono_class_is_open_constructed_type (m_class_get_byval_arg (t->data.klass));
610 case MONO_TYPE_ARRAY:
611 return mono_class_is_open_constructed_type (m_class_get_byval_arg (t->data.array->eklass));
612 case MONO_TYPE_PTR:
613 return mono_class_is_open_constructed_type (t->data.type);
614 case MONO_TYPE_GENERICINST:
615 return t->data.generic_class->context.class_inst->is_open;
616 case MONO_TYPE_CLASS:
617 case MONO_TYPE_VALUETYPE:
618 return mono_class_is_gtd (t->data.klass);
619 default:
620 return FALSE;
625 This is a simple function to catch the most common bad instances of generic types.
626 Specially those that might lead to further failures in the runtime.
628 gboolean
629 mono_type_is_valid_generic_argument (MonoType *type)
631 switch (type->type) {
632 case MONO_TYPE_VOID:
633 case MONO_TYPE_TYPEDBYREF:
634 return FALSE;
635 case MONO_TYPE_VALUETYPE:
636 return !m_class_is_byreflike (type->data.klass);
637 default:
638 return TRUE;
642 static gboolean
643 can_inflate_gparam_with (MonoGenericParam *gparam, MonoType *type)
645 if (!mono_type_is_valid_generic_argument (type))
646 return FALSE;
647 #if FALSE
648 /* Avoid inflating gparams with valuetype constraints with ref types during gsharing */
649 MonoGenericParamInfo *info = mono_generic_param_info (gparam);
650 if (info && (info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)) {
651 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
652 MonoGenericParam *inst_gparam = type->data.generic_param;
653 if (inst_gparam->gshared_constraint && inst_gparam->gshared_constraint->type == MONO_TYPE_OBJECT)
654 return FALSE;
657 #endif
658 return TRUE;
661 static MonoType*
662 inflate_generic_custom_modifiers (MonoImage *image, const MonoType *type, MonoGenericContext *context, MonoError *error);
664 static MonoType*
665 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
667 gboolean changed = FALSE;
668 error_init (error);
670 /* C++/CLI (and some Roslyn tests) constructs method signatures like:
671 * void .CL1`1.Test(!0 modopt(System.Nullable`1<!0>))
672 * where !0 has a custom modifier which itself mentions the type variable.
673 * So we need to potentially inflate the modifiers.
675 if (type->has_cmods) {
676 MonoType *new_type = inflate_generic_custom_modifiers (image, type, context, error);
677 return_val_if_nok (error, NULL);
678 if (new_type != NULL) {
679 type = new_type;
680 changed = TRUE;
684 switch (type->type) {
685 case MONO_TYPE_MVAR: {
686 MonoType *nt;
687 int num = mono_type_get_generic_param_num (type);
688 MonoGenericInst *inst = context->method_inst;
689 if (!inst) {
690 if (!changed)
691 return NULL;
692 else
693 return type;
695 MonoGenericParam *gparam = type->data.generic_param;
696 if (num >= inst->type_argc) {
697 const char *pname = mono_generic_param_name (gparam);
698 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
699 num, pname ? pname : "", inst->type_argc);
700 return NULL;
703 if (!can_inflate_gparam_with (gparam, inst->type_argv [num])) {
704 const char *pname = mono_generic_param_name (gparam);
705 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
706 num, pname ? pname : "", inst->type_argv [num]->type);
707 return NULL;
710 * Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
711 * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
712 * ->byref and ->attrs from @type are propagated to the returned type.
714 nt = mono_metadata_type_dup_with_cmods (image, inst->type_argv [num], type);
715 nt->byref = type->byref;
716 nt->attrs = type->attrs;
717 return nt;
719 case MONO_TYPE_VAR: {
720 MonoType *nt;
721 int num = mono_type_get_generic_param_num (type);
722 MonoGenericInst *inst = context->class_inst;
723 if (!inst) {
724 if (!changed)
725 return NULL;
726 else
727 return type;
729 MonoGenericParam *gparam = type->data.generic_param;
730 if (num >= inst->type_argc) {
731 const char *pname = mono_generic_param_name (gparam);
732 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
733 num, pname ? pname : "", inst->type_argc);
734 return NULL;
736 if (!can_inflate_gparam_with (gparam, inst->type_argv [num])) {
737 const char *pname = mono_generic_param_name (gparam);
738 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
739 num, pname ? pname : "", inst->type_argv [num]->type);
740 return NULL;
743 #ifdef DEBUG_INFLATE_CMODS
744 gboolean append_cmods;
745 append_cmods = FALSE;
746 if (type->has_cmods && inst->type_argv[num]->has_cmods) {
747 char *tname = mono_type_full_name (type);
748 char *vname = mono_type_full_name (inst->type_argv[num]);
749 printf ("\n\n\tsubstitution for '%s' with '%s' yields...\n", tname, vname);
750 g_free (tname);
751 g_free (vname);
752 append_cmods = TRUE;
754 #endif
756 nt = mono_metadata_type_dup_with_cmods (image, inst->type_argv [num], type);
757 nt->byref = type->byref || inst->type_argv[num]->byref;
758 nt->attrs = type->attrs;
759 #ifdef DEBUG_INFLATE_CMODS
760 if (append_cmods) {
761 char *ntname = mono_type_full_name (nt);
762 printf ("\tyields '%s'\n\n\n", ntname);
763 g_free (ntname);
765 #endif
766 return nt;
768 case MONO_TYPE_SZARRAY: {
769 MonoClass *eclass = type->data.klass;
770 MonoType *nt, *inflated = inflate_generic_type (NULL, m_class_get_byval_arg (eclass), context, error);
771 if ((!inflated && !changed) || !is_ok (error))
772 return NULL;
773 if (!inflated)
774 return type;
775 nt = mono_metadata_type_dup (image, type);
776 nt->data.klass = mono_class_from_mono_type_internal (inflated);
777 mono_metadata_free_type (inflated);
778 return nt;
780 case MONO_TYPE_ARRAY: {
781 MonoClass *eclass = type->data.array->eklass;
782 MonoType *nt, *inflated = inflate_generic_type (NULL, m_class_get_byval_arg (eclass), context, error);
783 if ((!inflated && !changed) || !is_ok (error))
784 return NULL;
785 if (!inflated)
786 return type;
787 nt = mono_metadata_type_dup (image, type);
788 nt->data.array->eklass = mono_class_from_mono_type_internal (inflated);
789 mono_metadata_free_type (inflated);
790 return nt;
792 case MONO_TYPE_GENERICINST: {
793 MonoGenericClass *gclass = type->data.generic_class;
794 MonoGenericInst *inst;
795 MonoType *nt;
796 if (!gclass->context.class_inst->is_open) {
797 if (!changed)
798 return NULL;
799 else
800 return type;
803 inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
804 return_val_if_nok (error, NULL);
806 if (inst != gclass->context.class_inst)
807 gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
809 if (gclass == type->data.generic_class) {
810 if (!changed)
811 return NULL;
812 else
813 return type;
816 nt = mono_metadata_type_dup (image, type);
817 nt->data.generic_class = gclass;
818 return nt;
820 case MONO_TYPE_CLASS:
821 case MONO_TYPE_VALUETYPE: {
822 MonoClass *klass = type->data.klass;
823 MonoGenericContainer *container = mono_class_try_get_generic_container (klass);
824 MonoGenericInst *inst;
825 MonoGenericClass *gclass = NULL;
826 MonoType *nt;
828 if (!container) {
829 if (!changed)
830 return NULL;
831 else
832 return type;
835 /* We can't use context->class_inst directly, since it can have more elements */
836 inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
837 return_val_if_nok (error, NULL);
839 if (inst == container->context.class_inst) {
840 if (!changed)
841 return NULL;
842 else
843 return type;
846 gclass = mono_metadata_lookup_generic_class (klass, inst, image_is_dynamic (m_class_get_image (klass)));
848 nt = mono_metadata_type_dup (image, type);
849 nt->type = MONO_TYPE_GENERICINST;
850 nt->data.generic_class = gclass;
851 return nt;
853 case MONO_TYPE_PTR: {
854 MonoType *nt, *inflated = inflate_generic_type (image, type->data.type, context, error);
855 if ((!inflated && !changed) || !is_ok (error))
856 return NULL;
857 if (!inflated && changed)
858 return type;
859 nt = mono_metadata_type_dup (image, type);
860 nt->data.type = inflated;
861 return nt;
863 default:
864 if (!changed)
865 return NULL;
866 else
867 return type;
869 return NULL;
872 static MonoType*
873 inflate_generic_custom_modifiers (MonoImage *image, const MonoType *type, MonoGenericContext *context, MonoError *error)
875 MonoType *result = NULL;
876 g_assert (type->has_cmods);
877 int count = mono_type_custom_modifier_count (type);
878 gboolean changed = FALSE;
880 /* Try not to blow up the stack. See comment on MONO_MAX_EXPECTED_CMODS. */
881 g_assert (count < MONO_MAX_EXPECTED_CMODS);
882 size_t aggregate_size = mono_sizeof_aggregate_modifiers (count);
883 MonoAggregateModContainer *candidate_mods = g_alloca (aggregate_size);
884 memset (candidate_mods, 0, aggregate_size);
885 candidate_mods->count = count;
887 for (int i = 0; i < count; ++i) {
888 gboolean required;
889 MonoType *cmod_old = mono_type_get_custom_modifier (type, i, &required, error);
890 goto_if_nok (error, leave);
891 MonoType *cmod_new = inflate_generic_type (NULL, cmod_old, context, error);
892 goto_if_nok (error, leave);
893 if (cmod_new)
894 changed = TRUE;
895 candidate_mods->modifiers [i].required = required;
896 candidate_mods->modifiers [i].type = cmod_new;
899 if (changed) {
900 /* 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. */
901 for (int i = 0; i < count; ++i) {
902 if (candidate_mods->modifiers [i].type == NULL) {
903 candidate_mods->modifiers [i].type = mono_metadata_type_dup (NULL, mono_type_get_custom_modifier (type, i, NULL, error));
905 /* it didn't error in the first loop, so should be ok now, too */
906 mono_error_assert_ok (error);
910 #ifdef DEBUG_INFLATE_CMODS
911 if (changed) {
912 char *full_name = mono_type_full_name ((MonoType*)type);
913 printf ("\n\n\tcustom modifier on '%s' affected by subsititution\n\n\n", full_name);
914 g_free (full_name);
916 #endif
917 if (changed) {
918 MonoType *new_type = g_alloca (mono_sizeof_type_with_mods (count, TRUE));
919 /* first init just the non-modifier portion of new_type before populating the
920 * new modifiers */
921 memcpy (new_type, type, MONO_SIZEOF_TYPE);
922 mono_type_with_mods_init (new_type, count, TRUE);
923 mono_type_set_amods (new_type, mono_metadata_get_canonical_aggregate_modifiers (candidate_mods));
924 result = mono_metadata_type_dup (image, new_type);
927 leave:
928 for (int i = 0; i < count; ++i) {
929 if (candidate_mods->modifiers [i].type)
930 mono_metadata_free_type (candidate_mods->modifiers [i].type);
933 return result;
936 MonoGenericContext *
937 mono_generic_class_get_context (MonoGenericClass *gclass)
939 return &gclass->context;
942 MonoGenericContext *
943 mono_class_get_context (MonoClass *klass)
945 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
946 return gklass ? mono_generic_class_get_context (gklass) : NULL;
950 * mono_class_inflate_generic_type_with_mempool:
951 * @mempool: a mempool
952 * @type: a type
953 * @context: a generics context
954 * @error: error context
956 * The same as mono_class_inflate_generic_type, but allocates the MonoType
957 * from mempool if it is non-NULL. If it is NULL, the MonoType is
958 * allocated on the heap and is owned by the caller.
959 * The returned type can potentially be the same as TYPE, so it should not be
960 * modified by the caller, and it should be freed using mono_metadata_free_type ().
962 MonoType*
963 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
965 MonoType *inflated = NULL;
966 error_init (error);
968 if (context)
969 inflated = inflate_generic_type (image, type, context, error);
970 return_val_if_nok (error, NULL);
972 if (!inflated) {
973 MonoType *shared = mono_metadata_get_shared_type (type);
975 if (shared && !type->has_cmods) {
976 return shared;
977 } else {
978 return mono_metadata_type_dup (image, type);
982 UnlockedIncrement (&mono_stats.inflated_type_count);
983 return inflated;
987 * mono_class_inflate_generic_type:
988 * \param type a type
989 * \param context a generics context
990 * \deprecated Please use \c mono_class_inflate_generic_type_checked instead
992 * If \p type is a generic type and \p context is not NULL, instantiate it using the
993 * generics context \p context.
995 * \returns The instantiated type or a copy of \p type. The returned \c MonoType is allocated
996 * on the heap and is owned by the caller. Returns NULL on error.
998 MonoType*
999 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
1001 ERROR_DECL (error);
1002 MonoType *result;
1003 result = mono_class_inflate_generic_type_checked (type, context, error);
1004 mono_error_cleanup (error);
1005 return result;
1009 * mono_class_inflate_generic_type:
1010 * @type: a type
1011 * @context: a generics context
1012 * @error: error context to use
1014 * If @type is a generic type and @context is not NULL, instantiate it using the
1015 * generics context @context.
1017 * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
1018 * on the heap and is owned by the caller.
1020 MonoType*
1021 mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
1023 return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
1027 * mono_class_inflate_generic_type_no_copy:
1029 * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
1030 * was done.
1032 static MonoType*
1033 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
1035 MonoType *inflated = NULL;
1037 error_init (error);
1038 if (context) {
1039 inflated = inflate_generic_type (image, type, context, error);
1040 return_val_if_nok (error, NULL);
1043 if (!inflated)
1044 return type;
1046 UnlockedIncrement (&mono_stats.inflated_type_count);
1047 return inflated;
1051 * mono_class_inflate_generic_class:
1053 * Inflate the class @gklass with @context. Set @error on failure.
1055 MonoClass*
1056 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
1058 MonoClass *res;
1059 MonoType *inflated;
1061 inflated = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (gklass), context, error);
1062 return_val_if_nok (error, NULL);
1064 res = mono_class_from_mono_type_internal (inflated);
1065 mono_metadata_free_type (inflated);
1067 return res;
1070 static MonoGenericContext
1071 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
1073 MonoGenericInst *class_inst = NULL;
1074 MonoGenericInst *method_inst = NULL;
1075 MonoGenericContext res = { NULL, NULL };
1077 error_init (error);
1079 if (context->class_inst) {
1080 class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
1081 if (!is_ok (error))
1082 goto fail;
1085 if (context->method_inst) {
1086 method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with, error);
1087 if (!is_ok (error))
1088 goto fail;
1091 res.class_inst = class_inst;
1092 res.method_inst = method_inst;
1093 fail:
1094 return res;
1098 * mono_class_inflate_generic_method:
1099 * \param method a generic method
1100 * \param context a generics context
1102 * Instantiate the generic method \p method using the generics context \p context.
1104 * \returns The new instantiated method
1106 MonoMethod *
1107 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
1109 ERROR_DECL (error);
1110 MonoMethod *res = mono_class_inflate_generic_method_full_checked (method, NULL, context, error);
1111 mono_error_assert_msg_ok (error, "Could not inflate generic method");
1112 return res;
1115 MonoMethod *
1116 mono_class_inflate_generic_method_checked (MonoMethod *method, MonoGenericContext *context, MonoError *error)
1118 return mono_class_inflate_generic_method_full_checked (method, NULL, context, error);
1122 * mono_class_inflate_generic_method_full_checked:
1123 * Instantiate method \p method with the generic context \p context.
1124 * On failure returns NULL and sets \p error.
1126 * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
1127 * Use mono_method_signature_internal () and mono_method_get_header () to get the correct values.
1129 MonoMethod*
1130 mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error)
1132 MonoMethod *result;
1133 MonoMethodInflated *iresult, *cached;
1134 MonoMethodSignature *sig;
1135 MonoGenericContext tmp_context;
1137 error_init (error);
1139 /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
1140 while (method->is_inflated) {
1141 MonoGenericContext *method_context = mono_method_get_context (method);
1142 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1144 tmp_context = inflate_generic_context (method_context, context, error);
1145 return_val_if_nok (error, NULL);
1147 context = &tmp_context;
1149 if (mono_metadata_generic_context_equal (method_context, context))
1150 return method;
1152 method = imethod->declaring;
1156 * A method only needs to be inflated if the context has argument for which it is
1157 * parametric. Eg:
1159 * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
1160 * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
1163 if (!((method->is_generic && context->method_inst) ||
1164 (mono_class_is_gtd (method->klass) && context->class_inst)))
1165 return method;
1167 iresult = g_new0 (MonoMethodInflated, 1);
1168 iresult->context = *context;
1169 iresult->declaring = method;
1171 if (!context->method_inst && method->is_generic)
1172 iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
1174 if (!context->class_inst) {
1175 g_assert (!mono_class_is_ginst (iresult->declaring->klass));
1176 if (mono_class_is_gtd (iresult->declaring->klass))
1177 iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst;
1179 /* This can happen with some callers like mono_object_get_virtual_method_internal () */
1180 if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass))
1181 iresult->context.class_inst = NULL;
1183 MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
1185 // check cache
1186 mono_image_set_lock (set);
1187 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1188 mono_image_set_unlock (set);
1190 if (cached) {
1191 g_free (iresult);
1192 return (MonoMethod*)cached;
1195 UnlockedIncrement (&mono_stats.inflated_method_count);
1197 UnlockedAdd (&mono_inflated_methods_size, sizeof (MonoMethodInflated));
1199 sig = mono_method_signature_internal (method);
1200 if (!sig) {
1201 char *name = mono_type_get_full_name (method->klass);
1202 mono_error_set_bad_image (error, mono_method_get_image (method), "Could not resolve signature of method %s:%s", name, method->name);
1203 g_free (name);
1204 goto fail;
1207 if (sig->pinvoke) {
1208 memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
1209 } else {
1210 memcpy (&iresult->method.method, method, sizeof (MonoMethod));
1213 result = (MonoMethod *) iresult;
1214 result->is_inflated = TRUE;
1215 result->is_generic = FALSE;
1216 result->sre_method = FALSE;
1217 result->signature = NULL;
1219 if (method->wrapper_type) {
1220 MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
1221 MonoMethodWrapper *resw = (MonoMethodWrapper*)result;
1222 int len = GPOINTER_TO_INT (((void**)mw->method_data) [0]);
1224 resw->method_data = (void **)g_malloc (sizeof (gpointer) * (len + 1));
1225 memcpy (resw->method_data, mw->method_data, sizeof (gpointer) * (len + 1));
1228 if (iresult->context.method_inst) {
1229 MonoGenericInst *method_inst = iresult->context.method_inst;
1230 /* Set the generic_container of the result to the generic_container of method */
1231 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
1233 if (generic_container && method_inst == generic_container->context.method_inst) {
1234 result->is_generic = 1;
1235 mono_method_set_generic_container (result, generic_container);
1238 /* Check that the method is not instantiated with any invalid types */
1239 for (int i = 0; i < method_inst->type_argc; i++) {
1240 if (!mono_type_is_valid_generic_argument (method_inst->type_argv [i])) {
1241 mono_error_set_bad_image (error, mono_method_get_image (method), "MVAR %d cannot be expanded with type 0x%x",
1242 i, method_inst->type_argv [i]->type);
1243 goto fail;
1248 if (klass_hint) {
1249 MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint);
1250 if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst))
1251 klass_hint = NULL;
1254 if (mono_class_is_gtd (method->klass))
1255 result->klass = klass_hint;
1257 if (!result->klass) {
1258 MonoType *inflated = inflate_generic_type (NULL, m_class_get_byval_arg (method->klass), context, error);
1259 if (!is_ok (error))
1260 goto fail;
1262 result->klass = inflated ? mono_class_from_mono_type_internal (inflated) : method->klass;
1263 if (inflated)
1264 mono_metadata_free_type (inflated);
1268 * FIXME: This should hold, but it doesn't:
1270 * if (result->is_inflated && mono_method_get_context (result)->method_inst &&
1271 * mono_method_get_context (result)->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)result)->declaring)->context.method_inst) {
1272 * g_assert (result->is_generic);
1275 * Fixing this here causes other things to break, hence a very
1276 * ugly hack in mini-trampolines.c - see
1277 * is_generic_method_definition().
1280 // check cache
1281 mono_image_set_lock (set);
1282 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1283 if (!cached) {
1284 g_hash_table_insert (set->gmethod_cache, iresult, iresult);
1285 iresult->owner = set;
1286 cached = iresult;
1288 mono_image_set_unlock (set);
1290 return (MonoMethod*)cached;
1292 fail:
1293 g_free (iresult);
1294 return NULL;
1298 * mono_get_inflated_method:
1300 * Obsolete. We keep it around since it's mentioned in the public API.
1302 MonoMethod*
1303 mono_get_inflated_method (MonoMethod *method)
1305 return method;
1309 * mono_method_get_context_general:
1310 * @method: a method
1311 * @uninflated: handle uninflated methods?
1313 * Returns the generic context of a method or NULL if it doesn't have
1314 * one. For an inflated method that's the context stored in the
1315 * method. Otherwise it's in the method's generic container or in the
1316 * generic container of the method's class.
1318 MonoGenericContext*
1319 mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
1321 if (method->is_inflated) {
1322 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1323 return &imethod->context;
1325 if (!uninflated)
1326 return NULL;
1327 if (method->is_generic)
1328 return &(mono_method_get_generic_container (method)->context);
1329 if (mono_class_is_gtd (method->klass))
1330 return &mono_class_get_generic_container (method->klass)->context;
1331 return NULL;
1335 * mono_method_get_context:
1336 * @method: a method
1338 * Returns the generic context for method if it's inflated, otherwise
1339 * NULL.
1341 MonoGenericContext*
1342 mono_method_get_context (MonoMethod *method)
1344 return mono_method_get_context_general (method, FALSE);
1348 * mono_method_get_generic_container:
1350 * Returns the generic container of METHOD, which should be a generic method definition.
1351 * Returns NULL if METHOD is not a generic method definition.
1352 * LOCKING: Acquires the loader lock.
1354 MonoGenericContainer*
1355 mono_method_get_generic_container (MonoMethod *method)
1357 MonoGenericContainer *container;
1359 if (!method->is_generic)
1360 return NULL;
1362 container = (MonoGenericContainer *)mono_image_property_lookup (mono_method_get_image (method), method, MONO_METHOD_PROP_GENERIC_CONTAINER);
1363 g_assert (container);
1365 return container;
1369 * mono_method_set_generic_container:
1371 * Sets the generic container of METHOD to CONTAINER.
1372 * LOCKING: Acquires the image lock.
1374 void
1375 mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
1377 g_assert (method->is_generic);
1379 mono_image_property_insert (mono_method_get_image (method), method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
1382 /**
1383 * mono_class_find_enum_basetype:
1384 * \param class The enum class
1386 * Determine the basetype of an enum by iterating through its fields. We do this
1387 * in a separate function since it is cheaper than calling mono_class_setup_fields.
1389 MonoType*
1390 mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
1392 MonoGenericContainer *container = NULL;
1393 MonoImage *image = m_class_get_image (klass);
1394 const int top = mono_class_get_field_count (klass);
1395 int i, first_field_idx;
1397 g_assert (m_class_is_enumtype (klass));
1399 error_init (error);
1401 container = mono_class_try_get_generic_container (klass);
1402 if (mono_class_is_ginst (klass)) {
1403 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1405 container = mono_class_get_generic_container (gklass);
1406 g_assert (container);
1410 * Fetch all the field information.
1412 first_field_idx = mono_class_get_first_field_idx (klass);
1413 for (i = 0; i < top; i++){
1414 const char *sig;
1415 guint32 cols [MONO_FIELD_SIZE];
1416 int idx = first_field_idx + i;
1417 MonoType *ftype;
1419 /* first_field_idx and idx points into the fieldptr table */
1420 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
1422 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
1423 continue;
1425 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], error))
1426 goto fail;
1428 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
1429 mono_metadata_decode_value (sig, &sig);
1430 /* FIELD signature == 0x06 */
1431 if (*sig != 0x06) {
1432 mono_error_set_bad_image (error, image, "Invalid field signature %x, expected 0x6 but got %x", cols [MONO_FIELD_SIGNATURE], *sig);
1433 goto fail;
1436 ftype = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
1437 if (!ftype)
1438 goto fail;
1440 if (mono_class_is_ginst (klass)) {
1441 //FIXME do we leak here?
1442 ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error);
1443 if (!is_ok (error))
1444 goto fail;
1445 ftype->attrs = cols [MONO_FIELD_FLAGS];
1448 return ftype;
1450 mono_error_set_type_load_class (error, klass, "Could not find base type");
1452 fail:
1453 return NULL;
1457 * Checks for MonoClass::has_failure without resolving all MonoType's into MonoClass'es
1459 gboolean
1460 mono_type_has_exceptions (MonoType *type)
1462 switch (type->type) {
1463 case MONO_TYPE_CLASS:
1464 case MONO_TYPE_VALUETYPE:
1465 case MONO_TYPE_SZARRAY:
1466 return mono_class_has_failure (type->data.klass);
1467 case MONO_TYPE_ARRAY:
1468 return mono_class_has_failure (type->data.array->eklass);
1469 case MONO_TYPE_GENERICINST:
1470 return mono_class_has_failure (mono_class_create_generic_inst (type->data.generic_class));
1471 default:
1472 return FALSE;
1476 void
1477 mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
1479 g_assert (mono_class_has_failure (klass));
1480 MonoErrorBoxed *box = mono_class_get_exception_data ((MonoClass*)klass);
1481 mono_error_set_from_boxed (oerror, box);
1485 * mono_class_alloc:
1487 * Allocate memory for some data belonging to CLASS, either from its image's mempool,
1488 * or from the heap.
1490 gpointer
1491 mono_class_alloc (MonoClass *klass, int size)
1493 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1494 if (gklass)
1495 return mono_image_set_alloc (gklass->owner, size);
1496 else
1497 return mono_image_alloc (m_class_get_image (klass), size);
1500 gpointer
1501 (mono_class_alloc0) (MonoClass *klass, int size)
1503 gpointer res;
1505 res = mono_class_alloc (klass, size);
1506 memset (res, 0, size);
1507 return res;
1510 #define mono_class_new0(klass,struct_type, n_structs) \
1511 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
1514 * mono_class_set_failure_causedby_class:
1515 * \param klass the class that is failing
1516 * \param caused_by the class that caused the failure
1517 * \param msg Why \p klass is failing.
1519 * If \p caused_by has a failure, sets a TypeLoadException failure on
1520 * \p klass with message "\p msg, due to: {\p caused_by message}".
1522 * \returns TRUE if a failiure was set, or FALSE if \p caused_by doesn't have a failure.
1524 gboolean
1525 mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg)
1527 if (mono_class_has_failure (caused_by)) {
1528 ERROR_DECL (cause_error);
1529 mono_error_set_for_class_failure (cause_error, caused_by);
1530 mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (cause_error));
1531 mono_error_cleanup (cause_error);
1532 return TRUE;
1533 } else {
1534 return FALSE;
1540 * mono_type_get_basic_type_from_generic:
1541 * @type: a type
1543 * Returns a closed type corresponding to the possibly open type
1544 * passed to it.
1546 MonoType*
1547 mono_type_get_basic_type_from_generic (MonoType *type)
1549 /* When we do generic sharing we let type variables stand for reference/primitive types. */
1550 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) &&
1551 (!type->data.generic_param->gshared_constraint || type->data.generic_param->gshared_constraint->type == MONO_TYPE_OBJECT))
1552 return mono_get_object_type ();
1553 return type;
1557 * mono_class_get_method_by_index:
1559 * Returns klass->methods [index], initializing klass->methods if neccesary.
1561 * LOCKING: Acquires the loader lock.
1563 MonoMethod*
1564 mono_class_get_method_by_index (MonoClass *klass, int index)
1566 ERROR_DECL (error);
1568 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1569 /* Avoid calling setup_methods () if possible */
1570 if (gklass && !m_class_get_methods (klass)) {
1571 MonoMethod *m;
1573 m = mono_class_inflate_generic_method_full_checked (
1574 m_class_get_methods (gklass->container_class) [index], klass, mono_class_get_context (klass), error);
1575 g_assert (is_ok (error)); /* FIXME don't swallow the error */
1577 * If setup_methods () is called later for this class, no duplicates are created,
1578 * since inflate_generic_method guarantees that only one instance of a method
1579 * is created for each context.
1582 mono_class_setup_methods (klass);
1583 g_assert (m == klass->methods [index]);
1585 return m;
1586 } else {
1587 mono_class_setup_methods (klass);
1588 if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
1589 return NULL;
1590 g_assert (index >= 0 && index < mono_class_get_method_count (klass));
1591 return m_class_get_methods (klass) [index];
1596 * mono_class_get_inflated_method:
1597 * \param klass an inflated class
1598 * \param method a method of \p klass's generic definition
1599 * \param error set on error
1601 * Given an inflated class \p klass and a method \p method which should be a
1602 * method of \p klass's generic definition, return the inflated method
1603 * corresponding to \p method.
1605 * On failure sets \p error and returns NULL.
1607 MonoMethod*
1608 mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method, MonoError *error)
1610 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1611 int i, mcount;
1613 g_assert (method->klass == gklass);
1615 mono_class_setup_methods (gklass);
1616 if (mono_class_has_failure (gklass)) {
1617 mono_error_set_for_class_failure (error, gklass);
1618 return NULL;
1621 MonoMethod **gklass_methods = m_class_get_methods (gklass);
1622 mcount = mono_class_get_method_count (gklass);
1623 for (i = 0; i < mcount; ++i) {
1624 if (gklass_methods [i] == method) {
1625 MonoMethod *inflated_method = NULL;
1626 MonoMethod **klass_methods = m_class_get_methods (klass);
1627 if (klass_methods) {
1628 inflated_method = klass_methods [i];
1629 } else {
1630 inflated_method = mono_class_inflate_generic_method_full_checked (gklass_methods [i], klass, mono_class_get_context (klass), error);
1631 return_val_if_nok (error, NULL);
1633 g_assert (inflated_method);
1634 return inflated_method;
1638 g_assert_not_reached ();
1642 * mono_class_get_vtable_entry:
1644 * Returns klass->vtable [offset], computing it if neccesary. Returns NULL on failure.
1645 * LOCKING: Acquires the loader lock.
1647 MonoMethod*
1648 mono_class_get_vtable_entry (MonoClass *klass, int offset)
1650 MonoMethod *m;
1652 if (m_class_get_rank (klass) == 1) {
1653 MonoClass *klass_parent = m_class_get_parent (klass);
1655 * szarrays do not overwrite any methods of Array, so we can avoid
1656 * initializing their vtables in some cases.
1658 mono_class_setup_vtable (klass_parent);
1659 if (offset < m_class_get_vtable_size (klass_parent))
1660 return m_class_get_vtable (klass_parent) [offset];
1663 if (mono_class_is_ginst (klass)) {
1664 ERROR_DECL (error);
1665 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1666 mono_class_setup_vtable (gklass);
1667 m = m_class_get_vtable (gklass) [offset];
1669 m = mono_class_inflate_generic_method_full_checked (m, klass, mono_class_get_context (klass), error);
1670 g_assert (is_ok (error)); /* FIXME don't swallow this error */
1671 } else {
1672 mono_class_setup_vtable (klass);
1673 if (mono_class_has_failure (klass))
1674 return NULL;
1675 m = m_class_get_vtable (klass) [offset];
1678 return m;
1682 * mono_class_get_vtable_size:
1684 * Return the vtable size for KLASS.
1687 mono_class_get_vtable_size (MonoClass *klass)
1689 mono_class_setup_vtable (klass);
1691 return m_class_get_vtable_size (klass);
1694 static void
1695 collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, GHashTable **ifaces, MonoError *error)
1697 int i;
1698 MonoClass *ic;
1700 mono_class_setup_interfaces (klass, error);
1701 return_if_nok (error);
1703 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
1704 for (i = 0; i < m_class_get_interface_count (klass); i++) {
1705 ic = klass_interfaces [i];
1707 if (*res == NULL)
1708 *res = g_ptr_array_new ();
1709 if (*ifaces == NULL)
1710 *ifaces = g_hash_table_new (NULL, NULL);
1711 if (g_hash_table_lookup (*ifaces, ic))
1712 continue;
1713 /* A gparam is not an implemented interface for the purposes of
1714 * mono_class_get_implemented_interfaces */
1715 if (mono_class_is_gparam (ic))
1716 continue;
1717 g_ptr_array_add (*res, ic);
1718 g_hash_table_insert (*ifaces, ic, ic);
1719 mono_class_init_internal (ic);
1720 if (mono_class_has_failure (ic)) {
1721 mono_error_set_type_load_class (error, ic, "Error Loading class");
1722 return;
1725 collect_implemented_interfaces_aux (ic, res, ifaces, error);
1726 return_if_nok (error);
1730 GPtrArray*
1731 mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error)
1733 GPtrArray *res = NULL;
1734 GHashTable *ifaces = NULL;
1736 collect_implemented_interfaces_aux (klass, &res, &ifaces, error);
1737 if (ifaces)
1738 g_hash_table_destroy (ifaces);
1739 if (!is_ok (error)) {
1740 if (res)
1741 g_ptr_array_free (res, TRUE);
1742 return NULL;
1744 return res;
1747 /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/
1749 mono_class_interface_offset (MonoClass *klass, MonoClass *itf)
1751 int i;
1752 MonoClass **klass_interfaces_packed = m_class_get_interfaces_packed (klass);
1753 for (i = m_class_get_interface_offsets_count (klass) -1 ; i >= 0 ; i-- ){
1754 MonoClass *result = klass_interfaces_packed[i];
1755 if (m_class_get_interface_id(result) == m_class_get_interface_id(itf)) {
1756 return m_class_get_interface_offsets_packed (klass) [i];
1759 return -1;
1763 * mono_class_interface_offset_with_variance:
1765 * Return the interface offset of \p itf in \p klass. Sets \p non_exact_match to TRUE if the match required variance check
1766 * If \p itf is an interface with generic variant arguments, try to find the compatible one.
1768 * Note that this function is responsible for resolving ambiguities. Right now we use whatever ordering interfaces_packed gives us.
1770 * FIXME figure out MS disambiguation rules and fix this function.
1773 mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match)
1775 int i = mono_class_interface_offset (klass, itf);
1776 *non_exact_match = FALSE;
1777 if (i >= 0)
1778 return i;
1780 int klass_interface_offsets_count = m_class_get_interface_offsets_count (klass);
1782 if (m_class_is_array_special_interface (itf) && m_class_get_rank (klass) < 2) {
1783 MonoClass *gtd = mono_class_get_generic_type_definition (itf);
1784 int found = -1;
1786 for (i = 0; i < klass_interface_offsets_count; i++) {
1787 if (mono_class_is_variant_compatible (itf, m_class_get_interfaces_packed (klass) [i], FALSE)) {
1788 found = i;
1789 *non_exact_match = TRUE;
1790 break;
1794 if (found != -1)
1795 return m_class_get_interface_offsets_packed (klass) [found];
1797 for (i = 0; i < klass_interface_offsets_count; i++) {
1798 if (mono_class_get_generic_type_definition (m_class_get_interfaces_packed (klass) [i]) == gtd) {
1799 found = i;
1800 *non_exact_match = TRUE;
1801 break;
1805 if (found == -1)
1806 return -1;
1808 return m_class_get_interface_offsets_packed (klass) [found];
1811 if (!mono_class_has_variant_generic_params (itf))
1812 return -1;
1814 for (i = 0; i < klass_interface_offsets_count; i++) {
1815 if (mono_class_is_variant_compatible (itf, m_class_get_interfaces_packed (klass) [i], FALSE)) {
1816 *non_exact_match = TRUE;
1817 return m_class_get_interface_offsets_packed (klass) [i];
1821 return -1;
1826 * mono_method_get_vtable_slot:
1828 * Returns method->slot, computing it if neccesary. Return -1 on failure.
1829 * LOCKING: Acquires the loader lock.
1831 * FIXME Use proper MonoError machinery here.
1834 mono_method_get_vtable_slot (MonoMethod *method)
1836 if (method->slot == -1) {
1837 mono_class_setup_vtable (method->klass);
1838 if (mono_class_has_failure (method->klass))
1839 return -1;
1840 if (method->slot == -1) {
1841 MonoClass *gklass;
1842 int i, mcount;
1844 if (!mono_class_is_ginst (method->klass)) {
1845 g_assert (method->is_inflated);
1846 return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
1849 /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
1850 g_assert (mono_class_is_ginst (method->klass));
1851 gklass = mono_class_get_generic_class (method->klass)->container_class;
1852 mono_class_setup_methods (method->klass);
1853 MonoMethod **klass_methods = m_class_get_methods (method->klass);
1854 g_assert (klass_methods);
1855 mcount = mono_class_get_method_count (method->klass);
1856 for (i = 0; i < mcount; ++i) {
1857 if (klass_methods [i] == method)
1858 break;
1860 g_assert (i < mcount);
1861 g_assert (m_class_get_methods (gklass));
1862 method->slot = m_class_get_methods (gklass) [i]->slot;
1864 g_assert (method->slot != -1);
1866 return method->slot;
1870 * mono_method_get_vtable_index:
1871 * \param method a method
1873 * Returns the index into the runtime vtable to access the method or,
1874 * in the case of a virtual generic method, the virtual generic method
1875 * thunk. Returns -1 on failure.
1877 * FIXME Use proper MonoError machinery here.
1880 mono_method_get_vtable_index (MonoMethod *method)
1882 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
1883 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
1884 if (imethod->declaring->is_generic)
1885 return mono_method_get_vtable_slot (imethod->declaring);
1887 return mono_method_get_vtable_slot (method);
1891 * mono_class_has_finalizer:
1893 * Return whenever KLASS has a finalizer, initializing klass->has_finalizer in the
1894 * process.
1896 * LOCKING: Acquires the loader lock;
1898 gboolean
1899 mono_class_has_finalizer (MonoClass *klass)
1901 if (!m_class_is_has_finalize_inited (klass))
1902 mono_class_setup_has_finalizer (klass);
1904 return m_class_has_finalize (klass);
1907 gboolean
1908 mono_is_corlib_image (MonoImage *image)
1910 return image == mono_defaults.corlib;
1914 /** Is klass a Nullable<T> ginst? */
1915 gboolean
1916 mono_class_is_nullable (MonoClass *klass)
1918 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1919 return gklass && gklass->container_class == mono_defaults.generic_nullable_class;
1922 /** if klass is T? return T */
1923 MonoClass*
1924 mono_class_get_nullable_param_internal (MonoClass *klass)
1926 g_assert (mono_class_is_nullable (klass));
1927 return mono_class_from_mono_type_internal (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
1930 MonoClass*
1931 mono_class_get_nullable_param (MonoClass *klass)
1933 MonoClass *result = NULL;
1934 MONO_ENTER_GC_UNSAFE;
1935 result = mono_class_get_nullable_param_internal (klass);
1936 MONO_EXIT_GC_UNSAFE;
1937 return result;
1940 gboolean
1941 mono_type_is_primitive (MonoType *type)
1943 return (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_R8) ||
1944 type-> type == MONO_TYPE_I || type->type == MONO_TYPE_U;
1947 static MonoImage *
1948 get_image_for_container (MonoGenericContainer *container)
1950 MonoImage *result;
1951 if (container->is_anonymous) {
1952 result = container->owner.image;
1953 } else {
1954 MonoClass *klass;
1955 if (container->is_method) {
1956 MonoMethod *method = container->owner.method;
1957 g_assert_checked (method);
1958 klass = method->klass;
1959 } else {
1960 klass = container->owner.klass;
1962 g_assert_checked (klass);
1963 result = m_class_get_image (klass);
1965 g_assert (result);
1966 return result;
1969 MonoImage *
1970 mono_get_image_for_generic_param (MonoGenericParam *param)
1972 MonoGenericContainer *container = mono_generic_param_owner (param);
1973 g_assert_checked (container);
1974 return get_image_for_container (container);
1977 // Make a string in the designated image consisting of a single integer.
1978 #define INT_STRING_SIZE 16
1979 char *
1980 mono_make_generic_name_string (MonoImage *image, int num)
1982 char *name = (char *)mono_image_alloc0 (image, INT_STRING_SIZE);
1983 g_snprintf (name, INT_STRING_SIZE, "%d", num);
1984 return name;
1988 * mono_class_from_generic_parameter:
1989 * \param param Parameter to find/construct a class for.
1990 * \param arg2 Is ignored.
1991 * \param arg3 Is ignored.
1993 MonoClass *
1994 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GNUC_UNUSED, gboolean arg3 G_GNUC_UNUSED)
1996 return mono_class_create_generic_parameter (param);
2000 * mono_ptr_class_get:
2002 MonoClass *
2003 mono_ptr_class_get (MonoType *type)
2005 return mono_class_create_ptr (type);
2009 * mono_class_from_mono_type:
2010 * \param type describes the type to return
2011 * \returns a \c MonoClass for the specified \c MonoType, the value is never NULL.
2013 MonoClass *
2014 mono_class_from_mono_type (MonoType *type)
2016 MonoClass *result;
2017 MONO_ENTER_GC_UNSAFE;
2018 result = mono_class_from_mono_type_internal (type);
2019 MONO_EXIT_GC_UNSAFE;
2020 return result;
2023 MonoClass *
2024 mono_class_from_mono_type_internal (MonoType *type)
2026 g_assert (type);
2027 switch (type->type) {
2028 case MONO_TYPE_OBJECT:
2029 return type->data.klass? type->data.klass: mono_defaults.object_class;
2030 case MONO_TYPE_VOID:
2031 return type->data.klass? type->data.klass: mono_defaults.void_class;
2032 case MONO_TYPE_BOOLEAN:
2033 return type->data.klass? type->data.klass: mono_defaults.boolean_class;
2034 case MONO_TYPE_CHAR:
2035 return type->data.klass? type->data.klass: mono_defaults.char_class;
2036 case MONO_TYPE_I1:
2037 return type->data.klass? type->data.klass: mono_defaults.sbyte_class;
2038 case MONO_TYPE_U1:
2039 return type->data.klass? type->data.klass: mono_defaults.byte_class;
2040 case MONO_TYPE_I2:
2041 return type->data.klass? type->data.klass: mono_defaults.int16_class;
2042 case MONO_TYPE_U2:
2043 return type->data.klass? type->data.klass: mono_defaults.uint16_class;
2044 case MONO_TYPE_I4:
2045 return type->data.klass? type->data.klass: mono_defaults.int32_class;
2046 case MONO_TYPE_U4:
2047 return type->data.klass? type->data.klass: mono_defaults.uint32_class;
2048 case MONO_TYPE_I:
2049 return type->data.klass? type->data.klass: mono_defaults.int_class;
2050 case MONO_TYPE_U:
2051 return type->data.klass? type->data.klass: mono_defaults.uint_class;
2052 case MONO_TYPE_I8:
2053 return type->data.klass? type->data.klass: mono_defaults.int64_class;
2054 case MONO_TYPE_U8:
2055 return type->data.klass? type->data.klass: mono_defaults.uint64_class;
2056 case MONO_TYPE_R4:
2057 return type->data.klass? type->data.klass: mono_defaults.single_class;
2058 case MONO_TYPE_R8:
2059 return type->data.klass? type->data.klass: mono_defaults.double_class;
2060 case MONO_TYPE_STRING:
2061 return type->data.klass? type->data.klass: mono_defaults.string_class;
2062 case MONO_TYPE_TYPEDBYREF:
2063 return type->data.klass? type->data.klass: mono_defaults.typed_reference_class;
2064 case MONO_TYPE_ARRAY:
2065 return mono_class_create_bounded_array (type->data.array->eklass, type->data.array->rank, TRUE);
2066 case MONO_TYPE_PTR:
2067 return mono_class_create_ptr (type->data.type);
2068 case MONO_TYPE_FNPTR:
2069 return mono_class_create_fnptr (type->data.method);
2070 case MONO_TYPE_SZARRAY:
2071 return mono_class_create_array (type->data.klass, 1);
2072 case MONO_TYPE_CLASS:
2073 case MONO_TYPE_VALUETYPE:
2074 return type->data.klass;
2075 case MONO_TYPE_GENERICINST:
2076 return mono_class_create_generic_inst (type->data.generic_class);
2077 case MONO_TYPE_MVAR:
2078 case MONO_TYPE_VAR:
2079 return mono_class_create_generic_parameter (type->data.generic_param);
2080 default:
2081 g_warning ("mono_class_from_mono_type_internal: implement me 0x%02x\n", type->type);
2082 g_assert_not_reached ();
2085 // Yes, this returns NULL, even if it is documented as not doing so, but there
2086 // is no way for the code to make it this far, due to the assert above.
2087 return NULL;
2091 * mono_type_retrieve_from_typespec
2092 * \param image context where the image is created
2093 * \param type_spec typespec token
2094 * \param context the generic context used to evaluate generic instantiations in
2096 static MonoType *
2097 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
2099 MonoType *t = mono_type_create_from_typespec_checked (image, type_spec, error);
2101 *did_inflate = FALSE;
2103 if (!t)
2104 return NULL;
2106 if (context && (context->class_inst || context->method_inst)) {
2107 MonoType *inflated = inflate_generic_type (NULL, t, context, error);
2109 if (!is_ok (error)) {
2110 return NULL;
2113 if (inflated) {
2114 t = inflated;
2115 *did_inflate = TRUE;
2118 return t;
2122 * mono_class_create_from_typespec
2123 * \param image context where the image is created
2124 * \param type_spec typespec token
2125 * \param context the generic context used to evaluate generic instantiations in
2127 static MonoClass *
2128 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
2130 MonoClass *ret;
2131 gboolean inflated = FALSE;
2132 MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
2133 return_val_if_nok (error, NULL);
2134 ret = mono_class_from_mono_type_internal (t);
2135 if (inflated)
2136 mono_metadata_free_type (t);
2137 return ret;
2141 * mono_bounded_array_class_get:
2142 * \param element_class element class
2143 * \param rank the dimension of the array class
2144 * \param bounded whenever the array has non-zero bounds
2145 * \returns A class object describing the array with element type \p element_type and
2146 * dimension \p rank.
2148 MonoClass *
2149 mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
2151 return mono_class_create_bounded_array (eclass, rank, bounded);
2155 * mono_array_class_get:
2156 * \param element_class element class
2157 * \param rank the dimension of the array class
2158 * \returns A class object describing the array with element type \p element_type and
2159 * dimension \p rank.
2161 MonoClass *
2162 mono_array_class_get (MonoClass *eclass, guint32 rank)
2164 return mono_class_create_array (eclass, rank);
2168 * mono_class_instance_size:
2169 * \param klass a class
2171 * Use to get the size of a class in bytes.
2173 * \returns The size of an object instance
2175 gint32
2176 mono_class_instance_size (MonoClass *klass)
2178 if (!m_class_is_size_inited (klass))
2179 mono_class_init_internal (klass);
2181 return m_class_get_instance_size (klass);
2185 * mono_class_min_align:
2186 * \param klass a class
2188 * Use to get the computed minimum alignment requirements for the specified class.
2190 * Returns: minimum alignment requirements
2192 gint32
2193 mono_class_min_align (MonoClass *klass)
2195 if (!m_class_is_size_inited (klass))
2196 mono_class_init_internal (klass);
2198 return m_class_get_min_align (klass);
2202 * mono_class_data_size:
2203 * \param klass a class
2205 * \returns The size of the static class data
2207 gint32
2208 mono_class_data_size (MonoClass *klass)
2210 if (!m_class_is_inited (klass))
2211 mono_class_init_internal (klass);
2212 /* This can happen with dynamically created types */
2213 if (!m_class_is_fields_inited (klass))
2214 mono_class_setup_fields (klass);
2216 /* in arrays, sizes.class_size is unioned with element_size
2217 * and arrays have no static fields
2219 if (m_class_get_rank (klass))
2220 return 0;
2221 return m_class_get_sizes (klass).class_size;
2225 * Auxiliary routine to mono_class_get_field
2227 * Takes a field index instead of a field token.
2229 static MonoClassField *
2230 mono_class_get_field_idx (MonoClass *klass, int idx)
2232 mono_class_setup_fields (klass);
2233 if (mono_class_has_failure (klass))
2234 return NULL;
2236 while (klass) {
2237 int first_field_idx = mono_class_get_first_field_idx (klass);
2238 int fcount = mono_class_get_field_count (klass);
2239 MonoImage *klass_image = m_class_get_image (klass);
2240 MonoClassField *klass_fields = m_class_get_fields (klass);
2241 if (klass_image->uncompressed_metadata) {
2243 * first_field_idx points to the FieldPtr table, while idx points into the
2244 * Field table, so we have to do a search.
2246 /*FIXME this is broken for types with multiple fields with the same name.*/
2247 const char *name = mono_metadata_string_heap (klass_image, mono_metadata_decode_row_col (&klass_image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
2248 int i;
2250 for (i = 0; i < fcount; ++i)
2251 if (mono_field_get_name (&klass_fields [i]) == name)
2252 return &klass_fields [i];
2253 g_assert_not_reached ();
2254 } else {
2255 if (fcount) {
2256 if ((idx >= first_field_idx) && (idx < first_field_idx + fcount)){
2257 return &klass_fields [idx - first_field_idx];
2261 klass = m_class_get_parent (klass);
2263 return NULL;
2267 * mono_class_get_field:
2268 * \param class the class to lookup the field.
2269 * \param field_token the field token
2271 * \returns A \c MonoClassField representing the type and offset of
2272 * the field, or a NULL value if the field does not belong to this
2273 * class.
2275 MonoClassField *
2276 mono_class_get_field (MonoClass *klass, guint32 field_token)
2278 int idx = mono_metadata_token_index (field_token);
2280 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
2282 return mono_class_get_field_idx (klass, idx - 1);
2286 * mono_class_get_field_from_name:
2287 * \param klass the class to lookup the field.
2288 * \param name the field name
2290 * Search the class \p klass and its parents for a field with the name \p name.
2292 * \returns The \c MonoClassField pointer of the named field or NULL
2294 MonoClassField *
2295 mono_class_get_field_from_name (MonoClass *klass, const char *name)
2297 MonoClassField *result;
2298 MONO_ENTER_GC_UNSAFE;
2299 result = mono_class_get_field_from_name_full (klass, name, NULL);
2300 MONO_EXIT_GC_UNSAFE;
2301 return result;
2305 * mono_class_get_field_from_name_full:
2306 * \param klass the class to lookup the field.
2307 * \param name the field name
2308 * \param type the type of the fields. This optional.
2310 * Search the class \p klass and it's parents for a field with the name \p name and type \p type.
2312 * If \p klass is an inflated generic type, the type comparison is done with the equivalent field
2313 * of its generic type definition.
2315 * \returns The MonoClassField pointer of the named field or NULL
2317 MonoClassField *
2318 mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
2320 MONO_REQ_GC_UNSAFE_MODE;
2322 int i;
2324 mono_class_setup_fields (klass);
2325 if (mono_class_has_failure (klass))
2326 return NULL;
2328 while (klass) {
2329 int fcount = mono_class_get_field_count (klass);
2330 for (i = 0; i < fcount; ++i) {
2331 MonoClassField *field = &m_class_get_fields (klass) [i];
2333 if (strcmp (name, mono_field_get_name (field)) != 0)
2334 continue;
2336 if (type) {
2337 MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
2338 if (!mono_metadata_type_equal_full (type, field_type, TRUE))
2339 continue;
2341 return field;
2343 klass = m_class_get_parent (klass);
2345 return NULL;
2349 * mono_class_get_field_token:
2350 * \param field the field we need the token of
2352 * Get the token of a field. Note that the tokesn is only valid for the image
2353 * the field was loaded from. Don't use this function for fields in dynamic types.
2355 * \returns The token representing the field in the image it was loaded from.
2357 guint32
2358 mono_class_get_field_token (MonoClassField *field)
2360 MonoClass *klass = field->parent;
2361 int i;
2363 mono_class_setup_fields (klass);
2365 while (klass) {
2366 MonoClassField *klass_fields = m_class_get_fields (klass);
2367 if (!klass_fields)
2368 return 0;
2369 int first_field_idx = mono_class_get_first_field_idx (klass);
2370 int fcount = mono_class_get_field_count (klass);
2371 for (i = 0; i < fcount; ++i) {
2372 if (&klass_fields [i] == field) {
2373 int idx = first_field_idx + i + 1;
2375 if (m_class_get_image (klass)->uncompressed_metadata)
2376 idx = mono_metadata_translate_token_index (m_class_get_image (klass), MONO_TABLE_FIELD, idx);
2377 return mono_metadata_make_token (MONO_TABLE_FIELD, idx);
2380 klass = m_class_get_parent (klass);
2383 g_assert_not_reached ();
2384 return 0;
2387 static int
2388 mono_field_get_index (MonoClassField *field)
2390 int index = field - m_class_get_fields (field->parent);
2391 g_assert (index >= 0 && index < mono_class_get_field_count (field->parent));
2393 return index;
2397 * mono_class_get_field_default_value:
2399 * Return the default value of the field as a pointer into the metadata blob.
2401 const char*
2402 mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
2404 guint32 cindex;
2405 guint32 constant_cols [MONO_CONSTANT_SIZE];
2406 int field_index;
2407 MonoClass *klass = field->parent;
2408 MonoFieldDefaultValue *def_values;
2410 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2412 def_values = mono_class_get_field_def_values (klass);
2413 if (!def_values) {
2414 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
2416 mono_class_set_field_def_values (klass, def_values);
2419 field_index = mono_field_get_index (field);
2421 if (!def_values [field_index].data) {
2422 MonoImage *field_parent_image = m_class_get_image (field->parent);
2423 cindex = mono_metadata_get_constant_index (field_parent_image, mono_class_get_field_token (field), 0);
2424 if (!cindex)
2425 return NULL;
2427 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
2429 mono_metadata_decode_row (&field_parent_image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
2430 def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
2431 mono_memory_barrier ();
2432 def_values [field_index].data = (const char *)mono_metadata_blob_heap (field_parent_image, constant_cols [MONO_CONSTANT_VALUE]);
2435 *def_type = def_values [field_index].def_type;
2436 return def_values [field_index].data;
2439 static int
2440 mono_property_get_index (MonoProperty *prop)
2442 MonoClassPropertyInfo *info = mono_class_get_property_info (prop->parent);
2443 int index = prop - info->properties;
2445 g_assert (index >= 0 && index < info->count);
2447 return index;
2451 * mono_class_get_property_default_value:
2453 * Return the default value of the field as a pointer into the metadata blob.
2455 const char*
2456 mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type)
2458 guint32 cindex;
2459 guint32 constant_cols [MONO_CONSTANT_SIZE];
2460 MonoClass *klass = property->parent;
2461 MonoImage *klass_image = m_class_get_image (klass);
2463 g_assert (property->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT);
2465 * We don't cache here because it is not used by C# so it's quite rare, but
2466 * we still do the lookup in klass->ext because that is where the data
2467 * is stored for dynamic assemblies.
2470 if (image_is_dynamic (klass_image)) {
2471 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
2472 int prop_index = mono_property_get_index (property);
2473 if (info->def_values && info->def_values [prop_index].data) {
2474 *def_type = info->def_values [prop_index].def_type;
2475 return info->def_values [prop_index].data;
2477 return NULL;
2479 cindex = mono_metadata_get_constant_index (klass_image, mono_class_get_property_token (property), 0);
2480 if (!cindex)
2481 return NULL;
2483 mono_metadata_decode_row (&klass_image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
2484 *def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
2485 return (const char *)mono_metadata_blob_heap (klass_image, constant_cols [MONO_CONSTANT_VALUE]);
2489 * mono_class_get_event_token:
2491 guint32
2492 mono_class_get_event_token (MonoEvent *event)
2494 MonoClass *klass = event->parent;
2495 int i;
2497 while (klass) {
2498 MonoClassEventInfo *info = mono_class_get_event_info (klass);
2499 if (info) {
2500 for (i = 0; i < info->count; ++i) {
2501 if (&info->events [i] == event)
2502 return mono_metadata_make_token (MONO_TABLE_EVENT, info->first + i + 1);
2505 klass = m_class_get_parent (klass);
2508 g_assert_not_reached ();
2509 return 0;
2512 MonoProperty*
2513 mono_class_get_property_from_name_internal (MonoClass *klass, const char *name)
2515 MONO_REQ_GC_UNSAFE_MODE;
2516 while (klass) {
2517 MonoProperty* p;
2518 gpointer iter = NULL;
2519 while ((p = mono_class_get_properties (klass, &iter))) {
2520 if (! strcmp (name, p->name))
2521 return p;
2523 klass = m_class_get_parent (klass);
2525 return NULL;
2529 * mono_class_get_property_token:
2530 * \param prop MonoProperty to query
2532 * \returns The ECMA token for the specified property.
2534 guint32
2535 mono_class_get_property_token (MonoProperty *prop)
2537 MonoClass *klass = prop->parent;
2538 while (klass) {
2539 MonoProperty* p;
2540 int i = 0;
2541 gpointer iter = NULL;
2542 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
2543 while ((p = mono_class_get_properties (klass, &iter))) {
2544 if (&info->properties [i] == prop)
2545 return mono_metadata_make_token (MONO_TABLE_PROPERTY, info->first + i + 1);
2547 i ++;
2549 klass = m_class_get_parent (klass);
2552 g_assert_not_reached ();
2553 return 0;
2557 * mono_class_name_from_token:
2559 char *
2560 mono_class_name_from_token (MonoImage *image, guint32 type_token)
2562 const char *name, *nspace;
2563 if (image_is_dynamic (image))
2564 return g_strdup_printf ("DynamicType 0x%08x", type_token);
2566 switch (type_token & 0xff000000){
2567 case MONO_TOKEN_TYPE_DEF: {
2568 guint32 cols [MONO_TYPEDEF_SIZE];
2569 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
2570 guint tidx = mono_metadata_token_index (type_token);
2572 if (tidx > tt->rows)
2573 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2575 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
2576 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2577 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2578 if (strlen (nspace) == 0)
2579 return g_strdup_printf ("%s", name);
2580 else
2581 return g_strdup_printf ("%s.%s", nspace, name);
2584 case MONO_TOKEN_TYPE_REF: {
2585 ERROR_DECL (error);
2586 guint32 cols [MONO_TYPEREF_SIZE];
2587 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2588 guint tidx = mono_metadata_token_index (type_token);
2590 if (tidx > t->rows)
2591 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2593 if (!mono_verifier_verify_typeref_row (image, tidx - 1, error)) {
2594 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (error));
2595 mono_error_cleanup (error);
2596 return msg;
2599 mono_metadata_decode_row (t, tidx-1, cols, MONO_TYPEREF_SIZE);
2600 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2601 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2602 if (strlen (nspace) == 0)
2603 return g_strdup_printf ("%s", name);
2604 else
2605 return g_strdup_printf ("%s.%s", nspace, name);
2608 case MONO_TOKEN_TYPE_SPEC:
2609 return g_strdup_printf ("Typespec 0x%08x", type_token);
2610 default:
2611 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2615 static char *
2616 mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
2618 if (image_is_dynamic (image))
2619 return g_strdup_printf ("DynamicAssembly %s", image->name);
2621 switch (type_token & 0xff000000){
2622 case MONO_TOKEN_TYPE_DEF:
2623 if (image->assembly)
2624 return mono_stringify_assembly_name (&image->assembly->aname);
2625 else if (image->assembly_name)
2626 return g_strdup (image->assembly_name);
2627 return g_strdup_printf ("%s", image->name ? image->name : "[Could not resolve assembly name");
2628 case MONO_TOKEN_TYPE_REF: {
2629 ERROR_DECL (error);
2630 MonoAssemblyName aname;
2631 guint32 cols [MONO_TYPEREF_SIZE];
2632 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2633 guint32 idx = mono_metadata_token_index (type_token);
2635 if (idx > t->rows)
2636 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2638 if (!mono_verifier_verify_typeref_row (image, idx - 1, error)) {
2639 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (error));
2640 mono_error_cleanup (error);
2641 return msg;
2643 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
2645 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
2646 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
2647 case MONO_RESOLUTION_SCOPE_MODULE:
2648 /* FIXME: */
2649 return g_strdup ("");
2650 case MONO_RESOLUTION_SCOPE_MODULEREF:
2651 /* FIXME: */
2652 return g_strdup ("");
2653 case MONO_RESOLUTION_SCOPE_TYPEREF:
2654 /* FIXME: */
2655 return g_strdup ("");
2656 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
2657 mono_assembly_get_assemblyref (image, idx - 1, &aname);
2658 return mono_stringify_assembly_name (&aname);
2659 default:
2660 g_assert_not_reached ();
2662 break;
2664 case MONO_TOKEN_TYPE_SPEC:
2665 /* FIXME: */
2666 return g_strdup ("");
2667 default:
2668 g_assert_not_reached ();
2671 return NULL;
2675 * mono_class_get_full:
2676 * \param image the image where the class resides
2677 * \param type_token the token for the class
2678 * \param context the generic context used to evaluate generic instantiations in
2679 * \deprecated Functions that expose \c MonoGenericContext are going away in mono 4.0
2680 * \returns The \c MonoClass that represents \p type_token in \p image
2682 MonoClass *
2683 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
2685 ERROR_DECL (error);
2686 MonoClass *klass;
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 mono_error_assert_ok (error);
2693 return klass;
2697 MonoClass *
2698 mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
2700 MonoClass *klass;
2702 error_init (error);
2703 klass = mono_class_get_checked (image, type_token, error);
2705 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
2706 klass = mono_class_inflate_generic_class_checked (klass, context, error);
2708 return klass;
2711 * mono_class_get_checked:
2712 * \param image the image where the class resides
2713 * \param type_token the token for the class
2714 * \param error error object to return any error
2716 * \returns The MonoClass that represents \p type_token in \p image, or NULL on error.
2718 MonoClass *
2719 mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
2721 MonoClass *klass = NULL;
2723 error_init (error);
2725 if (image_is_dynamic (image)) {
2726 int table = mono_metadata_token_table (type_token);
2728 if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
2729 mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
2730 return NULL;
2732 klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
2733 goto done;
2736 switch (type_token & 0xff000000){
2737 case MONO_TOKEN_TYPE_DEF:
2738 klass = mono_class_create_from_typedef (image, type_token, error);
2739 break;
2740 case MONO_TOKEN_TYPE_REF:
2741 klass = mono_class_from_typeref_checked (image, type_token, error);
2742 break;
2743 case MONO_TOKEN_TYPE_SPEC:
2744 klass = mono_class_create_from_typespec (image, type_token, NULL, error);
2745 break;
2746 default:
2747 mono_error_set_bad_image (error, image, "Unknown type token %x", type_token & 0xff000000);
2750 done:
2751 /* Generic case, should be avoided for when a better error is possible. */
2752 if (!klass && is_ok (error)) {
2753 char *name = mono_class_name_from_token (image, type_token);
2754 char *assembly = mono_assembly_name_from_token (image, type_token);
2755 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);
2758 return klass;
2763 * mono_type_get_checked:
2764 * \param image the image where the type resides
2765 * \param type_token the token for the type
2766 * \param context the generic context used to evaluate generic instantiations in
2767 * \param error Error handling context
2769 * This functions exists to fullfill the fact that sometimes it's desirable to have access to the
2771 * \returns The MonoType that represents \p type_token in \p image
2773 MonoType *
2774 mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
2776 MonoType *type = NULL;
2777 gboolean inflated = FALSE;
2779 error_init (error);
2781 //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
2782 if (image_is_dynamic (image)) {
2783 MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
2784 return_val_if_nok (error, NULL);
2785 return m_class_get_byval_arg (klass);
2788 if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
2789 MonoClass *klass = mono_class_get_checked (image, type_token, error);
2791 if (!klass)
2792 return NULL;
2793 if (m_class_has_failure (klass)) {
2794 mono_error_set_for_class_failure (error, klass);
2795 return NULL;
2797 return m_class_get_byval_arg (klass);
2800 type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
2802 if (!type) {
2803 return NULL;
2806 if (inflated) {
2807 MonoType *tmp = type;
2808 type = m_class_get_byval_arg (mono_class_from_mono_type_internal (type));
2809 /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
2810 * A MonoClass::_byval_arg of a generic type definion has type CLASS.
2811 * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with _byval_arg.
2813 * The long term solution is to chaise this places and make then set MonoType::type correctly.
2814 * */
2815 if (type->type != tmp->type)
2816 type = tmp;
2817 else
2818 mono_metadata_free_type (tmp);
2820 return type;
2824 * mono_class_get:
2825 * \param image image where the class token will be looked up.
2826 * \param type_token a type token from the image
2827 * \returns the \c MonoClass with the given \p type_token on the \p image
2829 MonoClass *
2830 mono_class_get (MonoImage *image, guint32 type_token)
2832 ERROR_DECL (error);
2833 MonoClass *result = mono_class_get_checked (image, type_token, error);
2834 mono_error_assert_ok (error);
2835 return result;
2839 * mono_image_init_name_cache:
2841 * Initializes the class name cache stored in image->name_cache.
2843 * LOCKING: Acquires the corresponding image lock.
2845 void
2846 mono_image_init_name_cache (MonoImage *image)
2848 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
2849 guint32 cols [MONO_TYPEDEF_SIZE];
2850 const char *name;
2851 const char *nspace;
2852 guint32 i, visib, nspace_index;
2853 GHashTable *name_cache2, *nspace_table, *the_name_cache;
2855 if (image->name_cache)
2856 return;
2858 the_name_cache = g_hash_table_new (g_str_hash, g_str_equal);
2860 if (image_is_dynamic (image)) {
2861 mono_image_lock (image);
2862 if (image->name_cache) {
2863 /* Somebody initialized it before us */
2864 g_hash_table_destroy (the_name_cache);
2865 } else {
2866 mono_atomic_store_release (&image->name_cache, the_name_cache);
2868 mono_image_unlock (image);
2869 return;
2872 /* Temporary hash table to avoid lookups in the nspace_table */
2873 name_cache2 = g_hash_table_new (NULL, NULL);
2875 for (i = 1; i <= t->rows; ++i) {
2876 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
2877 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2879 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
2880 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
2882 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
2883 continue;
2884 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2885 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2887 nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
2888 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
2889 if (!nspace_table) {
2890 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
2891 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
2892 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
2893 nspace_table);
2895 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
2898 /* Load type names from EXPORTEDTYPES table */
2900 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
2901 guint32 cols [MONO_EXP_TYPE_SIZE];
2902 int i;
2904 for (i = 0; i < t->rows; ++i) {
2905 mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
2907 guint32 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
2908 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_EXP_TYPE)
2909 /* Nested type */
2910 continue;
2912 name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
2913 nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
2915 nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
2916 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
2917 if (!nspace_table) {
2918 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
2919 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
2920 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
2921 nspace_table);
2923 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
2927 g_hash_table_destroy (name_cache2);
2929 mono_image_lock (image);
2930 if (image->name_cache) {
2931 /* Somebody initialized it before us */
2932 g_hash_table_destroy (the_name_cache);
2933 } else {
2934 mono_atomic_store_release (&image->name_cache, the_name_cache);
2936 mono_image_unlock (image);
2939 /*FIXME Only dynamic assemblies should allow this operation.*/
2941 * mono_image_add_to_name_cache:
2943 void
2944 mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
2945 const char *name, guint32 index)
2947 GHashTable *nspace_table;
2948 GHashTable *name_cache;
2949 guint32 old_index;
2951 mono_image_init_name_cache (image);
2952 mono_image_lock (image);
2954 name_cache = image->name_cache;
2955 if (!(nspace_table = (GHashTable *)g_hash_table_lookup (name_cache, nspace))) {
2956 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
2957 g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
2960 if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
2961 g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
2963 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
2965 mono_image_unlock (image);
2968 typedef struct {
2969 gconstpointer key;
2970 GSList *values;
2971 } FindAllUserData;
2973 static void
2974 find_all_nocase (gpointer key, gpointer value, gpointer user_data)
2976 char *name = (char*)key;
2977 FindAllUserData *data = (FindAllUserData*)user_data;
2978 if (mono_utf8_strcasecmp (name, (char*)data->key) == 0)
2979 data->values = g_slist_prepend (data->values, value);
2982 typedef struct {
2983 gconstpointer key;
2984 gpointer value;
2985 } FindUserData;
2987 static void
2988 find_nocase (gpointer key, gpointer value, gpointer user_data)
2990 char *name = (char*)key;
2991 FindUserData *data = (FindUserData*)user_data;
2993 if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
2994 data->value = value;
2998 * mono_class_from_name_case:
2999 * \param image The MonoImage where the type is looked up in
3000 * \param name_space the type namespace
3001 * \param name the type short name.
3002 * \deprecated use the mono_class_from_name_case_checked variant instead.
3004 * Obtains a \c MonoClass with a given namespace and a given name which
3005 * is located in the given \c MonoImage. The namespace and name
3006 * lookups are case insensitive.
3008 MonoClass *
3009 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
3011 ERROR_DECL (error);
3012 MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, error);
3013 mono_error_cleanup (error);
3015 return res;
3019 * mono_class_from_name_case_checked:
3020 * \param image The MonoImage where the type is looked up in
3021 * \param name_space the type namespace
3022 * \param name the type short name.
3023 * \param error if
3025 * Obtains a MonoClass with a given namespace and a given name which
3026 * is located in the given MonoImage. The namespace and name
3027 * lookups are case insensitive.
3029 * \returns The MonoClass if the given namespace and name were found, or NULL if it
3030 * was not found. The \p error object will contain information about the problem
3031 * in that case.
3033 MonoClass *
3034 mono_class_from_name_case_checked (MonoImage *image, const char *name_space, const char *name, MonoError *error)
3036 MonoClass *klass;
3037 GHashTable *visited_images;
3039 visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
3041 klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, FALSE, error);
3043 g_hash_table_destroy (visited_images);
3045 return klass;
3048 static MonoClass*
3049 return_nested_in (MonoClass *klass, char *nested, gboolean case_sensitive)
3051 MonoClass *found;
3052 char *s = strchr (nested, '/');
3053 gpointer iter = NULL;
3055 if (s) {
3056 *s = 0;
3057 s++;
3060 while ((found = mono_class_get_nested_types (klass, &iter))) {
3061 const char *name = m_class_get_name (found);
3062 gint strcmp_result;
3063 if (case_sensitive)
3064 strcmp_result = strcmp (name, nested);
3065 else
3066 strcmp_result = mono_utf8_strcasecmp (name, nested);
3068 if (strcmp_result == 0) {
3069 if (s)
3070 return return_nested_in (found, s, case_sensitive);
3071 return found;
3074 return NULL;
3077 static MonoClass*
3078 search_modules (MonoImage *image, const char *name_space, const char *name, gboolean case_sensitive, MonoError *error)
3080 MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
3081 MonoImage *file_image;
3082 MonoClass *klass;
3083 int i;
3085 error_init (error);
3088 * The EXPORTEDTYPES table only contains public types, so have to search the
3089 * modules as well.
3090 * Note: image->modules contains the contents of the MODULEREF table, while
3091 * the real module list is in the FILE table.
3093 for (i = 0; i < file_table->rows; i++) {
3094 guint32 cols [MONO_FILE_SIZE];
3095 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
3096 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
3097 continue;
3099 file_image = mono_image_load_file_for_image_checked (image, i + 1, error);
3100 if (file_image) {
3101 if (case_sensitive)
3102 klass = mono_class_from_name_checked (file_image, name_space, name, error);
3103 else
3104 klass = mono_class_from_name_case_checked (file_image, name_space, name, error);
3106 if (klass || !is_ok (error))
3107 return klass;
3111 return NULL;
3114 static MonoClass *
3115 mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, gboolean case_sensitive, MonoError *error)
3117 GHashTable *nspace_table = NULL;
3118 MonoImage *loaded_image = NULL;
3119 guint32 token = 0;
3120 int i;
3121 MonoClass *klass;
3122 char *nested;
3123 char buf [1024];
3125 error_init (error);
3127 // Checking visited images avoids stack overflows when cyclic references exist.
3128 if (g_hash_table_lookup (visited_images, image))
3129 return NULL;
3131 g_hash_table_insert (visited_images, image, GUINT_TO_POINTER(1));
3133 if ((nested = (char*)strchr (name, '/'))) {
3134 int pos = nested - name;
3135 int len = strlen (name);
3136 if (len > 1023)
3137 return NULL;
3138 memcpy (buf, name, len + 1);
3139 buf [pos] = 0;
3140 nested = buf + pos + 1;
3141 name = buf;
3144 /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */
3145 // The AOT cache in get_class_from_name is case-sensitive, so don't bother with it for case-insensitive lookups
3146 if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0 && case_sensitive) {
3147 gboolean res = get_class_from_name (image, name_space, name, &klass);
3148 if (res) {
3149 if (!klass) {
3150 klass = search_modules (image, name_space, name, case_sensitive, error);
3151 if (!is_ok (error))
3152 return NULL;
3154 if (nested)
3155 return klass ? return_nested_in (klass, nested, case_sensitive) : NULL;
3156 else
3157 return klass;
3161 mono_image_init_name_cache (image);
3162 mono_image_lock (image);
3164 if (case_sensitive) {
3165 nspace_table = (GHashTable *)g_hash_table_lookup (image->name_cache, name_space);
3167 if (nspace_table)
3168 token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
3169 } else {
3170 FindAllUserData all_user_data = { name_space, NULL };
3171 FindUserData user_data = { name, NULL };
3172 GSList *values;
3174 // We're forced to check all matching namespaces, not just the first one found,
3175 // because our desired type could be in any of the ones that match case-insensitively.
3176 g_hash_table_foreach (image->name_cache, find_all_nocase, &all_user_data);
3178 values = all_user_data.values;
3179 while (values && !user_data.value) {
3180 nspace_table = (GHashTable*)values->data;
3181 g_hash_table_foreach (nspace_table, find_nocase, &user_data);
3182 values = values->next;
3185 g_slist_free (all_user_data.values);
3187 if (user_data.value)
3188 token = GPOINTER_TO_UINT (user_data.value);
3191 mono_image_unlock (image);
3193 if (!token && image_is_dynamic (image) && image->modules) {
3194 /* Search modules as well */
3195 for (i = 0; i < image->module_count; ++i) {
3196 MonoImage *module = image->modules [i];
3198 if (case_sensitive)
3199 klass = mono_class_from_name_checked (module, name_space, name, error);
3200 else
3201 klass = mono_class_from_name_case_checked (module, name_space, name, error);
3203 if (klass || !is_ok (error))
3204 return klass;
3208 if (!token) {
3209 klass = search_modules (image, name_space, name, case_sensitive, error);
3210 if (klass || !is_ok (error))
3211 return klass;
3212 return NULL;
3215 if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
3216 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
3217 guint32 cols [MONO_EXP_TYPE_SIZE];
3218 guint32 idx, impl;
3220 idx = mono_metadata_token_index (token);
3222 mono_metadata_decode_row (t, idx - 1, cols, MONO_EXP_TYPE_SIZE);
3224 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
3225 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
3226 loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error);
3227 if (!loaded_image)
3228 return NULL;
3229 klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, case_sensitive, error);
3230 if (nested)
3231 return klass ? return_nested_in (klass, nested, case_sensitive) : NULL;
3232 return klass;
3233 } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
3234 guint32 assembly_idx;
3236 assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
3238 mono_assembly_load_reference (image, assembly_idx - 1);
3239 g_assert (image->references [assembly_idx - 1]);
3240 if (image->references [assembly_idx - 1] == (gpointer)-1)
3241 return NULL;
3242 klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, case_sensitive, error);
3243 if (nested)
3244 return klass ? return_nested_in (klass, nested, case_sensitive) : NULL;
3245 return klass;
3246 } else {
3247 g_assert_not_reached ();
3251 token = MONO_TOKEN_TYPE_DEF | token;
3253 klass = mono_class_get_checked (image, token, error);
3254 if (nested)
3255 return return_nested_in (klass, nested, case_sensitive);
3256 return klass;
3260 * mono_class_from_name_checked:
3261 * \param image The MonoImage where the type is looked up in
3262 * \param name_space the type namespace
3263 * \param name the type short name.
3265 * Obtains a MonoClass with a given namespace and a given name which
3266 * is located in the given MonoImage.
3268 * Works like mono_class_from_name, but error handling is tricky. It can return NULL and have no error
3269 * set if the class was not found or it will return NULL and set the error if there was a loading error.
3271 MonoClass *
3272 mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
3274 MonoClass *klass;
3275 GHashTable *visited_images;
3277 visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
3279 klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, TRUE, error);
3281 g_hash_table_destroy (visited_images);
3283 return klass;
3287 * mono_class_from_name:
3288 * \param image The \c MonoImage where the type is looked up in
3289 * \param name_space the type namespace
3290 * \param name the type short name.
3292 * Obtains a \c MonoClass with a given namespace and a given name which
3293 * is located in the given \c MonoImage.
3295 * To reference nested classes, use the "/" character as a separator.
3296 * For example use \c "Foo/Bar" to reference the class \c Bar that is nested
3297 * inside \c Foo, like this: "class Foo { class Bar {} }".
3299 MonoClass *
3300 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
3302 MonoClass *klass;
3303 MONO_ENTER_GC_UNSAFE;
3304 ERROR_DECL (error);
3306 klass = mono_class_from_name_checked (image, name_space, name, error);
3307 mono_error_cleanup (error); /* FIXME Don't swallow the error */
3308 MONO_EXIT_GC_UNSAFE;
3309 return klass;
3313 * mono_class_load_from_name:
3314 * \param image The MonoImage where the type is looked up in
3315 * \param name_space the type namespace
3316 * \param name the type short name.
3318 * This function works exactly like mono_class_from_name but it will abort if the class is not found.
3319 * This function should be used by the runtime for critical types to which there's no way to recover but crash
3320 * If they are missing. Thing of System.Object or System.String.
3322 MonoClass *
3323 mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
3325 ERROR_DECL (error);
3326 MonoClass *klass;
3328 klass = mono_class_from_name_checked (image, name_space, name, error);
3329 if (!klass)
3330 g_error ("Runtime critical type %s.%s not found", name_space, name);
3331 mono_error_assertf_ok (error, "Could not load runtime critical type %s.%s", name_space, name);
3332 return klass;
3336 * mono_class_try_load_from_name:
3337 * \param image The MonoImage where the type is looked up in
3338 * \param name_space the type namespace
3339 * \param name the type short name.
3341 * This function tries to load a type, returning the class was found or NULL otherwise.
3342 * This function should be used by the runtime when probing for optional types, those that could have being linked out.
3344 * Big design consideration. This function aborts if there was an error loading the type. This prevents us from missing
3345 * a type that we would otherwise assume to be available but was not due some error.
3348 MonoClass*
3349 mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name)
3351 ERROR_DECL (error);
3352 MonoClass *klass;
3354 klass = mono_class_from_name_checked (image, name_space, name, error);
3355 mono_error_assertf_ok (error, "Could not load runtime critical type %s.%s", name_space, name);
3356 return klass;
3359 static gboolean
3360 mono_interface_implements_interface (MonoClass *interface_implementer, MonoClass *interface_implemented)
3362 int i;
3363 ERROR_DECL (error);
3364 mono_class_setup_interfaces (interface_implementer, error);
3365 if (!is_ok (error)) {
3366 mono_error_cleanup (error);
3367 return FALSE;
3369 MonoClass **klass_interfaces = m_class_get_interfaces (interface_implementer);
3370 for (i = 0; i < m_class_get_interface_count (interface_implementer); i++) {
3371 MonoClass *ic = klass_interfaces [i];
3372 if (mono_class_is_ginst (ic))
3373 ic = mono_class_get_generic_type_definition (ic);
3374 if (ic == interface_implemented)
3375 return TRUE;
3377 return FALSE;
3380 gboolean
3381 mono_class_is_subclass_of_internal (MonoClass *klass, MonoClass *klassc,
3382 gboolean check_interfaces)
3384 MONO_REQ_GC_UNSAFE_MODE;
3385 /* FIXME test for interfaces with variant generic arguments */
3386 mono_class_init_internal (klass);
3387 mono_class_init_internal (klassc);
3389 if (check_interfaces && MONO_CLASS_IS_INTERFACE_INTERNAL (klassc) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
3390 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, m_class_get_interface_id (klassc)))
3391 return TRUE;
3392 } else if (check_interfaces && MONO_CLASS_IS_INTERFACE_INTERNAL (klassc) && MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
3393 int i;
3395 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
3396 for (i = 0; i < m_class_get_interface_count (klass); i ++) {
3397 MonoClass *ic = klass_interfaces [i];
3398 if (ic == klassc)
3399 return TRUE;
3401 } else {
3402 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) && mono_class_has_parent (klass, klassc))
3403 return TRUE;
3407 * MS.NET thinks interfaces are a subclass of Object, so we think it as
3408 * well.
3410 if (klassc == mono_defaults.object_class)
3411 return TRUE;
3413 return FALSE;
3416 static gboolean
3417 mono_type_is_generic_argument (MonoType *type)
3419 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
3422 gboolean
3423 mono_class_has_variant_generic_params (MonoClass *klass)
3425 int i;
3426 MonoGenericContainer *container;
3428 if (!mono_class_is_ginst (klass))
3429 return FALSE;
3431 container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
3433 for (i = 0; i < container->type_argc; ++i)
3434 if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
3435 return TRUE;
3437 return FALSE;
3440 static gboolean
3441 mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
3443 if (target == candidate)
3444 return TRUE;
3446 if (check_for_reference_conv &&
3447 mono_type_is_generic_argument (m_class_get_byval_arg (target)) &&
3448 mono_type_is_generic_argument (m_class_get_byval_arg (candidate))) {
3449 MonoGenericParam *gparam = m_class_get_byval_arg (candidate)->data.generic_param;
3450 MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
3452 if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
3453 return FALSE;
3455 if (!mono_class_is_assignable_from_internal (target, candidate))
3456 return FALSE;
3457 return TRUE;
3461 * @container the generic container from the GTD
3462 * @klass: the class to be assigned to
3463 * @oklass: the source class
3465 * Both @klass and @oklass must be instances of the same generic interface.
3467 * Returns: TRUE if @klass can be assigned to a @klass variable
3469 gboolean
3470 mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
3472 int j;
3473 MonoType **klass_argv, **oklass_argv;
3474 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
3475 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
3477 if (klass == oklass)
3478 return TRUE;
3480 /*Viable candidates are instances of the same generic interface*/
3481 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
3482 return FALSE;
3484 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
3485 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
3487 for (j = 0; j < container->type_argc; ++j) {
3488 MonoClass *param1_class = mono_class_from_mono_type_internal (klass_argv [j]);
3489 MonoClass *param2_class = mono_class_from_mono_type_internal (oklass_argv [j]);
3491 if (m_class_is_valuetype (param1_class) != m_class_is_valuetype (param2_class) || (m_class_is_valuetype (param1_class) && param1_class != param2_class))
3492 return FALSE;
3495 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
3496 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
3498 if (param1_class != param2_class) {
3499 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
3500 if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
3501 return FALSE;
3502 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
3503 if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
3504 return FALSE;
3505 } else
3506 return FALSE;
3509 return TRUE;
3512 static gboolean
3513 mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
3515 MonoGenericParam *gparam, *ogparam;
3516 MonoGenericParamInfo *tinfo, *cinfo;
3517 MonoClass **candidate_class;
3518 gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
3519 int tmask, cmask;
3521 if (target == candidate)
3522 return TRUE;
3523 MonoType *target_byval_arg = m_class_get_byval_arg (target);
3524 MonoType *candidate_byval_arg = m_class_get_byval_arg (candidate);
3525 if (target_byval_arg->type != candidate_byval_arg->type)
3526 return FALSE;
3528 gparam = target_byval_arg->data.generic_param;
3529 ogparam = candidate_byval_arg->data.generic_param;
3530 tinfo = mono_generic_param_info (gparam);
3531 cinfo = mono_generic_param_info (ogparam);
3533 class_constraint_satisfied = FALSE;
3534 valuetype_constraint_satisfied = FALSE;
3536 /*candidate must have a super set of target's special constraints*/
3537 tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
3538 cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
3540 if (cinfo->constraints) {
3541 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
3542 MonoClass *cc = *candidate_class;
3543 MonoType *cc_byval_arg = m_class_get_byval_arg (cc);
3545 if (mono_type_is_reference (cc_byval_arg) && !MONO_CLASS_IS_INTERFACE_INTERNAL (cc))
3546 class_constraint_satisfied = TRUE;
3547 else if (!mono_type_is_reference (cc_byval_arg) && !MONO_CLASS_IS_INTERFACE_INTERNAL (cc))
3548 valuetype_constraint_satisfied = TRUE;
3551 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
3552 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
3554 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
3555 return FALSE;
3556 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
3557 return FALSE;
3558 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
3559 valuetype_constraint_satisfied)) {
3560 return FALSE;
3564 /*candidate type constraints must be a superset of target's*/
3565 if (tinfo->constraints) {
3566 MonoClass **target_class;
3567 for (target_class = tinfo->constraints; *target_class; ++target_class) {
3568 MonoClass *tc = *target_class;
3569 MonoType *tc_byval_arg = m_class_get_byval_arg (tc);
3572 * A constraint from @target might inflate into @candidate itself and in that case we don't need
3573 * check it's constraints since it satisfy the constraint by itself.
3575 if (mono_metadata_type_equal (tc_byval_arg, candidate_byval_arg))
3576 continue;
3578 if (!cinfo->constraints)
3579 return FALSE;
3581 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
3582 MonoClass *cc = *candidate_class;
3584 if (mono_class_is_assignable_from_internal (tc, cc))
3585 break;
3588 * This happens when we have the following:
3590 * Bar<K> where K : IFace
3591 * Foo<T, U> where T : U where U : IFace
3592 * ...
3593 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
3596 if (mono_type_is_generic_argument (m_class_get_byval_arg (cc))) {
3597 if (mono_gparam_is_assignable_from (target, cc))
3598 break;
3601 if (!*candidate_class)
3602 return FALSE;
3606 /*candidate itself must have a constraint that satisfy target*/
3607 if (cinfo->constraints) {
3608 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
3609 MonoClass *cc = *candidate_class;
3610 if (mono_class_is_assignable_from_internal (target, cc))
3611 return TRUE;
3614 return FALSE;
3618 * mono_class_is_assignable_from_internal:
3619 * \param klass the class to be assigned to
3620 * \param oklass the source class
3622 * \returns TRUE if an instance of class \p oklass can be assigned to an
3623 * instance of class \p klass
3625 gboolean
3626 mono_class_is_assignable_from_internal (MonoClass *klass, MonoClass *oklass)
3628 gboolean result = FALSE;
3629 ERROR_DECL (error);
3630 mono_class_is_assignable_from_checked (klass, oklass, &result, error);
3631 mono_error_cleanup (error);
3632 return result;
3636 * mono_class_is_assignable_from:
3637 * \param klass the class to be assigned to
3638 * \param oklass the source class
3640 * \returns TRUE if an instance of class \p oklass can be assigned to an
3641 * instance of class \p klass
3643 mono_bool
3644 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
3646 gboolean result;
3647 MONO_ENTER_GC_UNSAFE;
3648 result = mono_class_is_assignable_from_internal (klass, oklass);
3649 MONO_EXIT_GC_UNSAFE;
3650 return result;
3654 * mono_class_is_assignable_from_checked:
3655 * \param klass the class to be assigned to
3656 * \param oklass the source class
3657 * \param result set if there was no error
3658 * \param error set if there was an error
3660 * Sets \p result to TRUE if an instance of class \p oklass can be assigned to
3661 * an instance of class \p klass or FALSE if it cannot. On error, no \p error
3662 * is set and \p result is not valid.
3664 void
3665 mono_class_is_assignable_from_checked (MonoClass *klass, MonoClass *oklass, gboolean *result, MonoError *error)
3667 g_assert (result);
3668 if (klass == oklass) {
3669 *result = TRUE;
3670 return;
3673 MONO_REQ_GC_UNSAFE_MODE;
3674 /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
3675 if (!m_class_is_inited (klass))
3676 mono_class_init_internal (klass);
3678 if (!m_class_is_inited (oklass))
3679 mono_class_init_internal (oklass);
3681 if (mono_class_has_failure (klass)) {
3682 mono_error_set_for_class_failure (error, klass);
3683 *result = FALSE;
3684 return;
3687 if (mono_class_has_failure (oklass)) {
3688 mono_error_set_for_class_failure (error, oklass);
3689 *result = FALSE;
3690 return;
3693 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
3694 MonoType *oklass_byval_arg = m_class_get_byval_arg (oklass);
3696 if (mono_type_is_generic_argument (klass_byval_arg)) {
3697 if (!mono_type_is_generic_argument (oklass_byval_arg)) {
3698 *result = FALSE;
3699 return;
3701 *result = mono_gparam_is_assignable_from (klass, oklass);
3702 return;
3705 /* This can happen if oklass is a tyvar that has a constraint which is another tyvar which in turn
3706 * has a constraint which is a class type:
3708 * class Foo { }
3709 * class G<T1, T2> where T1 : T2 where T2 : Foo { }
3711 * In this case, Foo is assignable from T1.
3713 if (mono_type_is_generic_argument (oklass_byval_arg)) {
3714 MonoGenericParam *gparam = oklass_byval_arg->data.generic_param;
3715 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
3716 int i;
3718 if (constraints) {
3719 for (i = 0; constraints [i]; ++i) {
3720 if (mono_class_is_assignable_from_internal (klass, constraints [i])) {
3721 *result = TRUE;
3722 return;
3727 *result = mono_class_has_parent (oklass, klass);
3728 return;
3731 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
3733 /* interface_offsets might not be set for dynamic classes */
3734 if (mono_class_get_ref_info_handle (oklass) && !m_class_get_interface_bitmap (oklass)) {
3736 * oklass might be a generic type parameter but they have
3737 * interface_offsets set.
3739 gboolean assign_result = mono_reflection_call_is_assignable_to (oklass, klass, error);
3740 return_if_nok (error);
3741 *result = assign_result;
3742 return;
3744 if (!m_class_get_interface_bitmap (oklass)) {
3745 /* Happens with generic instances of not-yet created dynamic types */
3746 *result = FALSE;
3747 return;
3749 if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, m_class_get_interface_id (klass))) {
3750 *result = TRUE;
3751 return;
3754 if (m_class_is_array_special_interface (klass) && m_class_get_rank (oklass) == 1) {
3755 if (mono_class_is_gtd (klass)) {
3756 /* klass is an array special gtd like
3757 * IList`1<>, and oklass is X[] for some X.
3758 * Moreover we know that X isn't !0 (the gparam
3759 * of IList`1) because in that case we would
3760 * have returned TRUE for
3761 * MONO_CLASS_IMPLEMENTS_INTERFACE, above.
3763 *result = FALSE;
3764 return;
3766 // FIXME: IEnumerator`1 should not be an array special interface.
3767 // The correct fix is to make
3768 // ((IEnumerable<U>) (new T[] {...})).GetEnumerator()
3769 // return an IEnumerator<U> (like .NET does) instead of IEnumerator<T>
3770 // and to stop marking IEnumerable`1 as an array_special_interface.
3771 if (mono_class_get_generic_type_definition (klass) == mono_defaults.generic_ienumerator_class) {
3772 *result = FALSE;
3773 return;
3776 //XXX we could offset this by having the cast target computed at JIT time
3777 //XXX we could go even further and emit a wrapper that would do the extra type check
3778 MonoClass *iface_klass = mono_class_from_mono_type_internal (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
3779 MonoClass *obj_klass = m_class_get_cast_class (oklass); //This gets us the cast class of element type of the array
3781 // 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
3782 // We can't apply it for ref types as this would go wrong with arrays - IList<byte[]> would have byte tested
3783 if (!mono_class_is_nullable (iface_klass)) {
3784 if (m_class_is_valuetype (iface_klass))
3785 iface_klass = m_class_get_cast_class (iface_klass);
3787 //array covariant casts only operates on scalar to scalar
3788 //This is so int[] can't be casted to IComparable<int>[]
3789 if (!(m_class_is_valuetype (obj_klass) && !m_class_is_valuetype (iface_klass)) && mono_class_is_assignable_from_internal (iface_klass, obj_klass)) {
3790 *result = TRUE;
3791 return;
3796 if (mono_class_has_variant_generic_params (klass)) {
3797 int i;
3798 mono_class_setup_interfaces (oklass, error);
3799 return_if_nok (error);
3801 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
3802 for (i = 0; i < m_class_get_interface_offsets_count (oklass); ++i) {
3803 MonoClass *iface = m_class_get_interfaces_packed (oklass) [i];
3805 if (mono_class_is_variant_compatible (klass, iface, FALSE)) {
3806 *result = TRUE;
3807 return;
3812 *result = FALSE;
3813 return;
3814 } else if (m_class_is_delegate (klass)) {
3815 if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE)) {
3816 *result = TRUE;
3817 return;
3819 } else if (m_class_get_rank (klass)) {
3820 MonoClass *eclass, *eoclass;
3822 if (m_class_get_rank (oklass) != m_class_get_rank (klass)) {
3823 *result = FALSE;
3824 return;
3827 /* vectors vs. one dimensional arrays */
3828 if (oklass_byval_arg->type != klass_byval_arg->type) {
3829 *result = FALSE;
3830 return;
3833 eclass = m_class_get_cast_class (klass);
3834 eoclass = m_class_get_cast_class (oklass);
3837 * a is b does not imply a[] is b[] when a is a valuetype, and
3838 * b is a reference type.
3841 if (m_class_is_valuetype (eoclass)) {
3842 if ((eclass == mono_defaults.enum_class) ||
3843 (eclass == m_class_get_parent (mono_defaults.enum_class)) ||
3844 (!m_class_is_valuetype (eclass))) {
3845 *result = FALSE;
3846 return;
3851 * a is b does not imply a[] is b[] in the case where b is an interface and
3852 * a is a generic parameter, unless a has an additional class constraint.
3853 * For example (C#):
3854 * ```
3855 * interface I {}
3856 * class G<T> where T : I {}
3857 * class H<U> where U : class, I {}
3858 * public class P {
3859 * public static void Main() {
3860 * var t = typeof(G<>).GetTypeInfo().GenericTypeParameters[0].MakeArrayType();
3861 * var i = typeof(I).MakeArrayType();
3862 * var u = typeof(H<>).GetTypeInfo().GenericTypeParameters[0].MakeArrayType();
3863 * Console.WriteLine("I[] assignable from T[] ? {0}", i.IsAssignableFrom(t));
3864 * Console.WriteLine("I[] assignable from U[] ? {0}", i.IsAssignableFrom(u));
3867 * ```
3868 * This should print:
3869 * I[] assignable from T[] ? False
3870 * I[] assignable from U[] ? True
3873 if (MONO_CLASS_IS_INTERFACE_INTERNAL (eclass)) {
3874 MonoType *eoclass_byval_arg = m_class_get_byval_arg (eoclass);
3875 if (mono_type_is_generic_argument (eoclass_byval_arg)) {
3876 MonoGenericParam *eoparam = eoclass_byval_arg->data.generic_param;
3877 MonoGenericParamInfo *eoinfo = mono_generic_param_info (eoparam);
3878 int eomask = eoinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
3879 // check for class constraint
3880 if ((eomask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0) {
3881 *result = FALSE;
3882 return;
3887 if (mono_class_is_nullable (eclass) ^ mono_class_is_nullable (eoclass)) {
3888 *result = FALSE;
3889 return;
3892 mono_class_is_assignable_from_checked (eclass, eoclass, result, error);
3893 return;
3894 } else if (mono_class_is_nullable (klass)) {
3895 if (mono_class_is_nullable (oklass))
3896 mono_class_is_assignable_from_checked (m_class_get_cast_class (klass), m_class_get_cast_class (oklass), result, error);
3897 else
3898 mono_class_is_assignable_from_checked (m_class_get_cast_class (klass), oklass, result, error);
3899 return;
3900 } else if (klass == mono_defaults.object_class) {
3901 if (m_class_get_class_kind (oklass) == MONO_CLASS_POINTER)
3902 *result = FALSE;
3903 else
3904 *result = TRUE;
3905 return;
3908 *result = mono_class_has_parent (oklass, klass);
3911 /*Check if @oklass is variant compatible with @klass.*/
3912 static gboolean
3913 mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
3915 int j;
3916 MonoType **klass_argv, **oklass_argv;
3917 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
3918 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
3920 /*Viable candidates are instances of the same generic interface*/
3921 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
3922 return FALSE;
3924 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
3925 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
3927 for (j = 0; j < container->type_argc; ++j) {
3928 MonoClass *param1_class = mono_class_from_mono_type_internal (klass_argv [j]);
3929 MonoClass *param2_class = mono_class_from_mono_type_internal (oklass_argv [j]);
3931 if (m_class_is_valuetype (param1_class) != m_class_is_valuetype (param2_class))
3932 return FALSE;
3935 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
3936 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
3938 if (param1_class != param2_class) {
3939 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
3940 if (!mono_class_is_assignable_from_slow (param1_class, param2_class))
3941 return FALSE;
3942 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
3943 if (!mono_class_is_assignable_from_slow (param2_class, param1_class))
3944 return FALSE;
3945 } else
3946 return FALSE;
3949 return TRUE;
3951 /*Check if @candidate implements the interface @target*/
3952 static gboolean
3953 mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
3955 ERROR_DECL (error);
3956 int i;
3957 gboolean is_variant = mono_class_has_variant_generic_params (target);
3959 if (is_variant && MONO_CLASS_IS_INTERFACE_INTERNAL (candidate)) {
3960 if (mono_class_is_variant_compatible_slow (target, candidate))
3961 return TRUE;
3964 do {
3965 if (candidate == target)
3966 return TRUE;
3968 /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
3969 if (image_is_dynamic (m_class_get_image (candidate)) && !m_class_was_typebuilder (candidate)) {
3970 MonoReflectionTypeBuilder *tb = mono_class_get_ref_info_raw (candidate); /* FIXME use handles */
3971 int j;
3972 if (tb && tb->interfaces) {
3973 for (j = mono_array_length_internal (tb->interfaces) - 1; j >= 0; --j) {
3974 MonoReflectionType *iface = mono_array_get_internal (tb->interfaces, MonoReflectionType*, j);
3975 MonoClass *iface_class;
3977 /* we can't realize the type here since it can do pretty much anything. */
3978 if (!iface->type)
3979 continue;
3980 iface_class = mono_class_from_mono_type_internal (iface->type);
3981 if (iface_class == target)
3982 return TRUE;
3983 if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class))
3984 return TRUE;
3985 if (mono_class_implement_interface_slow (target, iface_class))
3986 return TRUE;
3989 } else {
3990 /*setup_interfaces don't mono_class_init_internal anything*/
3991 /*FIXME this doesn't handle primitive type arrays.
3992 ICollection<sbyte> x byte [] won't work because candidate->interfaces, for byte[], won't have IList<sbyte>.
3993 A possible way to fix this would be to move that to setup_interfaces from setup_interface_offsets.
3995 mono_class_setup_interfaces (candidate, error);
3996 if (!is_ok (error)) {
3997 mono_error_cleanup (error);
3998 return FALSE;
4001 int candidate_interface_count = m_class_get_interface_count (candidate);
4002 MonoClass **candidate_interfaces = m_class_get_interfaces (candidate);
4003 for (i = 0; i < candidate_interface_count; ++i) {
4004 if (candidate_interfaces [i] == target)
4005 return TRUE;
4007 if (is_variant && mono_class_is_variant_compatible_slow (target, candidate_interfaces [i]))
4008 return TRUE;
4010 if (mono_class_implement_interface_slow (target, candidate_interfaces [i]))
4011 return TRUE;
4014 candidate = m_class_get_parent (candidate);
4015 } while (candidate);
4017 return FALSE;
4021 * Check if @oklass can be assigned to @klass.
4022 * This function does the same as mono_class_is_assignable_from_internal but is safe to be used from mono_class_init_internal context.
4024 gboolean
4025 mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
4027 if (candidate == target)
4028 return TRUE;
4029 if (target == mono_defaults.object_class)
4030 return TRUE;
4032 if (mono_class_has_parent (candidate, target))
4033 return TRUE;
4035 /*If target is not an interface there is no need to check them.*/
4036 if (MONO_CLASS_IS_INTERFACE_INTERNAL (target))
4037 return mono_class_implement_interface_slow (target, candidate);
4039 if (m_class_is_delegate (target) && mono_class_has_variant_generic_params (target))
4040 return mono_class_is_variant_compatible (target, candidate, FALSE);
4042 if (m_class_get_rank (target)) {
4043 MonoClass *eclass, *eoclass;
4045 if (m_class_get_rank (target) != m_class_get_rank (candidate))
4046 return FALSE;
4048 /* vectors vs. one dimensional arrays */
4049 if (m_class_get_byval_arg (target)->type != m_class_get_byval_arg (candidate)->type)
4050 return FALSE;
4052 eclass = m_class_get_cast_class (target);
4053 eoclass = m_class_get_cast_class (candidate);
4056 * a is b does not imply a[] is b[] when a is a valuetype, and
4057 * b is a reference type.
4060 if (m_class_is_valuetype (eoclass)) {
4061 if ((eclass == mono_defaults.enum_class) ||
4062 (eclass == m_class_get_parent (mono_defaults.enum_class)) ||
4063 (eclass == mono_defaults.object_class))
4064 return FALSE;
4067 return mono_class_is_assignable_from_slow (eclass, eoclass);
4069 /*FIXME properly handle nullables */
4070 /*FIXME properly handle (M)VAR */
4071 return FALSE;
4075 * mono_generic_param_get_base_type:
4077 * Return the base type of the given generic parameter from its constraints.
4079 * Could be another generic parameter, or it could be Object or ValueType.
4081 MonoClass*
4082 mono_generic_param_get_base_type (MonoClass *klass)
4084 MonoType *type = m_class_get_byval_arg (klass);
4085 g_assert (mono_type_is_generic_argument (type));
4087 MonoGenericParam *gparam = type->data.generic_param;
4089 g_assert (gparam->owner && !gparam->owner->is_anonymous);
4091 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
4093 MonoClass *base_class = mono_defaults.object_class;
4095 if (constraints) {
4096 int i;
4097 for (i = 0; constraints [i]; ++i) {
4098 MonoClass *constraint = constraints[i];
4100 if (MONO_CLASS_IS_INTERFACE_INTERNAL (constraint))
4101 continue;
4103 MonoType *constraint_type = m_class_get_byval_arg (constraint);
4104 if (mono_type_is_generic_argument (constraint_type)) {
4105 MonoGenericParam *constraint_param = constraint_type->data.generic_param;
4106 MonoGenericParamInfo *constraint_info = mono_generic_param_info (constraint_param);
4107 if ((constraint_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0 &&
4108 (constraint_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) == 0)
4109 continue;
4112 base_class = constraint;
4117 if (base_class == mono_defaults.object_class)
4119 MonoGenericParamInfo *gparam_info = mono_generic_param_info (gparam);
4120 if ((gparam_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0) {
4121 base_class = mono_class_get_valuetype_class ();
4125 return base_class;
4129 * mono_class_get_cctor:
4130 * \param klass A MonoClass pointer
4132 * \returns The static constructor of \p klass if it exists, NULL otherwise.
4134 MonoMethod*
4135 mono_class_get_cctor (MonoClass *klass)
4137 MonoMethod *result = NULL;
4138 ERROR_DECL (error);
4139 MonoCachedClassInfo cached_info;
4141 if (image_is_dynamic (m_class_get_image (klass))) {
4143 * has_cctor is not set for these classes because mono_class_init_internal () is
4144 * not run for them.
4146 result = mono_class_get_method_from_name_checked (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME, error);
4147 mono_error_assert_msg_ok (error, "Could not lookup class cctor in dynamic image");
4148 return result;
4151 mono_class_init_internal (klass);
4153 if (!m_class_has_cctor (klass))
4154 return result;
4156 if (mono_class_is_ginst (klass) && !m_class_get_methods (klass)) {
4157 result = mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class), error);
4158 mono_error_assert_msg_ok (error, "Could not lookup inflated class cctor"); /* FIXME do proper error handling */
4159 return result;
4162 if (mono_class_get_cached_class_info (klass, &cached_info)) {
4163 result = mono_get_method_checked (m_class_get_image (klass), cached_info.cctor_token, klass, NULL, error);
4164 mono_error_assert_msg_ok (error, "Could not lookup class cctor from cached metadata");
4165 return result;
4168 result = mono_class_get_method_from_name_checked (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME, error);
4169 mono_error_assert_msg_ok (error, "Could not lookup class cctor");
4170 return result;
4174 * mono_class_get_finalizer:
4175 * \param klass: The MonoClass pointer
4177 * \returns The finalizer method of \p klass if it exists, NULL otherwise.
4179 MonoMethod*
4180 mono_class_get_finalizer (MonoClass *klass)
4182 MonoCachedClassInfo cached_info;
4184 if (!m_class_is_inited (klass))
4185 mono_class_init_internal (klass);
4186 if (!mono_class_has_finalizer (klass))
4187 return NULL;
4189 if (mono_class_get_cached_class_info (klass, &cached_info)) {
4190 ERROR_DECL (error);
4191 MonoMethod *result = mono_get_method_checked (cached_info.finalize_image, cached_info.finalize_token, NULL, NULL, error);
4192 mono_error_assert_msg_ok (error, "Could not lookup finalizer from cached metadata");
4193 return result;
4194 }else {
4195 mono_class_setup_vtable (klass);
4196 return m_class_get_vtable (klass) [mono_class_get_object_finalize_slot ()];
4201 * mono_class_needs_cctor_run:
4202 * \param klass the MonoClass pointer
4203 * \param caller a MonoMethod describing the caller
4205 * Determines whenever the class has a static constructor and whenever it
4206 * needs to be called when executing CALLER.
4208 gboolean
4209 mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
4211 MonoMethod *method;
4213 method = mono_class_get_cctor (klass);
4214 if (method)
4215 return (method == caller) ? FALSE : TRUE;
4216 else
4217 return FALSE;
4221 * mono_class_array_element_size:
4222 * \param klass
4224 * \returns The number of bytes an element of type \p klass uses when stored into an array.
4226 gint32
4227 mono_class_array_element_size (MonoClass *klass)
4229 MonoType *type = m_class_get_byval_arg (klass);
4231 handle_enum:
4232 switch (type->type) {
4233 case MONO_TYPE_I1:
4234 case MONO_TYPE_U1:
4235 case MONO_TYPE_BOOLEAN:
4236 return 1;
4237 case MONO_TYPE_I2:
4238 case MONO_TYPE_U2:
4239 case MONO_TYPE_CHAR:
4240 return 2;
4241 case MONO_TYPE_I4:
4242 case MONO_TYPE_U4:
4243 case MONO_TYPE_R4:
4244 return 4;
4245 case MONO_TYPE_I:
4246 case MONO_TYPE_U:
4247 case MONO_TYPE_PTR:
4248 case MONO_TYPE_CLASS:
4249 case MONO_TYPE_STRING:
4250 case MONO_TYPE_OBJECT:
4251 case MONO_TYPE_SZARRAY:
4252 case MONO_TYPE_ARRAY:
4253 return TARGET_SIZEOF_VOID_P;
4254 case MONO_TYPE_I8:
4255 case MONO_TYPE_U8:
4256 case MONO_TYPE_R8:
4257 return 8;
4258 case MONO_TYPE_VALUETYPE:
4259 if (m_class_is_enumtype (type->data.klass)) {
4260 type = mono_class_enum_basetype_internal (type->data.klass);
4261 klass = m_class_get_element_class (klass);
4262 goto handle_enum;
4264 return mono_class_value_size (klass, NULL);
4265 case MONO_TYPE_GENERICINST:
4266 type = m_class_get_byval_arg (type->data.generic_class->container_class);
4267 goto handle_enum;
4268 case MONO_TYPE_VAR:
4269 case MONO_TYPE_MVAR: {
4270 int align;
4272 return mono_type_size (type, &align);
4274 case MONO_TYPE_VOID:
4275 return 0;
4277 default:
4278 g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
4280 return -1;
4284 * mono_array_element_size:
4285 * \param ac pointer to a \c MonoArrayClass
4287 * \returns The size of single array element.
4289 * LOCKING: Acquires the loader lock.
4291 gint32
4292 mono_array_element_size (MonoClass *ac)
4294 g_assert (m_class_get_rank (ac));
4295 if (G_UNLIKELY (!m_class_is_size_inited (ac))) {
4296 mono_class_setup_fields (ac);
4298 return m_class_get_sizes (ac).element_size;
4302 * mono_ldtoken:
4304 gpointer
4305 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
4306 MonoGenericContext *context)
4308 ERROR_DECL (error);
4309 gpointer res = mono_ldtoken_checked (image, token, handle_class, context, error);
4310 mono_error_assert_ok (error);
4311 return res;
4314 gpointer
4315 mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
4316 MonoGenericContext *context, MonoError *error)
4318 error_init (error);
4320 if (image_is_dynamic (image)) {
4321 MonoClass *tmp_handle_class;
4322 gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
4324 mono_error_assert_ok (error);
4325 g_assert (tmp_handle_class);
4326 if (handle_class)
4327 *handle_class = tmp_handle_class;
4329 if (tmp_handle_class == mono_defaults.typehandle_class)
4330 return m_class_get_byval_arg ((MonoClass*)obj);
4331 else
4332 return obj;
4335 switch (token & 0xff000000) {
4336 case MONO_TOKEN_TYPE_DEF:
4337 case MONO_TOKEN_TYPE_REF:
4338 case MONO_TOKEN_TYPE_SPEC: {
4339 MonoType *type;
4340 if (handle_class)
4341 *handle_class = mono_defaults.typehandle_class;
4342 type = mono_type_get_checked (image, token, context, error);
4343 if (!type)
4344 return NULL;
4346 mono_class_init_internal (mono_class_from_mono_type_internal (type));
4347 /* We return a MonoType* as handle */
4348 return type;
4350 case MONO_TOKEN_FIELD_DEF: {
4351 MonoClass *klass;
4352 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
4353 if (!type) {
4354 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
4355 return NULL;
4357 if (handle_class)
4358 *handle_class = mono_defaults.fieldhandle_class;
4359 klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_DEF | type, context, error);
4360 if (!klass)
4361 return NULL;
4363 mono_class_init_internal (klass);
4364 return mono_class_get_field (klass, token);
4366 case MONO_TOKEN_METHOD_DEF:
4367 case MONO_TOKEN_METHOD_SPEC: {
4368 MonoMethod *meth;
4369 meth = mono_get_method_checked (image, token, NULL, context, error);
4370 if (handle_class)
4371 *handle_class = mono_defaults.methodhandle_class;
4372 if (!meth)
4373 return NULL;
4375 return meth;
4377 case MONO_TOKEN_MEMBER_REF: {
4378 guint32 cols [MONO_MEMBERREF_SIZE];
4379 const char *sig;
4380 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE);
4381 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
4382 mono_metadata_decode_blob_size (sig, &sig);
4383 if (*sig == 0x6) { /* it's a field */
4384 MonoClass *klass;
4385 MonoClassField *field;
4386 field = mono_field_from_token_checked (image, token, &klass, context, error);
4387 if (handle_class)
4388 *handle_class = mono_defaults.fieldhandle_class;
4389 return field;
4390 } else {
4391 MonoMethod *meth;
4392 meth = mono_get_method_checked (image, token, NULL, context, error);
4393 if (handle_class)
4394 *handle_class = mono_defaults.methodhandle_class;
4395 return meth;
4398 default:
4399 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
4401 return NULL;
4404 gpointer
4405 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
4407 MonoClass *handle_class;
4408 error_init (error);
4409 return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
4412 gpointer
4413 mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
4415 return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
4418 static MonoGetCachedClassInfo get_cached_class_info = NULL;
4420 void
4421 mono_install_get_cached_class_info (MonoGetCachedClassInfo func)
4423 get_cached_class_info = func;
4426 gboolean
4427 mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
4429 if (!get_cached_class_info)
4430 return FALSE;
4431 else
4432 return get_cached_class_info (klass, res);
4435 void
4436 mono_install_get_class_from_name (MonoGetClassFromName func)
4438 get_class_from_name = func;
4442 * mono_class_get_image:
4444 * Use this method to get the \c MonoImage* where this class came from.
4446 * \returns The image where this class is defined.
4448 MonoImage*
4449 mono_class_get_image (MonoClass *klass)
4451 return m_class_get_image (klass);
4455 * mono_class_get_element_class:
4456 * \param klass the \c MonoClass to act on
4458 * Use this function to get the element class of an array.
4460 * \returns The element class of an array.
4462 MonoClass*
4463 mono_class_get_element_class (MonoClass *klass)
4465 MonoClass *result;
4466 MONO_ENTER_GC_UNSAFE;
4467 result = m_class_get_element_class (klass);
4468 MONO_EXIT_GC_UNSAFE;
4469 return result;
4473 * mono_class_is_valuetype:
4474 * \param klass the \c MonoClass to act on
4476 * Use this method to determine if the provided \c MonoClass* represents a value type,
4477 * or a reference type.
4479 * \returns TRUE if the \c MonoClass represents a \c ValueType, FALSE if it represents a reference type.
4481 gboolean
4482 mono_class_is_valuetype (MonoClass *klass)
4484 gboolean result;
4485 MONO_ENTER_GC_UNSAFE;
4486 result = m_class_is_valuetype (klass);
4487 MONO_EXIT_GC_UNSAFE;
4488 return result;
4492 * mono_class_is_enum:
4493 * \param klass the \c MonoClass to act on
4495 * Use this function to determine if the provided \c MonoClass* represents an enumeration.
4497 * \returns TRUE if the \c MonoClass represents an enumeration.
4499 gboolean
4500 mono_class_is_enum (MonoClass *klass)
4502 gboolean result;
4503 MONO_ENTER_GC_UNSAFE;
4504 result = m_class_is_enumtype (klass);
4505 MONO_EXIT_GC_UNSAFE;
4506 return result;
4510 * mono_class_enum_basetype_internal:
4511 * \param klass the \c MonoClass to act on
4513 * Use this function to get the underlying type for an enumeration value.
4515 * \returns The underlying type representation for an enumeration.
4517 MonoType*
4518 mono_class_enum_basetype_internal (MonoClass *klass)
4520 if (m_class_get_element_class (klass) == klass)
4521 /* SRE or broken types */
4522 return NULL;
4523 return m_class_get_byval_arg (m_class_get_element_class (klass));
4527 * mono_class_enum_basetype:
4528 * \param klass the \c MonoClass to act on
4530 * Use this function to get the underlying type for an enumeration value.
4532 * \returns The underlying type representation for an enumeration.
4534 MonoType*
4535 mono_class_enum_basetype (MonoClass *klass)
4537 MonoType *res;
4538 MONO_ENTER_GC_UNSAFE;
4539 res = mono_class_enum_basetype_internal (klass);
4540 MONO_EXIT_GC_UNSAFE;
4541 return res;
4545 * mono_class_get_parent
4546 * \param klass the \c MonoClass to act on
4548 * \returns The parent class for this class.
4550 MonoClass*
4551 mono_class_get_parent (MonoClass *klass)
4553 MonoClass *result;
4554 MONO_ENTER_GC_UNSAFE;
4555 result = m_class_get_parent (klass);
4556 MONO_EXIT_GC_UNSAFE;
4557 return result;
4561 * mono_class_get_nesting_type:
4562 * \param klass the \c MonoClass to act on
4564 * Use this function to obtain the class that the provided \c MonoClass* is nested on.
4566 * If the return is NULL, this indicates that this class is not nested.
4568 * \returns The container type where this type is nested or NULL if this type is not a nested type.
4570 MonoClass*
4571 mono_class_get_nesting_type (MonoClass *klass)
4573 return m_class_get_nested_in (klass);
4577 * mono_class_get_rank:
4578 * \param klass the MonoClass to act on
4580 * \returns The rank for the array (the number of dimensions).
4583 mono_class_get_rank (MonoClass *klass)
4585 return m_class_get_rank (klass);
4589 * mono_class_get_name
4590 * \param klass the \c MonoClass to act on
4592 * \returns The name of the class.
4594 const char*
4595 mono_class_get_name (MonoClass *klass)
4597 const char *result;
4598 MONO_ENTER_GC_UNSAFE;
4599 result = m_class_get_name (klass);
4600 MONO_EXIT_GC_UNSAFE;
4601 return result;
4605 * mono_class_get_namespace:
4606 * \param klass the \c MonoClass to act on
4608 * \returns The namespace of the class.
4610 const char*
4611 mono_class_get_namespace (MonoClass *klass)
4613 const char *result;
4614 MONO_ENTER_GC_UNSAFE;
4615 result = m_class_get_name_space (klass);
4616 MONO_EXIT_GC_UNSAFE;
4617 return result;
4621 * mono_class_get_type:
4622 * \param klass the \c MonoClass to act on
4624 * This method returns the internal \c MonoType representation for the class.
4626 * \returns The \c MonoType from the class.
4628 MonoType*
4629 mono_class_get_type (MonoClass *klass)
4631 return m_class_get_byval_arg (klass);
4635 * mono_class_get_type_token:
4636 * \param klass the \c MonoClass to act on
4638 * This method returns type token for the class.
4640 * \returns The type token for the class.
4642 guint32
4643 mono_class_get_type_token (MonoClass *klass)
4645 return m_class_get_type_token (klass);
4649 * mono_class_get_byref_type:
4650 * \param klass the \c MonoClass to act on
4654 MonoType*
4655 mono_class_get_byref_type (MonoClass *klass)
4657 return m_class_get_this_arg (klass);
4661 * mono_class_num_fields:
4662 * \param klass the \c MonoClass to act on
4664 * \returns The number of static and instance fields in the class.
4667 mono_class_num_fields (MonoClass *klass)
4669 return mono_class_get_field_count (klass);
4673 * mono_class_num_methods:
4674 * \param klass the \c MonoClass to act on
4676 * \returns The number of methods in the class.
4679 mono_class_num_methods (MonoClass *klass)
4681 return mono_class_get_method_count (klass);
4685 * mono_class_num_properties
4686 * \param klass the \c MonoClass to act on
4688 * \returns The number of properties in the class.
4691 mono_class_num_properties (MonoClass *klass)
4693 mono_class_setup_properties (klass);
4695 return mono_class_get_property_info (klass)->count;
4699 * mono_class_num_events:
4700 * \param klass the \c MonoClass to act on
4702 * \returns The number of events in the class.
4705 mono_class_num_events (MonoClass *klass)
4707 mono_class_setup_events (klass);
4709 return mono_class_get_event_info (klass)->count;
4713 * mono_class_get_fields:
4714 * \param klass the \c MonoClass to act on
4716 * This routine is an iterator routine for retrieving the fields in a class.
4718 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4719 * iterate over all of the elements. When no more values are
4720 * available, the return value is NULL.
4722 * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
4724 MonoClassField*
4725 mono_class_get_fields (MonoClass* klass, gpointer *iter)
4727 MonoClassField *result;
4728 MONO_ENTER_GC_UNSAFE;
4729 result = mono_class_get_fields_internal (klass, iter);
4730 MONO_EXIT_GC_UNSAFE;
4731 return result;
4734 MonoClassField*
4735 mono_class_get_fields_internal (MonoClass *klass, gpointer *iter)
4737 MonoClassField* field;
4738 if (!iter)
4739 return NULL;
4740 if (!*iter) {
4741 mono_class_setup_fields (klass);
4742 if (mono_class_has_failure (klass))
4743 return NULL;
4744 /* start from the first */
4745 if (mono_class_get_field_count (klass)) {
4746 MonoClassField *klass_fields = m_class_get_fields (klass);
4747 *iter = &klass_fields [0];
4748 return &klass_fields [0];
4749 } else {
4750 /* no fields */
4751 return NULL;
4754 field = (MonoClassField *)*iter;
4755 field++;
4756 if (field < &m_class_get_fields (klass) [mono_class_get_field_count (klass)]) {
4757 *iter = field;
4758 return field;
4760 return NULL;
4764 * mono_class_get_methods:
4765 * \param klass the \c MonoClass to act on
4767 * This routine is an iterator routine for retrieving the fields in a class.
4769 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4770 * iterate over all of the elements. When no more values are
4771 * available, the return value is NULL.
4773 * \returns a \c MonoMethod on each iteration or NULL when no more methods are available.
4775 MonoMethod*
4776 mono_class_get_methods (MonoClass* klass, gpointer *iter)
4778 MonoMethod** method;
4779 if (!iter)
4780 return NULL;
4781 if (!*iter) {
4782 mono_class_setup_methods (klass);
4784 MonoMethod **klass_methods = m_class_get_methods (klass);
4786 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
4787 * FIXME we should better report this error to the caller
4789 if (!klass_methods)
4790 return NULL;
4791 /* start from the first */
4792 if (mono_class_get_method_count (klass)) {
4793 *iter = &klass_methods [0];
4794 return klass_methods [0];
4795 } else {
4796 /* no method */
4797 return NULL;
4800 method = (MonoMethod **)*iter;
4801 method++;
4802 if (method < &m_class_get_methods (klass) [mono_class_get_method_count (klass)]) {
4803 *iter = method;
4804 return *method;
4806 return NULL;
4810 * mono_class_get_properties:
4811 * \param klass the \c MonoClass to act on
4813 * This routine is an iterator routine for retrieving the properties in a class.
4815 * You must pass a gpointer that points to zero and is treated as an opaque handle to
4816 * iterate over all of the elements. When no more values are
4817 * available, the return value is NULL.
4819 * Returns: a \c MonoProperty* on each invocation, or NULL when no more are available.
4821 MonoProperty*
4822 mono_class_get_properties (MonoClass* klass, gpointer *iter)
4824 MonoProperty* property;
4825 if (!iter)
4826 return NULL;
4827 if (!*iter) {
4828 mono_class_setup_properties (klass);
4829 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
4830 /* start from the first */
4831 if (info->count) {
4832 *iter = &info->properties [0];
4833 return (MonoProperty *)*iter;
4834 } else {
4835 /* no fields */
4836 return NULL;
4839 property = (MonoProperty *)*iter;
4840 property++;
4841 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
4842 if (property < &info->properties [info->count]) {
4843 *iter = property;
4844 return (MonoProperty *)*iter;
4846 return NULL;
4850 * mono_class_get_events:
4851 * \param klass the \c MonoClass to act on
4853 * This routine is an iterator routine for retrieving the properties in a class.
4855 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4856 * iterate over all of the elements. When no more values are
4857 * available, the return value is NULL.
4859 * \returns a \c MonoEvent* on each invocation, or NULL when no more are available.
4861 MonoEvent*
4862 mono_class_get_events (MonoClass* klass, gpointer *iter)
4864 MonoEvent* event;
4865 if (!iter)
4866 return NULL;
4867 if (!*iter) {
4868 mono_class_setup_events (klass);
4869 MonoClassEventInfo *info = mono_class_get_event_info (klass);
4870 /* start from the first */
4871 if (info->count) {
4872 *iter = &info->events [0];
4873 return (MonoEvent *)*iter;
4874 } else {
4875 /* no fields */
4876 return NULL;
4879 event = (MonoEvent *)*iter;
4880 event++;
4881 MonoClassEventInfo *info = mono_class_get_event_info (klass);
4882 if (event < &info->events [info->count]) {
4883 *iter = event;
4884 return (MonoEvent *)*iter;
4886 return NULL;
4890 * mono_class_get_interfaces
4891 * \param klass the \c MonoClass to act on
4893 * This routine is an iterator routine for retrieving the interfaces implemented by this class.
4895 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4896 * iterate over all of the elements. When no more values are
4897 * available, the return value is NULL.
4899 * \returns a \c MonoClass* on each invocation, or NULL when no more are available.
4901 MonoClass*
4902 mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
4904 ERROR_DECL (error);
4905 MonoClass** iface;
4906 if (!iter)
4907 return NULL;
4908 if (!*iter) {
4909 if (!m_class_is_inited (klass))
4910 mono_class_init_internal (klass);
4911 if (!m_class_is_interfaces_inited (klass)) {
4912 mono_class_setup_interfaces (klass, error);
4913 if (!is_ok (error)) {
4914 mono_error_cleanup (error);
4915 return NULL;
4918 /* start from the first */
4919 if (m_class_get_interface_count (klass)) {
4920 *iter = &m_class_get_interfaces (klass) [0];
4921 return m_class_get_interfaces (klass) [0];
4922 } else {
4923 /* no interface */
4924 return NULL;
4927 iface = (MonoClass **)*iter;
4928 iface++;
4929 if (iface < &m_class_get_interfaces (klass) [m_class_get_interface_count (klass)]) {
4930 *iter = iface;
4931 return *iface;
4933 return NULL;
4937 * mono_class_get_nested_types
4938 * \param klass the \c MonoClass to act on
4940 * This routine is an iterator routine for retrieving the nested types of a class.
4941 * This works only if \p klass is non-generic, or a generic type definition.
4943 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4944 * iterate over all of the elements. When no more values are
4945 * available, the return value is NULL.
4947 * \returns a \c Monoclass* on each invocation, or NULL when no more are available.
4949 MonoClass*
4950 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
4952 GList *item;
4954 if (!iter)
4955 return NULL;
4956 if (!m_class_is_nested_classes_inited (klass))
4957 mono_class_setup_nested_types (klass);
4959 if (!*iter) {
4960 GList *nested_classes = mono_class_get_nested_classes_property (klass);
4961 /* start from the first */
4962 if (nested_classes) {
4963 *iter = nested_classes;
4964 return (MonoClass *)nested_classes->data;
4965 } else {
4966 /* no nested types */
4967 return NULL;
4970 item = (GList *)*iter;
4971 item = item->next;
4972 if (item) {
4973 *iter = item;
4974 return (MonoClass *)item->data;
4976 return NULL;
4981 * mono_class_is_delegate
4982 * \param klass the \c MonoClass to act on
4984 * \returns TRUE if the \c MonoClass represents a \c System.Delegate.
4986 mono_bool
4987 mono_class_is_delegate (MonoClass *klass)
4989 mono_bool result;
4990 MONO_ENTER_GC_UNSAFE;
4991 result = m_class_is_delegate (klass);
4992 MONO_EXIT_GC_UNSAFE;
4993 return result;
4997 * mono_class_implements_interface
4998 * \param klass The MonoClass to act on
4999 * \param interface The interface to check if \p klass implements.
5001 * \returns TRUE if \p klass implements \p interface.
5003 mono_bool
5004 mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
5006 return mono_class_is_assignable_from_internal (iface, klass);
5009 static mono_bool
5010 class_implements_interface_ignore_generics (MonoClass* klass, MonoClass* iface)
5012 int i;
5013 ERROR_DECL (error);
5014 if (mono_class_is_ginst (iface))
5015 iface = mono_class_get_generic_type_definition (iface);
5016 while (klass != NULL) {
5017 if (mono_class_is_assignable_from_internal (iface, klass))
5018 return TRUE;
5019 mono_class_setup_interfaces (klass, error);
5020 if (!is_ok (error)) {
5021 mono_error_cleanup (error);
5022 return FALSE;
5024 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
5025 for (i = 0; i < m_class_get_interface_count (klass); i++) {
5026 MonoClass *ic = klass_interfaces [i];
5027 if (mono_class_is_ginst (ic))
5028 ic = mono_class_get_generic_type_definition (ic);
5029 if (ic == iface) {
5030 return TRUE;
5033 klass = m_class_get_parent (klass);
5035 return FALSE;
5040 * mono_field_get_name:
5041 * \param field the \c MonoClassField to act on
5043 * \returns The name of the field.
5045 const char*
5046 mono_field_get_name (MonoClassField *field)
5048 return field->name;
5052 * mono_field_get_type_internal:
5053 * \param field the \c MonoClassField to act on
5054 * \returns \c MonoType of the field.
5056 MonoType*
5057 mono_field_get_type_internal (MonoClassField *field)
5059 MonoType *type = field->type;
5060 if (type)
5061 return type;
5063 ERROR_DECL (error);
5064 type = mono_field_get_type_checked (field, error);
5065 if (!is_ok (error)) {
5066 mono_trace_warning (MONO_TRACE_TYPE, "Could not load field's type due to %s", mono_error_get_message (error));
5067 mono_error_cleanup (error);
5069 return type;
5073 * mono_field_get_type:
5074 * \param field the \c MonoClassField to act on
5075 * \returns \c MonoType of the field.
5077 MonoType*
5078 mono_field_get_type (MonoClassField *field)
5080 MonoType *type = field->type;
5081 if (type)
5082 return type;
5084 MONO_ENTER_GC_UNSAFE;
5085 type = mono_field_get_type_internal (field);
5086 MONO_EXIT_GC_UNSAFE;
5087 return type;
5091 * mono_field_get_type_checked:
5092 * \param field the \c MonoClassField to act on
5093 * \param error used to return any error found while retrieving \p field type
5095 * \returns \c MonoType of the field.
5097 MonoType*
5098 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
5100 error_init (error);
5101 MonoType *type = field->type;
5102 if (type)
5103 return type;
5104 mono_field_resolve_type (field, error);
5105 return field->type;
5109 * mono_field_get_parent:
5110 * \param field the \c MonoClassField to act on
5112 * \returns \c MonoClass where the field was defined.
5114 MonoClass*
5115 mono_field_get_parent (MonoClassField *field)
5117 return field->parent;
5121 * mono_field_get_flags;
5122 * \param field the \c MonoClassField to act on
5124 * The metadata flags for a field are encoded using the
5125 * \c FIELD_ATTRIBUTE_* constants. See the \c tabledefs.h file for details.
5127 * \returns The flags for the field.
5129 guint32
5130 mono_field_get_flags (MonoClassField *field)
5132 if (!field->type)
5133 return mono_field_resolve_flags (field);
5134 return field->type->attrs;
5138 * mono_field_get_offset:
5139 * \param field the \c MonoClassField to act on
5141 * \returns The field offset.
5143 guint32
5144 mono_field_get_offset (MonoClassField *field)
5146 mono_class_setup_fields(field->parent);
5147 return field->offset;
5150 static const char *
5151 mono_field_get_rva (MonoClassField *field)
5153 guint32 rva;
5154 int field_index;
5155 MonoClass *klass = field->parent;
5156 MonoFieldDefaultValue *def_values;
5158 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
5160 def_values = mono_class_get_field_def_values (klass);
5161 if (!def_values) {
5162 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
5164 mono_class_set_field_def_values (klass, def_values);
5167 field_index = mono_field_get_index (field);
5169 if (!def_values [field_index].data && !image_is_dynamic (m_class_get_image (klass))) {
5170 int first_field_idx = mono_class_get_first_field_idx (klass);
5171 mono_metadata_field_info (m_class_get_image (field->parent), first_field_idx + field_index, NULL, &rva, NULL);
5172 if (!rva)
5173 g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), m_class_get_name (field->parent));
5174 def_values [field_index].data = mono_image_rva_map (m_class_get_image (field->parent), rva);
5177 return def_values [field_index].data;
5181 * mono_field_get_data:
5182 * \param field the \c MonoClassField to act on
5184 * \returns A pointer to the metadata constant value or to the field
5185 * data if it has an RVA flag.
5187 const char *
5188 mono_field_get_data (MonoClassField *field)
5190 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
5191 MonoTypeEnum def_type;
5193 return mono_class_get_field_default_value (field, &def_type);
5194 } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
5195 return mono_field_get_rva (field);
5196 } else {
5197 return NULL;
5202 * mono_property_get_name:
5203 * \param prop the \c MonoProperty to act on
5204 * \returns The name of the property
5206 const char*
5207 mono_property_get_name (MonoProperty *prop)
5209 return prop->name;
5213 * mono_property_get_set_method
5214 * \param prop the \c MonoProperty to act on.
5215 * \returns The setter method of the property, a \c MonoMethod.
5217 MonoMethod*
5218 mono_property_get_set_method (MonoProperty *prop)
5220 return prop->set;
5224 * mono_property_get_get_method
5225 * \param prop the MonoProperty to act on.
5226 * \returns The getter method of the property (A \c MonoMethod)
5228 MonoMethod*
5229 mono_property_get_get_method (MonoProperty *prop)
5231 return prop->get;
5235 * mono_property_get_parent:
5236 * \param prop the \c MonoProperty to act on.
5237 * \returns The \c MonoClass where the property was defined.
5239 MonoClass*
5240 mono_property_get_parent (MonoProperty *prop)
5242 return prop->parent;
5246 * mono_property_get_flags:
5247 * \param prop the \c MonoProperty to act on.
5249 * The metadata flags for a property are encoded using the
5250 * \c PROPERTY_ATTRIBUTE_* constants. See the \c tabledefs.h file for details.
5252 * \returns The flags for the property.
5254 guint32
5255 mono_property_get_flags (MonoProperty *prop)
5257 return prop->attrs;
5261 * mono_event_get_name:
5262 * \param event the MonoEvent to act on
5263 * \returns The name of the event.
5265 const char*
5266 mono_event_get_name (MonoEvent *event)
5268 return event->name;
5272 * mono_event_get_add_method:
5273 * \param event The \c MonoEvent to act on.
5274 * \returns The \c add method for the event, a \c MonoMethod.
5276 MonoMethod*
5277 mono_event_get_add_method (MonoEvent *event)
5279 return event->add;
5283 * mono_event_get_remove_method:
5284 * \param event The \c MonoEvent to act on.
5285 * \returns The \c remove method for the event, a \c MonoMethod.
5287 MonoMethod*
5288 mono_event_get_remove_method (MonoEvent *event)
5290 return event->remove;
5294 * mono_event_get_raise_method:
5295 * \param event The \c MonoEvent to act on.
5296 * \returns The \c raise method for the event, a \c MonoMethod.
5298 MonoMethod*
5299 mono_event_get_raise_method (MonoEvent *event)
5301 return event->raise;
5305 * mono_event_get_parent:
5306 * \param event the MonoEvent to act on.
5307 * \returns The \c MonoClass where the event is defined.
5309 MonoClass*
5310 mono_event_get_parent (MonoEvent *event)
5312 return event->parent;
5316 * mono_event_get_flags
5317 * \param event the \c MonoEvent to act on.
5319 * The metadata flags for an event are encoded using the
5320 * \c EVENT_* constants. See the \c tabledefs.h file for details.
5322 * \returns The flags for the event.
5324 guint32
5325 mono_event_get_flags (MonoEvent *event)
5327 return event->attrs;
5331 * mono_class_get_method_from_name:
5332 * \param klass where to look for the method
5333 * \param name name of the method
5334 * \param param_count number of parameters. -1 for any number.
5336 * Obtains a \c MonoMethod with a given name and number of parameters.
5337 * It only works if there are no multiple signatures for any given method name.
5339 MonoMethod *
5340 mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_count)
5342 MonoMethod *result;
5343 MONO_ENTER_GC_UNSAFE;
5344 ERROR_DECL (error);
5345 result = mono_class_get_method_from_name_checked (klass, name, param_count, 0, error);
5346 mono_error_cleanup (error);
5347 MONO_EXIT_GC_UNSAFE;
5348 return result;
5351 MonoMethod*
5352 mono_find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
5354 MonoImage *klass_image = m_class_get_image (klass);
5355 MonoMethod *res = NULL;
5356 int i;
5358 /* Search directly in the metadata to avoid calling setup_methods () */
5359 int first_idx = mono_class_get_first_method_idx (klass);
5360 int mcount = mono_class_get_method_count (klass);
5361 for (i = 0; i < mcount; ++i) {
5362 ERROR_DECL (error);
5363 guint32 cols [MONO_METHOD_SIZE];
5364 MonoMethod *method;
5365 MonoMethodSignature *sig;
5367 /* first_idx points into the methodptr table */
5368 mono_metadata_decode_table_row (klass_image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE);
5370 if (!strcmp (mono_metadata_string_heap (klass_image, cols [MONO_METHOD_NAME]), name)) {
5371 method = mono_get_method_checked (klass_image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error);
5372 if (!method) {
5373 mono_error_cleanup (error); /* FIXME don't swallow the error */
5374 continue;
5376 if (param_count == -1) {
5377 res = method;
5378 break;
5380 sig = mono_method_signature_checked (method, error);
5381 if (!sig) {
5382 mono_error_cleanup (error); /* FIXME don't swallow the error */
5383 continue;
5385 if (sig->param_count == param_count) {
5386 res = method;
5387 break;
5392 return res;
5396 * mono_class_get_method_from_name_flags:
5397 * \param klass where to look for the method
5398 * \param name_space name of the method
5399 * \param param_count number of parameters. -1 for any number.
5400 * \param flags flags which must be set in the method
5402 * Obtains a \c MonoMethod with a given name and number of parameters.
5403 * It only works if there are no multiple signatures for any given method name.
5405 MonoMethod *
5406 mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int param_count, int flags)
5408 MonoMethod *method;
5409 MONO_ENTER_GC_UNSAFE;
5410 ERROR_DECL (error);
5411 method = mono_class_get_method_from_name_checked (klass, name, param_count, flags, error);
5412 mono_error_cleanup (error);
5413 MONO_EXIT_GC_UNSAFE;
5414 return method;
5418 * mono_class_get_method_from_name_checked:
5419 * \param klass where to look for the method
5420 * \param name_space name of the method
5421 * \param param_count number of parameters. -1 for any number.
5422 * \param flags flags which must be set in the method
5423 * \param error
5425 * Obtains a \c MonoMethod with a given name and number of parameters.
5426 * It only works if there are no multiple signatures for any given method name.
5428 MonoMethod *
5429 mono_class_get_method_from_name_checked (MonoClass *klass, const char *name,
5430 int param_count, int flags, MonoError *error)
5432 MonoMethod *res = NULL;
5433 int i;
5435 mono_class_init_internal (klass);
5437 if (mono_class_is_ginst (klass) && !m_class_get_methods (klass)) {
5438 res = mono_class_get_method_from_name_checked (mono_class_get_generic_class (klass)->container_class, name, param_count, flags, error);
5440 if (res)
5441 res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), error);
5443 return res;
5446 if (m_class_get_methods (klass) || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
5447 mono_class_setup_methods (klass);
5449 We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
5450 See mono/tests/array_load_exception.il
5451 FIXME we should better report this error to the caller
5453 MonoMethod **klass_methods = m_class_get_methods (klass);
5454 if (!klass_methods)
5455 return NULL;
5456 int mcount = mono_class_get_method_count (klass);
5457 for (i = 0; i < mcount; ++i) {
5458 MonoMethod *method = klass_methods [i];
5460 if (method->name[0] == name [0] &&
5461 !strcmp (name, method->name) &&
5462 (param_count == -1 || mono_method_signature_internal (method)->param_count == param_count) &&
5463 ((method->flags & flags) == flags)) {
5464 res = method;
5465 break;
5469 else {
5470 res = mono_find_method_in_metadata (klass, name, param_count, flags);
5473 return res;
5476 gboolean
5477 mono_class_has_failure (const MonoClass *klass)
5479 g_assert (klass != NULL);
5480 return m_class_has_failure ((MonoClass*)klass) != 0;
5485 * mono_class_set_type_load_failure:
5486 * \param klass class in which the failure was detected
5487 * \param fmt \c printf -style error message string.
5489 * Collect detected failure informaion in the class for later processing.
5490 * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class()
5491 * Note that only the first failure is kept.
5493 * LOCKING: Acquires the loader lock.
5495 * \returns FALSE if a failure was already set on the class, or TRUE otherwise.
5497 gboolean
5498 mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
5500 ERROR_DECL (prepare_error);
5501 va_list args;
5503 if (mono_class_has_failure (klass))
5504 return FALSE;
5506 va_start (args, fmt);
5507 mono_error_vset_type_load_class (prepare_error, klass, fmt, args);
5508 va_end (args);
5510 MonoErrorBoxed *box = mono_error_box (prepare_error, m_class_get_image (klass));
5511 mono_error_cleanup (prepare_error);
5512 return mono_class_set_failure (klass, box);
5516 * mono_class_get_exception_for_failure:
5517 * \param klass class in which the failure was detected
5519 * \returns a constructed MonoException than the caller can then throw
5520 * using mono_raise_exception - or NULL if no failure is present (or
5521 * doesn't result in an exception).
5523 MonoException*
5524 mono_class_get_exception_for_failure (MonoClass *klass)
5526 if (!mono_class_has_failure (klass))
5527 return NULL;
5528 ERROR_DECL (unboxed_error);
5529 mono_error_set_for_class_failure (unboxed_error, klass);
5530 return mono_error_convert_to_exception (unboxed_error);
5533 static gboolean
5534 is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
5536 outer_klass = mono_class_get_generic_type_definition (outer_klass);
5537 inner_klass = mono_class_get_generic_type_definition (inner_klass);
5538 do {
5539 if (outer_klass == inner_klass)
5540 return TRUE;
5541 inner_klass = m_class_get_nested_in (inner_klass);
5542 } while (inner_klass);
5543 return FALSE;
5546 MonoClass *
5547 mono_class_get_generic_type_definition (MonoClass *klass)
5549 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
5550 return gklass ? gklass->container_class : klass;
5554 * Check if @klass is a subtype of @parent ignoring generic instantiations.
5556 * Generic instantiations are ignored for all super types of @klass.
5558 * Visibility checks ignoring generic instantiations.
5560 * Class implementing interface visibility checks ignore generic instantiations
5562 gboolean
5563 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
5565 int i;
5566 klass = mono_class_get_generic_type_definition (klass);
5567 parent = mono_class_get_generic_type_definition (parent);
5568 mono_class_setup_supertypes (klass);
5570 for (i = 0; i < m_class_get_idepth (klass); ++i) {
5571 if (parent == mono_class_get_generic_type_definition (m_class_get_supertypes (klass) [i]))
5572 return TRUE;
5575 if (MONO_CLASS_IS_INTERFACE_INTERNAL (parent) && class_implements_interface_ignore_generics (klass, parent))
5576 return TRUE;
5578 return FALSE;
5581 * Subtype can only access parent members with family protection if the site object
5582 * is subclass of Subtype. For example:
5583 * class A { protected int x; }
5584 * class B : A {
5585 * void valid_access () {
5586 * B b;
5587 * b.x = 0;
5589 * void invalid_access () {
5590 * A a;
5591 * a.x = 0;
5594 * */
5595 static gboolean
5596 is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
5598 if (MONO_CLASS_IS_INTERFACE_INTERNAL (member_klass) && !MONO_CLASS_IS_INTERFACE_INTERNAL (access_klass)) {
5599 /* Can happen with default interface methods */
5600 if (!class_implements_interface_ignore_generics (access_klass, member_klass))
5601 return FALSE;
5602 } else if (member_klass != access_klass && MONO_CLASS_IS_INTERFACE_INTERNAL (member_klass) && MONO_CLASS_IS_INTERFACE_INTERNAL (access_klass)) {
5603 /* Can happen with default interface methods */
5604 if (!mono_interface_implements_interface (access_klass, member_klass))
5605 return FALSE;
5606 } else {
5607 if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
5608 return FALSE;
5611 if (context_klass == NULL)
5612 return TRUE;
5613 /*if access_klass is not member_klass context_klass must be type compat*/
5614 if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
5615 return FALSE;
5616 return TRUE;
5619 static gboolean
5620 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
5622 GSList *tmp;
5623 if (accessing == accessed)
5624 return TRUE;
5625 if (!accessed || !accessing)
5626 return FALSE;
5628 /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
5629 * anywhere so untrusted friends are not safe to access platform's code internals */
5630 if (mono_security_core_clr_enabled ()) {
5631 if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
5632 return FALSE;
5635 mono_assembly_load_friends (accessed);
5636 for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
5637 MonoAssemblyName *friend_ = (MonoAssemblyName *)tmp->data;
5638 /* Be conservative with checks */
5639 if (!friend_->name)
5640 continue;
5641 if (g_ascii_strcasecmp (accessing->aname.name, friend_->name))
5642 continue;
5643 if (friend_->public_key_token [0]) {
5644 if (!accessing->aname.public_key_token [0])
5645 continue;
5646 if (!mono_public_tokens_are_equal (friend_->public_key_token, accessing->aname.public_key_token))
5647 continue;
5649 return TRUE;
5651 return FALSE;
5655 * If klass is a generic type or if it is derived from a generic type, return the
5656 * MonoClass of the generic definition
5657 * Returns NULL if not found
5659 static MonoClass*
5660 get_generic_definition_class (MonoClass *klass)
5662 while (klass) {
5663 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
5664 if (gklass && gklass->container_class)
5665 return gklass->container_class;
5666 klass = m_class_get_parent (klass);
5668 return NULL;
5671 static gboolean
5672 can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
5674 int i;
5675 for (i = 0; i < ginst->type_argc; ++i) {
5676 MonoType *type = ginst->type_argv[i];
5677 switch (type->type) {
5678 case MONO_TYPE_SZARRAY:
5679 if (!can_access_type (access_klass, type->data.klass))
5680 return FALSE;
5681 break;
5682 case MONO_TYPE_ARRAY:
5683 if (!can_access_type (access_klass, type->data.array->eklass))
5684 return FALSE;
5685 break;
5686 case MONO_TYPE_PTR:
5687 if (!can_access_type (access_klass, mono_class_from_mono_type_internal (type->data.type)))
5688 return FALSE;
5689 break;
5690 case MONO_TYPE_CLASS:
5691 case MONO_TYPE_VALUETYPE:
5692 case MONO_TYPE_GENERICINST:
5693 if (!can_access_type (access_klass, mono_class_from_mono_type_internal (type)))
5694 return FALSE;
5695 default:
5696 break;
5699 return TRUE;
5702 static gboolean
5703 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
5705 int access_level;
5707 if (access_klass == member_klass)
5708 return TRUE;
5710 MonoAssembly *access_klass_assembly = m_class_get_image (access_klass)->assembly;
5711 MonoAssembly *member_klass_assembly = m_class_get_image (member_klass)->assembly;
5713 if (access_klass_assembly && m_class_get_image (access_klass)->assembly->corlib_internal)
5714 return TRUE;
5716 if (m_class_get_element_class (access_klass) && !m_class_is_enumtype (access_klass)) {
5717 access_klass = m_class_get_element_class (access_klass);
5718 access_klass_assembly = m_class_get_image (access_klass)->assembly;
5721 if (m_class_get_element_class (member_klass) && !m_class_is_enumtype (member_klass)) {
5722 member_klass = m_class_get_element_class (member_klass);
5723 member_klass_assembly = m_class_get_image (member_klass)->assembly;
5726 access_level = mono_class_get_flags (member_klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
5728 if (mono_type_is_generic_argument (m_class_get_byval_arg (member_klass)))
5729 return TRUE;
5731 if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst))
5732 return FALSE;
5734 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)))
5735 return TRUE;
5737 /*Non nested type with nested visibility. We just fail it.*/
5738 if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && m_class_get_nested_in (member_klass) == NULL)
5739 return FALSE;
5741 MonoClass *member_klass_nested_in = m_class_get_nested_in (member_klass);
5742 switch (access_level) {
5743 case TYPE_ATTRIBUTE_NOT_PUBLIC:
5744 return can_access_internals (access_klass_assembly, member_klass_assembly);
5746 case TYPE_ATTRIBUTE_PUBLIC:
5747 return TRUE;
5749 case TYPE_ATTRIBUTE_NESTED_PUBLIC:
5750 return member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
5752 case TYPE_ATTRIBUTE_NESTED_PRIVATE:
5753 return is_nesting_type (member_klass, access_klass) && member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
5755 case TYPE_ATTRIBUTE_NESTED_FAMILY:
5756 return mono_class_has_parent_and_ignore_generics (access_klass, m_class_get_nested_in (member_klass));
5758 case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
5759 return can_access_internals (access_klass_assembly, member_klass_assembly) && member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
5761 case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
5762 return can_access_internals (access_klass_assembly, m_class_get_image (member_klass_nested_in)->assembly) &&
5763 mono_class_has_parent_and_ignore_generics (access_klass, member_klass_nested_in);
5765 case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
5766 return can_access_internals (access_klass_assembly, m_class_get_image (member_klass_nested_in)->assembly) ||
5767 mono_class_has_parent_and_ignore_generics (access_klass, member_klass_nested_in);
5769 return FALSE;
5772 /* FIXME: check visibility of type, too */
5773 static gboolean
5774 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
5776 MonoClass *member_generic_def;
5777 MonoAssembly *access_klass_assembly = m_class_get_image (access_klass)->assembly;
5778 if (access_klass_assembly && access_klass_assembly->corlib_internal)
5779 return TRUE;
5781 MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass);
5782 if (((access_gklass && access_gklass->container_class) ||
5783 mono_class_is_gtd (access_klass)) &&
5784 (member_generic_def = get_generic_definition_class (member_klass))) {
5785 MonoClass *access_container;
5787 if (mono_class_is_gtd (access_klass))
5788 access_container = access_klass;
5789 else
5790 access_container = access_gklass->container_class;
5792 if (can_access_member (access_container, member_generic_def, context_klass, access_level))
5793 return TRUE;
5796 MonoImage *member_klass_image = m_class_get_image (member_klass);
5797 /* Partition I 8.5.3.2 */
5798 /* the access level values are the same for fields and methods */
5799 switch (access_level) {
5800 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
5801 /* same compilation unit */
5802 return m_class_get_image (access_klass) == member_klass_image;
5803 case FIELD_ATTRIBUTE_PRIVATE:
5804 return access_klass == member_klass;
5805 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
5806 if (is_valid_family_access (access_klass, member_klass, context_klass) &&
5807 can_access_internals (access_klass_assembly, member_klass_image->assembly))
5808 return TRUE;
5809 return FALSE;
5810 case FIELD_ATTRIBUTE_ASSEMBLY:
5811 return can_access_internals (access_klass_assembly, member_klass_image->assembly);
5812 case FIELD_ATTRIBUTE_FAMILY:
5813 if (is_valid_family_access (access_klass, member_klass, context_klass))
5814 return TRUE;
5815 return FALSE;
5816 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
5817 if (is_valid_family_access (access_klass, member_klass, context_klass))
5818 return TRUE;
5819 return can_access_internals (access_klass_assembly, member_klass_image->assembly);
5820 case FIELD_ATTRIBUTE_PUBLIC:
5821 return TRUE;
5823 return FALSE;
5827 * mono_method_can_access_field:
5828 * \param method Method that will attempt to access the field
5829 * \param field the field to access
5831 * Used to determine if a method is allowed to access the specified field.
5833 * \returns TRUE if the given \p method is allowed to access the \p field while following
5834 * the accessibility rules of the CLI.
5836 gboolean
5837 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
5839 /* FIXME: check all overlapping fields */
5840 int can = can_access_member (method->klass, field->parent, NULL, mono_field_get_type_internal (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5841 if (!can) {
5842 MonoClass *nested = m_class_get_nested_in (method->klass);
5843 while (nested) {
5844 can = can_access_member (nested, field->parent, NULL, mono_field_get_type_internal (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5845 if (can)
5846 return TRUE;
5847 nested = m_class_get_nested_in (nested);
5850 return can;
5853 static MonoMethod*
5854 mono_method_get_method_definition (MonoMethod *method)
5856 while (method->is_inflated)
5857 method = ((MonoMethodInflated*)method)->declaring;
5858 return method;
5862 * mono_method_can_access_method:
5863 * \param method Method that will attempt to access the other method
5864 * \param called the method that we want to probe for accessibility.
5866 * Used to determine if the \p method is allowed to access the specified \p called method.
5868 * \returns TRUE if the given \p method is allowed to invoke the \p called while following
5869 * the accessibility rules of the CLI.
5871 gboolean
5872 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
5874 method = mono_method_get_method_definition (method);
5875 called = mono_method_get_method_definition (called);
5876 return mono_method_can_access_method_full (method, called, NULL);
5880 * mono_method_can_access_method_full:
5881 * @method: The caller method
5882 * @called: The called method
5883 * @context_klass: The static type on stack of the owner @called object used
5885 * This function must be used with instance calls, as they have more strict family accessibility.
5886 * It can be used with static methods, but context_klass should be NULL.
5888 * Returns: TRUE if caller have proper visibility and acessibility to @called
5890 gboolean
5891 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
5893 /* Wrappers are except from access checks */
5894 if (method->wrapper_type != MONO_WRAPPER_NONE || called->wrapper_type != MONO_WRAPPER_NONE)
5895 return TRUE;
5897 MonoClass *access_class = method->klass;
5898 MonoClass *member_class = called->klass;
5899 int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
5900 if (!can) {
5901 MonoClass *nested = m_class_get_nested_in (access_class);
5902 while (nested) {
5903 can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
5904 if (can)
5905 break;
5906 nested = m_class_get_nested_in (nested);
5910 if (!can)
5911 return FALSE;
5913 can = can_access_type (access_class, member_class);
5914 if (!can) {
5915 MonoClass *nested = m_class_get_nested_in (access_class);
5916 while (nested) {
5917 can = can_access_type (nested, member_class);
5918 if (can)
5919 break;
5920 nested = m_class_get_nested_in (nested);
5924 if (!can)
5925 return FALSE;
5927 if (called->is_inflated) {
5928 MonoMethodInflated * infl = (MonoMethodInflated*)called;
5929 if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
5930 return FALSE;
5933 return TRUE;
5938 * mono_method_can_access_field_full:
5939 * @method: The caller method
5940 * @field: The accessed field
5941 * @context_klass: The static type on stack of the owner @field object used
5943 * This function must be used with instance fields, as they have more strict family accessibility.
5944 * It can be used with static fields, but context_klass should be NULL.
5946 * Returns: TRUE if caller have proper visibility and acessibility to @field
5948 gboolean
5949 mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
5951 MonoClass *access_class = method->klass;
5952 MonoClass *member_class = field->parent;
5953 /* FIXME: check all overlapping fields */
5954 int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5955 if (!can) {
5956 MonoClass *nested = m_class_get_nested_in (access_class);
5957 while (nested) {
5958 can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5959 if (can)
5960 break;
5961 nested = m_class_get_nested_in (nested);
5965 if (!can)
5966 return FALSE;
5968 can = can_access_type (access_class, member_class);
5969 if (!can) {
5970 MonoClass *nested = m_class_get_nested_in (access_class);
5971 while (nested) {
5972 can = can_access_type (nested, member_class);
5973 if (can)
5974 break;
5975 nested = m_class_get_nested_in (nested);
5979 if (!can)
5980 return FALSE;
5981 return TRUE;
5985 * mono_class_can_access_class:
5986 * @source_class: The source class
5987 * @target_class: The accessed class
5989 * This function returns is @target_class is visible to @source_class
5991 * Returns: TRUE if source have proper visibility and acessibility to target
5993 gboolean
5994 mono_class_can_access_class (MonoClass *source_class, MonoClass *target_class)
5996 return can_access_type (source_class, target_class);
6000 * mono_type_is_valid_enum_basetype:
6001 * \param type The MonoType to check
6002 * \returns TRUE if the type can be used as the basetype of an enum
6004 gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
6005 switch (type->type) {
6006 case MONO_TYPE_I1:
6007 case MONO_TYPE_U1:
6008 case MONO_TYPE_BOOLEAN:
6009 case MONO_TYPE_I2:
6010 case MONO_TYPE_U2:
6011 case MONO_TYPE_CHAR:
6012 case MONO_TYPE_I4:
6013 case MONO_TYPE_U4:
6014 case MONO_TYPE_I8:
6015 case MONO_TYPE_U8:
6016 case MONO_TYPE_I:
6017 case MONO_TYPE_U:
6018 #if ENABLE_NETCORE
6019 case MONO_TYPE_R8:
6020 case MONO_TYPE_R4:
6021 #endif
6022 return TRUE;
6023 default:
6024 return FALSE;
6029 * mono_class_is_valid_enum:
6030 * \param klass An enum class to be validated
6032 * This method verify the required properties an enum should have.
6034 * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
6035 * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
6036 * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
6038 * \returns TRUE if the informed enum class is valid
6040 gboolean
6041 mono_class_is_valid_enum (MonoClass *klass)
6043 MonoClassField * field;
6044 gpointer iter = NULL;
6045 gboolean found_base_field = FALSE;
6047 g_assert (m_class_is_enumtype (klass));
6048 MonoClass *klass_parent = m_class_get_parent (klass);
6049 /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
6050 if (!klass_parent || strcmp (m_class_get_name (klass_parent), "Enum") || strcmp (m_class_get_name_space (klass_parent), "System") ) {
6051 return FALSE;
6054 if (!mono_class_is_auto_layout (klass))
6055 return FALSE;
6057 while ((field = mono_class_get_fields_internal (klass, &iter))) {
6058 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
6059 if (found_base_field)
6060 return FALSE;
6061 found_base_field = TRUE;
6062 if (!mono_type_is_valid_enum_basetype (field->type))
6063 return FALSE;
6067 if (!found_base_field)
6068 return FALSE;
6070 if (mono_class_get_method_count (klass) > 0)
6071 return FALSE;
6073 return TRUE;
6076 gboolean
6077 mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
6079 return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst;
6082 void
6083 mono_field_resolve_type (MonoClassField *field, MonoError *error)
6085 MonoClass *klass = field->parent;
6086 MonoImage *image = m_class_get_image (klass);
6087 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
6088 MonoType *ftype;
6089 int field_idx = field - m_class_get_fields (klass);
6091 error_init (error);
6093 if (gtd) {
6094 MonoClassField *gfield = &m_class_get_fields (gtd) [field_idx];
6095 MonoType *gtype = mono_field_get_type_checked (gfield, error);
6096 if (!is_ok (error)) {
6097 char *full_name = mono_type_get_full_name (gtd);
6098 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));
6099 g_free (full_name);
6102 ftype = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
6103 if (!is_ok (error)) {
6104 char *full_name = mono_type_get_full_name (klass);
6105 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));
6106 g_free (full_name);
6108 } else {
6109 const char *sig;
6110 guint32 cols [MONO_FIELD_SIZE];
6111 MonoGenericContainer *container = NULL;
6112 int idx = mono_class_get_first_field_idx (klass) + field_idx;
6114 /*FIXME, in theory we do not lazy load SRE fields*/
6115 g_assert (!image_is_dynamic (image));
6117 if (mono_class_is_gtd (klass)) {
6118 container = mono_class_get_generic_container (klass);
6119 } else if (gtd) {
6120 container = mono_class_get_generic_container (gtd);
6121 g_assert (container);
6124 /* first_field_idx and idx points into the fieldptr table */
6125 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
6127 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], error)) {
6128 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
6129 return;
6132 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
6134 mono_metadata_decode_value (sig, &sig);
6135 /* FIELD signature == 0x06 */
6136 g_assert (*sig == 0x06);
6138 ftype = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
6139 if (!ftype) {
6140 char *full_name = mono_type_get_full_name (klass);
6141 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));
6142 g_free (full_name);
6145 mono_memory_barrier ();
6146 field->type = ftype;
6149 static guint32
6150 mono_field_resolve_flags (MonoClassField *field)
6152 MonoClass *klass = field->parent;
6153 MonoImage *image = m_class_get_image (klass);
6154 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
6155 int field_idx = field - m_class_get_fields (klass);
6157 if (gtd) {
6158 MonoClassField *gfield = &m_class_get_fields (gtd) [field_idx];
6159 return mono_field_get_flags (gfield);
6160 } else {
6161 int idx = mono_class_get_first_field_idx (klass) + field_idx;
6163 /*FIXME, in theory we do not lazy load SRE fields*/
6164 g_assert (!image_is_dynamic (image));
6166 return mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_FLAGS);
6171 * mono_class_get_fields_lazy:
6172 * \param klass the MonoClass to act on
6174 * This routine is an iterator routine for retrieving the fields in a class.
6175 * Only minimal information about fields are loaded. Accessors must be used
6176 * for all MonoClassField returned.
6178 * You must pass a gpointer that points to zero and is treated as an opaque handle to
6179 * iterate over all of the elements. When no more values are
6180 * available, the return value is NULL.
6182 * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
6184 MonoClassField*
6185 mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
6187 MonoClassField* field;
6188 if (!iter)
6189 return NULL;
6190 if (!*iter) {
6191 mono_class_setup_basic_field_info (klass);
6192 MonoClassField *klass_fields = m_class_get_fields (klass);
6193 if (!klass_fields)
6194 return NULL;
6195 /* start from the first */
6196 if (mono_class_get_field_count (klass)) {
6197 *iter = &klass_fields [0];
6198 return (MonoClassField *)*iter;
6199 } else {
6200 /* no fields */
6201 return NULL;
6204 field = (MonoClassField *)*iter;
6205 field++;
6206 if (field < &m_class_get_fields (klass) [mono_class_get_field_count (klass)]) {
6207 *iter = field;
6208 return (MonoClassField *)*iter;
6210 return NULL;
6213 char*
6214 mono_class_full_name (MonoClass *klass)
6216 return mono_type_full_name (m_class_get_byval_arg (klass));
6219 /* Declare all shared lazy type lookup functions */
6220 GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, "System.Runtime.InteropServices", "SafeHandle")
6223 * mono_method_get_base_method:
6224 * \param method a method
6225 * \param definition if true, get the definition
6226 * \param error set on failure
6228 * Given a virtual method associated with a subclass, return the corresponding
6229 * method from an ancestor. If \p definition is FALSE, returns the method in the
6230 * superclass of the given method. If \p definition is TRUE, return the method
6231 * in the ancestor class where it was first declared. The type arguments will
6232 * be inflated in the ancestor classes. If the method is not associated with a
6233 * class, or isn't virtual, returns the method itself. On failure returns NULL
6234 * and sets \p error.
6236 MonoMethod*
6237 mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error)
6239 MonoClass *klass, *parent;
6240 MonoGenericContext *generic_inst = NULL;
6241 MonoMethod *result = NULL;
6242 int slot;
6244 if (method->klass == NULL)
6245 return method;
6247 if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
6248 MONO_CLASS_IS_INTERFACE_INTERNAL (method->klass) ||
6249 method->flags & METHOD_ATTRIBUTE_NEW_SLOT)
6250 return method;
6252 slot = mono_method_get_vtable_slot (method);
6253 if (slot == -1)
6254 return method;
6256 klass = method->klass;
6257 if (mono_class_is_gtd (klass)) {
6258 /* If we get a GTD like Foo`2 replace look instead at its instantiation with its own generic params: Foo`2<!0, !1>. */
6259 /* In particular we want generic_inst to be initialized to <!0,
6260 * !1> so that we can inflate parent classes correctly as we go
6261 * up the class hierarchy. */
6262 MonoType *ty = mono_class_gtd_get_canonical_inst (klass);
6263 g_assert (ty->type == MONO_TYPE_GENERICINST);
6264 MonoGenericClass *gklass = ty->data.generic_class;
6265 generic_inst = mono_generic_class_get_context (gklass);
6266 klass = gklass->container_class;
6267 } else if (mono_class_is_ginst (klass)) {
6268 generic_inst = mono_class_get_context (klass);
6269 klass = mono_class_get_generic_class (klass)->container_class;
6272 retry:
6273 if (definition) {
6274 /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */
6275 for (parent = m_class_get_parent (klass); parent != NULL; parent = m_class_get_parent (parent)) {
6276 /* on entry, klass is either a plain old non-generic class and generic_inst == NULL
6277 or klass is the generic container class and generic_inst is the instantiation.
6279 when we go to the parent, if the parent is an open constructed type, we need to
6280 replace the type parameters by the definitions from the generic_inst, and then take it
6281 apart again into the klass and the generic_inst.
6283 For cases like this:
6284 class C<T> : B<T, int> {
6285 public override void Foo () { ... }
6287 class B<U,V> : A<HashMap<U,V>> {
6288 public override void Foo () { ... }
6290 class A<X> {
6291 public virtual void Foo () { ... }
6294 if at each iteration the parent isn't open, we can skip inflating it. if at some
6295 iteration the parent isn't generic (after possible inflation), we set generic_inst to
6296 NULL;
6298 MonoGenericContext *parent_inst = NULL;
6299 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (parent))) {
6300 parent = mono_class_inflate_generic_class_checked (parent, generic_inst, error);
6301 return_val_if_nok (error, NULL);
6303 if (mono_class_is_ginst (parent)) {
6304 parent_inst = mono_class_get_context (parent);
6305 parent = mono_class_get_generic_class (parent)->container_class;
6308 mono_class_setup_vtable (parent);
6309 if (m_class_get_vtable_size (parent) <= slot)
6310 break;
6311 klass = parent;
6312 generic_inst = parent_inst;
6314 } else {
6315 /* When we get here, possibly after a retry, if generic_inst is
6316 * set, then the class is must be a gtd */
6317 g_assert (generic_inst == NULL || mono_class_is_gtd (klass));
6319 klass = m_class_get_parent (klass);
6320 if (!klass)
6321 return method;
6322 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (klass))) {
6323 klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
6324 return_val_if_nok (error, NULL);
6326 generic_inst = NULL;
6328 if (mono_class_is_ginst (klass)) {
6329 generic_inst = mono_class_get_context (klass);
6330 klass = mono_class_get_generic_class (klass)->container_class;
6335 if (generic_inst) {
6336 klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
6337 return_val_if_nok (error, NULL);
6338 generic_inst = NULL;
6341 if (klass == method->klass)
6342 return method;
6344 /*This is possible if definition == FALSE.
6345 * Do it here to be really sure we don't read invalid memory.
6347 if (slot >= m_class_get_vtable_size (klass))
6348 return method;
6350 mono_class_setup_vtable (klass);
6352 result = m_class_get_vtable (klass) [slot];
6353 if (result == NULL) {
6354 /* It is an abstract method */
6355 gboolean found = FALSE;
6356 gpointer iter = NULL;
6357 while ((result = mono_class_get_methods (klass, &iter))) {
6358 if (result->slot == slot) {
6359 found = TRUE;
6360 break;
6363 /* found might be FALSE if we looked in an abstract class
6364 * that doesn't override an abstract method of its
6365 * parent:
6366 * abstract class Base {
6367 * public abstract void Foo ();
6369 * abstract class Derived : Base { }
6370 * class Child : Derived {
6371 * public override void Foo () { }
6374 * if m was Child.Foo and we ask for the base method,
6375 * then we get here with klass == Derived and found == FALSE
6377 /* but it shouldn't be the case that if we're looking
6378 * for the definition and didn't find a result; the
6379 * loop above should've taken us as far as we could
6380 * go! */
6381 g_assert (!(definition && !found));
6382 if (!found)
6383 goto retry;
6386 g_assert (result != NULL);
6387 return result;
6390 gboolean
6391 mono_method_is_constructor (MonoMethod *method)
6393 return ((method->flags & CTOR_REQUIRED_FLAGS) == CTOR_REQUIRED_FLAGS &&
6394 !(method->flags & CTOR_INVALID_FLAGS) &&
6395 !strcmp (".ctor", method->name));
6398 gboolean
6399 mono_class_has_default_constructor (MonoClass *klass, gboolean public_only)
6401 MonoMethod *method;
6402 int i;
6404 mono_class_setup_methods (klass);
6405 if (mono_class_has_failure (klass))
6406 return FALSE;
6408 int mcount = mono_class_get_method_count (klass);
6409 MonoMethod **klass_methods = m_class_get_methods (klass);
6410 for (i = 0; i < mcount; ++i) {
6411 method = klass_methods [i];
6412 if (mono_method_is_constructor (method) &&
6413 mono_method_signature_internal (method) &&
6414 mono_method_signature_internal (method)->param_count == 0 &&
6415 (!public_only || (method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC))
6416 return TRUE;
6418 return FALSE;