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