[Coop] Convert Get/SetGenericValueImpl. (#17034)
[mono-project.git] / mono / metadata / class.c
blobf76724d2f9547489c3876a1bd3be5d225fa37ed5
1 /**
2 * \file
3 * Class management for the Mono runtime
5 * Author:
6 * Miguel de Icaza (miguel@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 #include <config.h>
14 #ifdef HAVE_ALLOCA_H
15 #include <alloca.h>
16 #endif
17 #include <glib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <mono/metadata/image.h>
22 #include <mono/metadata/image-internals.h>
23 #include <mono/metadata/assembly.h>
24 #include <mono/metadata/assembly-internals.h>
25 #include <mono/metadata/exception-internals.h>
26 #include <mono/metadata/metadata.h>
27 #include <mono/metadata/metadata-internals.h>
28 #include <mono/metadata/profiler-private.h>
29 #include <mono/metadata/tabledefs.h>
30 #include <mono/metadata/tokentype.h>
31 #include <mono/metadata/class-init.h>
32 #include <mono/metadata/class-internals.h>
33 #include <mono/metadata/object.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/mono-endian.h>
36 #include <mono/metadata/debug-helpers.h>
37 #include <mono/metadata/reflection.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/security-manager.h>
40 #include <mono/metadata/security-core-clr.h>
41 #include <mono/metadata/attrdefs.h>
42 #include <mono/metadata/gc-internals.h>
43 #include <mono/metadata/verify-internals.h>
44 #include <mono/metadata/mono-debug.h>
45 #include <mono/utils/mono-counters.h>
46 #include <mono/utils/mono-string.h>
47 #include <mono/utils/mono-error-internals.h>
48 #include <mono/utils/mono-logger-internals.h>
49 #include <mono/utils/mono-memory-model.h>
50 #include <mono/utils/atomic.h>
51 #include <mono/utils/unlocked.h>
52 #include <mono/utils/bsearch.h>
53 #include <mono/utils/checked-build.h>
55 MonoStats mono_stats;
57 /* Statistics */
58 extern gint32 mono_inflated_methods_size;
60 /* Function supplied by the runtime to find classes by name using information from the AOT file */
61 static MonoGetClassFromName get_class_from_name = NULL;
63 static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
65 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
66 static guint32 mono_field_resolve_flags (MonoClassField *field);
68 static MonoClass *
69 mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, gboolean case_sensitive, MonoError *error);
71 GENERATE_GET_CLASS_WITH_CACHE (valuetype, "System", "ValueType")
72 GENERATE_TRY_GET_CLASS_WITH_CACHE (handleref, "System.Runtime.InteropServices", "HandleRef")
74 // define to print types whenever custom modifiers are appended during inflation
75 #undef DEBUG_INFLATE_CMODS
77 static
78 MonoImage *
79 mono_method_get_image (MonoMethod *method)
81 return m_class_get_image (method->klass);
84 /**
85 * mono_class_from_typeref:
86 * \param image a MonoImage
87 * \param type_token a TypeRef token
89 * Creates the \c MonoClass* structure representing the type defined by
90 * the typeref token valid inside \p image.
91 * \returns The \c MonoClass* representing the typeref token, or NULL if it could
92 * not be loaded.
94 MonoClass *
95 mono_class_from_typeref (MonoImage *image, guint32 type_token)
97 ERROR_DECL (error);
98 MonoClass *klass = mono_class_from_typeref_checked (image, type_token, error);
99 g_assert (is_ok (error)); /*FIXME proper error handling*/
100 return klass;
104 * mono_class_from_typeref_checked:
105 * \param image a MonoImage
106 * \param type_token a TypeRef token
107 * \param error error return code, if any.
109 * Creates the \c MonoClass* structure representing the type defined by
110 * the typeref token valid inside \p image.
112 * \returns The \c MonoClass* representing the typeref token, NULL if it could
113 * not be loaded with the \p error value filled with the information about the
114 * error.
116 MonoClass *
117 mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
119 guint32 cols [MONO_TYPEREF_SIZE];
120 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
121 guint32 idx;
122 const char *name, *nspace;
123 MonoClass *res = NULL;
124 MonoImage *module;
126 error_init (error);
128 if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
129 return NULL;
131 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
133 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
134 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
136 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
137 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
138 case MONO_RESOLUTION_SCOPE_MODULE:
140 LAMESPEC The spec says that a null module resolution scope should go through the exported type table.
141 This is not the observed behavior of existing implementations.
142 The defacto behavior is that it's just a typedef in disguise.
144 /* a typedef in disguise */
145 res = mono_class_from_name_checked (image, nspace, name, error);
146 goto done;
148 case MONO_RESOLUTION_SCOPE_MODULEREF:
149 module = mono_image_load_module_checked (image, idx, error);
150 if (module)
151 res = mono_class_from_name_checked (module, nspace, name, error);
152 goto done;
154 case MONO_RESOLUTION_SCOPE_TYPEREF: {
155 MonoClass *enclosing;
156 GList *tmp;
158 if (idx == mono_metadata_token_index (type_token)) {
159 mono_error_set_bad_image (error, image, "Image with self-referencing typeref token %08x.", type_token);
160 return NULL;
163 enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
164 return_val_if_nok (error, NULL);
166 GList *nested_classes = mono_class_get_nested_classes_property (enclosing);
167 if (m_class_is_nested_classes_inited (enclosing) && nested_classes) {
168 /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
169 for (tmp = nested_classes; tmp; tmp = tmp->next) {
170 res = (MonoClass *)tmp->data;
171 if (strcmp (m_class_get_name (res), name) == 0)
172 return res;
174 } else {
175 MonoImage *enclosing_image = m_class_get_image (enclosing);
176 guint32 enclosing_type_token = m_class_get_type_token (enclosing);
177 /* Don't call mono_class_init_internal as we might've been called by it recursively */
178 int i = mono_metadata_nesting_typedef (enclosing_image, enclosing_type_token, 1);
179 while (i) {
180 guint32 class_nested = mono_metadata_decode_row_col (&enclosing_image->tables [MONO_TABLE_NESTEDCLASS], i - 1, MONO_NESTED_CLASS_NESTED);
181 guint32 string_offset = mono_metadata_decode_row_col (&enclosing_image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
182 const char *nname = mono_metadata_string_heap (enclosing_image, string_offset);
184 if (strcmp (nname, name) == 0)
185 return mono_class_create_from_typedef (enclosing_image, MONO_TOKEN_TYPE_DEF | class_nested, error);
187 i = mono_metadata_nesting_typedef (enclosing_image, enclosing_type_token, i + 1);
190 g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
191 goto done;
193 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
194 break;
197 if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
198 mono_error_set_bad_image (error, image, "Image with invalid assemblyref token %08x.", idx);
199 return NULL;
202 if (!image->references || !image->references [idx - 1])
203 mono_assembly_load_reference (image, idx - 1);
204 g_assert (image->references [idx - 1]);
206 /* If the assembly did not load, register this as a type load exception */
207 if (image->references [idx - 1] == REFERENCE_MISSING){
208 MonoAssemblyName aname;
209 char *human_name;
211 mono_assembly_get_assemblyref (image, idx - 1, &aname);
212 human_name = mono_stringify_assembly_name (&aname);
213 gboolean refonly = FALSE;
214 if (image->assembly)
215 refonly = mono_asmctx_get_kind (&image->assembly->context) == MONO_ASMCTX_REFONLY;
216 mono_error_set_simple_file_not_found (error, human_name, refonly);
217 g_free (human_name);
218 return NULL;
221 res = mono_class_from_name_checked (image->references [idx - 1]->image, nspace, name, error);
223 done:
224 /* Generic case, should be avoided for when a better error is possible. */
225 if (!res && is_ok (error)) {
226 char *name = mono_class_name_from_token (image, type_token);
227 char *assembly = mono_assembly_name_from_token (image, type_token);
228 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);
230 return res;
234 static void *
235 mono_image_memdup (MonoImage *image, void *data, guint size)
237 void *res = mono_image_alloc (image, size);
238 memcpy (res, data, size);
239 return res;
242 /* Copy everything mono_metadata_free_array free. */
243 MonoArrayType *
244 mono_dup_array_type (MonoImage *image, MonoArrayType *a)
246 if (image) {
247 a = (MonoArrayType *)mono_image_memdup (image, a, sizeof (MonoArrayType));
248 if (a->sizes)
249 a->sizes = (int *)mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
250 if (a->lobounds)
251 a->lobounds = (int *)mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
252 } else {
253 a = (MonoArrayType *)g_memdup (a, sizeof (MonoArrayType));
254 if (a->sizes)
255 a->sizes = (int *)g_memdup (a->sizes, a->numsizes * sizeof (int));
256 if (a->lobounds)
257 a->lobounds = (int *)g_memdup (a->lobounds, a->numlobounds * sizeof (int));
259 return a;
262 /* Copy everything mono_metadata_free_method_signature free. */
263 MonoMethodSignature*
264 mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
266 int i;
268 sig = mono_metadata_signature_dup_full (image, sig);
270 sig->ret = mono_metadata_type_dup (image, sig->ret);
271 for (i = 0; i < sig->param_count; ++i)
272 sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
274 return sig;
277 static void
278 _mono_type_get_assembly_name (MonoClass *klass, GString *str)
280 MonoAssembly *ta = m_class_get_image (klass)->assembly;
281 char *name;
283 name = mono_stringify_assembly_name (&ta->aname);
284 g_string_append_printf (str, ", %s", name);
285 g_free (name);
288 static void
289 mono_type_name_check_byref (MonoType *type, GString *str)
291 if (type->byref)
292 g_string_append_c (str, '&');
296 * mono_identifier_escape_type_name_chars:
297 * \param str a destination string
298 * \param identifier an IDENTIFIER in internal form
300 * \returns \p str
302 * The displayed form of the identifier is appended to str.
304 * The displayed form of an identifier has the characters ,+&*[]\
305 * that have special meaning in type names escaped with a preceeding
306 * backslash (\) character.
308 static GString*
309 mono_identifier_escape_type_name_chars (GString* str, const char* identifier)
311 if (!identifier)
312 return str;
314 size_t n = str->len;
315 // reserve space for common case: there will be no escaped characters.
316 g_string_set_size(str, n + strlen(identifier));
317 g_string_set_size(str, n);
319 for (const char* s = identifier; *s != 0 ; s++) {
320 switch (*s) {
321 case ',':
322 case '+':
323 case '&':
324 case '*':
325 case '[':
326 case ']':
327 case '\\':
328 g_string_append_c (str, '\\');
329 g_string_append_c (str, *s);
330 break;
331 default:
332 g_string_append_c (str, *s);
333 break;
336 return str;
339 static void
340 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
341 MonoTypeNameFormat format)
343 MonoClass *klass;
345 switch (type->type) {
346 case MONO_TYPE_ARRAY: {
347 int i, rank = type->data.array->rank;
348 MonoTypeNameFormat nested_format;
350 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
351 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
353 mono_type_get_name_recurse (
354 m_class_get_byval_arg (type->data.array->eklass), str, FALSE, nested_format);
355 g_string_append_c (str, '[');
356 if (rank == 1)
357 g_string_append_c (str, '*');
358 for (i = 1; i < rank; i++)
359 g_string_append_c (str, ',');
360 g_string_append_c (str, ']');
362 mono_type_name_check_byref (type, str);
364 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
365 _mono_type_get_assembly_name (type->data.array->eklass, str);
366 break;
368 case MONO_TYPE_SZARRAY: {
369 MonoTypeNameFormat nested_format;
371 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
372 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
374 mono_type_get_name_recurse (
375 m_class_get_byval_arg (type->data.klass), str, FALSE, nested_format);
376 g_string_append (str, "[]");
378 mono_type_name_check_byref (type, str);
380 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
381 _mono_type_get_assembly_name (type->data.klass, str);
382 break;
384 case MONO_TYPE_PTR: {
385 MonoTypeNameFormat nested_format;
387 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
388 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
390 mono_type_get_name_recurse (
391 type->data.type, str, FALSE, nested_format);
392 g_string_append_c (str, '*');
394 mono_type_name_check_byref (type, str);
396 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
397 _mono_type_get_assembly_name (mono_class_from_mono_type_internal (type->data.type), str);
398 break;
400 case MONO_TYPE_VAR:
401 case MONO_TYPE_MVAR:
402 if (!mono_generic_param_name (type->data.generic_param))
403 g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
404 else
405 g_string_append (str, mono_generic_param_name (type->data.generic_param));
407 mono_type_name_check_byref (type, str);
409 break;
410 default:
411 klass = mono_class_from_mono_type_internal (type);
412 if (m_class_get_nested_in (klass)) {
413 mono_type_get_name_recurse (
414 m_class_get_byval_arg (m_class_get_nested_in (klass)), str, TRUE, format);
415 if (format == MONO_TYPE_NAME_FORMAT_IL)
416 g_string_append_c (str, '.');
417 else
418 g_string_append_c (str, '+');
419 } else if (*m_class_get_name_space (klass)) {
420 const char *klass_name_space = m_class_get_name_space (klass);
421 if (format == MONO_TYPE_NAME_FORMAT_IL)
422 g_string_append (str, klass_name_space);
423 else
424 mono_identifier_escape_type_name_chars (str, klass_name_space);
425 g_string_append_c (str, '.');
427 const char *klass_name = m_class_get_name (klass);
428 if (format == MONO_TYPE_NAME_FORMAT_IL) {
429 const char *s = strchr (klass_name, '`');
430 gssize len = s ? (s - klass_name) : (gssize)strlen (klass_name);
431 g_string_append_len (str, klass_name, len);
432 } else {
433 mono_identifier_escape_type_name_chars (str, klass_name);
435 if (is_recursed)
436 break;
437 if (mono_class_is_ginst (klass)) {
438 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
439 MonoGenericInst *inst = gclass->context.class_inst;
440 MonoTypeNameFormat nested_format;
441 int i;
443 nested_format = format == MONO_TYPE_NAME_FORMAT_FULL_NAME ?
444 MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format;
446 if (format == MONO_TYPE_NAME_FORMAT_IL)
447 g_string_append_c (str, '<');
448 else
449 g_string_append_c (str, '[');
450 for (i = 0; i < inst->type_argc; i++) {
451 MonoType *t = inst->type_argv [i];
453 if (i)
454 g_string_append_c (str, ',');
455 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
456 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
457 g_string_append_c (str, '[');
458 mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
459 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
460 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
461 g_string_append_c (str, ']');
463 if (format == MONO_TYPE_NAME_FORMAT_IL)
464 g_string_append_c (str, '>');
465 else
466 g_string_append_c (str, ']');
467 } else if (mono_class_is_gtd (klass) &&
468 (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
469 (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
470 int i;
472 if (format == MONO_TYPE_NAME_FORMAT_IL)
473 g_string_append_c (str, '<');
474 else
475 g_string_append_c (str, '[');
476 for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) {
477 if (i)
478 g_string_append_c (str, ',');
479 g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name);
481 if (format == MONO_TYPE_NAME_FORMAT_IL)
482 g_string_append_c (str, '>');
483 else
484 g_string_append_c (str, ']');
487 mono_type_name_check_byref (type, str);
489 if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
490 (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
491 _mono_type_get_assembly_name (klass, str);
492 break;
497 * mono_type_get_name_full:
498 * \param type a type
499 * \param format the format for the return string.
502 * \returns The string representation in a number of formats:
504 * if \p format is \c MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
505 * returned in the format required by \c System.Reflection, this is the
506 * inverse of mono_reflection_parse_type().
508 * if \p format is \c MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
509 * be used by the IL assembler.
511 * if \p format is \c MONO_TYPE_NAME_FORMAT_FULL_NAME
513 * if \p format is \c MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
515 char*
516 mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
518 GString* result;
520 result = g_string_new ("");
522 mono_type_get_name_recurse (type, result, FALSE, format);
524 return g_string_free (result, FALSE);
528 * mono_type_get_full_name:
529 * \param class a class
531 * \returns The string representation for type as required by System.Reflection.
532 * The inverse of mono_reflection_parse_type().
534 char *
535 mono_type_get_full_name (MonoClass *klass)
537 return mono_type_get_name_full (m_class_get_byval_arg (klass), MONO_TYPE_NAME_FORMAT_REFLECTION);
541 * mono_type_get_name:
542 * \param type a type
543 * \returns The string representation for type as it would be represented in IL code.
545 char*
546 mono_type_get_name (MonoType *type)
548 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
552 * mono_type_get_underlying_type:
553 * \param type a type
554 * \returns The \c MonoType for the underlying integer type if \p type
555 * is an enum and byref is false, otherwise the type itself.
557 MonoType*
558 mono_type_get_underlying_type (MonoType *type)
560 if (type->type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (type->data.klass) && !type->byref)
561 return mono_class_enum_basetype_internal (type->data.klass);
562 if (type->type == MONO_TYPE_GENERICINST && m_class_is_enumtype (type->data.generic_class->container_class) && !type->byref)
563 return mono_class_enum_basetype_internal (type->data.generic_class->container_class);
564 return type;
568 * mono_class_is_open_constructed_type:
569 * \param type a type
571 * \returns TRUE if type represents a generics open constructed type.
572 * IOW, not all type parameters required for the instantiation have
573 * been provided or it's a generic type definition.
575 * An open constructed type means it's a non realizable type. Not to
576 * be mixed up with an abstract type - we can't cast or dispatch to
577 * an open type, for example.
579 gboolean
580 mono_class_is_open_constructed_type (MonoType *t)
582 switch (t->type) {
583 case MONO_TYPE_VAR:
584 case MONO_TYPE_MVAR:
585 return TRUE;
586 case MONO_TYPE_SZARRAY:
587 return mono_class_is_open_constructed_type (m_class_get_byval_arg (t->data.klass));
588 case MONO_TYPE_ARRAY:
589 return mono_class_is_open_constructed_type (m_class_get_byval_arg (t->data.array->eklass));
590 case MONO_TYPE_PTR:
591 return mono_class_is_open_constructed_type (t->data.type);
592 case MONO_TYPE_GENERICINST:
593 return t->data.generic_class->context.class_inst->is_open;
594 case MONO_TYPE_CLASS:
595 case MONO_TYPE_VALUETYPE:
596 return mono_class_is_gtd (t->data.klass);
597 default:
598 return FALSE;
603 This is a simple function to catch the most common bad instances of generic types.
604 Specially those that might lead to further failures in the runtime.
606 gboolean
607 mono_type_is_valid_generic_argument (MonoType *type)
609 switch (type->type) {
610 case MONO_TYPE_VOID:
611 case MONO_TYPE_TYPEDBYREF:
612 return FALSE;
613 case MONO_TYPE_VALUETYPE:
614 return !m_class_is_byreflike (type->data.klass);
615 default:
616 return TRUE;
620 static gboolean
621 can_inflate_gparam_with (MonoGenericParam *gparam, MonoType *type)
623 if (!mono_type_is_valid_generic_argument (type))
624 return FALSE;
625 #if FALSE
626 /* Avoid inflating gparams with valuetype constraints with ref types during gsharing */
627 MonoGenericParamInfo *info = mono_generic_param_info (gparam);
628 if (info && (info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)) {
629 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
630 MonoGenericParam *inst_gparam = type->data.generic_param;
631 if (inst_gparam->gshared_constraint && inst_gparam->gshared_constraint->type == MONO_TYPE_OBJECT)
632 return FALSE;
635 #endif
636 return TRUE;
639 static MonoType*
640 inflate_generic_custom_modifiers (MonoImage *image, const MonoType *type, MonoGenericContext *context, MonoError *error);
642 static MonoType*
643 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
645 gboolean changed = FALSE;
646 error_init (error);
648 /* C++/CLI (and some Roslyn tests) constructs method signatures like:
649 * void .CL1`1.Test(!0 modopt(System.Nullable`1<!0>))
650 * where !0 has a custom modifier which itself mentions the type variable.
651 * So we need to potentially inflate the modifiers.
653 if (type->has_cmods) {
654 MonoType *new_type = inflate_generic_custom_modifiers (image, type, context, error);
655 return_val_if_nok (error, NULL);
656 if (new_type != NULL) {
657 type = new_type;
658 changed = TRUE;
662 switch (type->type) {
663 case MONO_TYPE_MVAR: {
664 MonoType *nt;
665 int num = mono_type_get_generic_param_num (type);
666 MonoGenericInst *inst = context->method_inst;
667 if (!inst) {
668 if (!changed)
669 return NULL;
670 else
671 return type;
673 MonoGenericParam *gparam = type->data.generic_param;
674 if (num >= inst->type_argc) {
675 const char *pname = mono_generic_param_name (gparam);
676 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
677 num, pname ? pname : "", inst->type_argc);
678 return NULL;
681 if (!can_inflate_gparam_with (gparam, inst->type_argv [num])) {
682 const char *pname = mono_generic_param_name (gparam);
683 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
684 num, pname ? pname : "", inst->type_argv [num]->type);
685 return NULL;
688 * Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
689 * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
690 * ->byref and ->attrs from @type are propagated to the returned type.
692 nt = mono_metadata_type_dup_with_cmods (image, inst->type_argv [num], type);
693 nt->byref = type->byref;
694 nt->attrs = type->attrs;
695 return nt;
697 case MONO_TYPE_VAR: {
698 MonoType *nt;
699 int num = mono_type_get_generic_param_num (type);
700 MonoGenericInst *inst = context->class_inst;
701 if (!inst) {
702 if (!changed)
703 return NULL;
704 else
705 return type;
707 MonoGenericParam *gparam = type->data.generic_param;
708 if (num >= inst->type_argc) {
709 const char *pname = mono_generic_param_name (gparam);
710 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
711 num, pname ? pname : "", inst->type_argc);
712 return NULL;
714 if (!can_inflate_gparam_with (gparam, inst->type_argv [num])) {
715 const char *pname = mono_generic_param_name (gparam);
716 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
717 num, pname ? pname : "", inst->type_argv [num]->type);
718 return NULL;
721 #ifdef DEBUG_INFLATE_CMODS
722 gboolean append_cmods;
723 append_cmods = FALSE;
724 if (type->has_cmods && inst->type_argv[num]->has_cmods) {
725 char *tname = mono_type_full_name (type);
726 char *vname = mono_type_full_name (inst->type_argv[num]);
727 printf ("\n\n\tsubstitution for '%s' with '%s' yields...\n", tname, vname);
728 g_free (tname);
729 g_free (vname);
730 append_cmods = TRUE;
732 #endif
734 nt = mono_metadata_type_dup_with_cmods (image, inst->type_argv [num], type);
735 nt->byref = type->byref || inst->type_argv[num]->byref;
736 nt->attrs = type->attrs;
737 #ifdef DEBUG_INFLATE_CMODS
738 if (append_cmods) {
739 char *ntname = mono_type_full_name (nt);
740 printf ("\tyields '%s'\n\n\n", ntname);
741 g_free (ntname);
743 #endif
744 return nt;
746 case MONO_TYPE_SZARRAY: {
747 MonoClass *eclass = type->data.klass;
748 MonoType *nt, *inflated = inflate_generic_type (NULL, m_class_get_byval_arg (eclass), context, error);
749 if ((!inflated && !changed) || !is_ok (error))
750 return NULL;
751 if (!inflated)
752 return type;
753 nt = mono_metadata_type_dup (image, type);
754 nt->data.klass = mono_class_from_mono_type_internal (inflated);
755 mono_metadata_free_type (inflated);
756 return nt;
758 case MONO_TYPE_ARRAY: {
759 MonoClass *eclass = type->data.array->eklass;
760 MonoType *nt, *inflated = inflate_generic_type (NULL, m_class_get_byval_arg (eclass), context, error);
761 if ((!inflated && !changed) || !is_ok (error))
762 return NULL;
763 if (!inflated)
764 return type;
765 nt = mono_metadata_type_dup (image, type);
766 nt->data.array->eklass = mono_class_from_mono_type_internal (inflated);
767 mono_metadata_free_type (inflated);
768 return nt;
770 case MONO_TYPE_GENERICINST: {
771 MonoGenericClass *gclass = type->data.generic_class;
772 MonoGenericInst *inst;
773 MonoType *nt;
774 if (!gclass->context.class_inst->is_open) {
775 if (!changed)
776 return NULL;
777 else
778 return type;
781 inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
782 return_val_if_nok (error, NULL);
784 if (inst != gclass->context.class_inst)
785 gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
787 if (gclass == type->data.generic_class) {
788 if (!changed)
789 return NULL;
790 else
791 return type;
794 nt = mono_metadata_type_dup (image, type);
795 nt->data.generic_class = gclass;
796 return nt;
798 case MONO_TYPE_CLASS:
799 case MONO_TYPE_VALUETYPE: {
800 MonoClass *klass = type->data.klass;
801 MonoGenericContainer *container = mono_class_try_get_generic_container (klass);
802 MonoGenericInst *inst;
803 MonoGenericClass *gclass = NULL;
804 MonoType *nt;
806 if (!container) {
807 if (!changed)
808 return NULL;
809 else
810 return type;
813 /* We can't use context->class_inst directly, since it can have more elements */
814 inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
815 return_val_if_nok (error, NULL);
817 if (inst == container->context.class_inst) {
818 if (!changed)
819 return NULL;
820 else
821 return type;
824 gclass = mono_metadata_lookup_generic_class (klass, inst, image_is_dynamic (m_class_get_image (klass)));
826 nt = mono_metadata_type_dup (image, type);
827 nt->type = MONO_TYPE_GENERICINST;
828 nt->data.generic_class = gclass;
829 return nt;
831 case MONO_TYPE_PTR: {
832 MonoType *nt, *inflated = inflate_generic_type (image, type->data.type, context, error);
833 if ((!inflated && !changed) || !is_ok (error))
834 return NULL;
835 if (!inflated && changed)
836 return type;
837 nt = mono_metadata_type_dup (image, type);
838 nt->data.type = inflated;
839 return nt;
841 default:
842 if (!changed)
843 return NULL;
844 else
845 return type;
847 return NULL;
850 static MonoType*
851 inflate_generic_custom_modifiers (MonoImage *image, const MonoType *type, MonoGenericContext *context, MonoError *error)
853 MonoType *result = NULL;
854 g_assert (type->has_cmods);
855 int count = mono_type_custom_modifier_count (type);
856 gboolean changed = FALSE;
858 /* Try not to blow up the stack. See comment on MONO_MAX_EXPECTED_CMODS. */
859 g_assert (count < MONO_MAX_EXPECTED_CMODS);
860 size_t aggregate_size = mono_sizeof_aggregate_modifiers (count);
861 MonoAggregateModContainer *candidate_mods = g_alloca (aggregate_size);
862 memset (candidate_mods, 0, aggregate_size);
863 candidate_mods->count = count;
865 for (int i = 0; i < count; ++i) {
866 gboolean required;
867 MonoType *cmod_old = mono_type_get_custom_modifier (type, i, &required, error);
868 goto_if_nok (error, leave);
869 MonoType *cmod_new = inflate_generic_type (NULL, cmod_old, context, error);
870 goto_if_nok (error, leave);
871 if (cmod_new)
872 changed = TRUE;
873 candidate_mods->modifiers [i].required = required;
874 candidate_mods->modifiers [i].type = cmod_new;
877 if (changed) {
878 /* 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. */
879 for (int i = 0; i < count; ++i) {
880 if (candidate_mods->modifiers [i].type == NULL) {
881 candidate_mods->modifiers [i].type = mono_metadata_type_dup (NULL, mono_type_get_custom_modifier (type, i, NULL, error));
883 /* it didn't error in the first loop, so should be ok now, too */
884 mono_error_assert_ok (error);
888 #ifdef DEBUG_INFLATE_CMODS
889 if (changed) {
890 char *full_name = mono_type_full_name ((MonoType*)type);
891 printf ("\n\n\tcustom modifier on '%s' affected by subsititution\n\n\n", full_name);
892 g_free (full_name);
894 #endif
895 if (changed) {
896 MonoType *new_type = g_alloca (mono_sizeof_type_with_mods (count, TRUE));
897 /* first init just the non-modifier portion of new_type before populating the
898 * new modifiers */
899 memcpy (new_type, type, MONO_SIZEOF_TYPE);
900 mono_type_with_mods_init (new_type, count, TRUE);
901 mono_type_set_amods (new_type, mono_metadata_get_canonical_aggregate_modifiers (candidate_mods));
902 result = mono_metadata_type_dup (image, new_type);
905 leave:
906 for (int i = 0; i < count; ++i) {
907 if (candidate_mods->modifiers [i].type)
908 mono_metadata_free_type (candidate_mods->modifiers [i].type);
911 return result;
914 MonoGenericContext *
915 mono_generic_class_get_context (MonoGenericClass *gclass)
917 return &gclass->context;
920 MonoGenericContext *
921 mono_class_get_context (MonoClass *klass)
923 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
924 return gklass ? mono_generic_class_get_context (gklass) : NULL;
928 * mono_class_inflate_generic_type_with_mempool:
929 * @mempool: a mempool
930 * @type: a type
931 * @context: a generics context
932 * @error: error context
934 * The same as mono_class_inflate_generic_type, but allocates the MonoType
935 * from mempool if it is non-NULL. If it is NULL, the MonoType is
936 * allocated on the heap and is owned by the caller.
937 * The returned type can potentially be the same as TYPE, so it should not be
938 * modified by the caller, and it should be freed using mono_metadata_free_type ().
940 MonoType*
941 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
943 MonoType *inflated = NULL;
944 error_init (error);
946 if (context)
947 inflated = inflate_generic_type (image, type, context, error);
948 return_val_if_nok (error, NULL);
950 if (!inflated) {
951 MonoType *shared = mono_metadata_get_shared_type (type);
953 if (shared && !type->has_cmods) {
954 return shared;
955 } else {
956 return mono_metadata_type_dup (image, type);
960 UnlockedIncrement (&mono_stats.inflated_type_count);
961 return inflated;
965 * mono_class_inflate_generic_type:
966 * \param type a type
967 * \param context a generics context
968 * \deprecated Please use \c mono_class_inflate_generic_type_checked instead
970 * If \p type is a generic type and \p context is not NULL, instantiate it using the
971 * generics context \p context.
973 * \returns The instantiated type or a copy of \p type. The returned \c MonoType is allocated
974 * on the heap and is owned by the caller. Returns NULL on error.
976 MonoType*
977 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
979 ERROR_DECL (error);
980 MonoType *result;
981 result = mono_class_inflate_generic_type_checked (type, context, error);
982 mono_error_cleanup (error);
983 return result;
987 * mono_class_inflate_generic_type:
988 * @type: a type
989 * @context: a generics context
990 * @error: error context to use
992 * If @type is a generic type and @context is not NULL, instantiate it using the
993 * generics context @context.
995 * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
996 * on the heap and is owned by the caller.
998 MonoType*
999 mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
1001 return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
1005 * mono_class_inflate_generic_type_no_copy:
1007 * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
1008 * was done.
1010 static MonoType*
1011 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
1013 MonoType *inflated = NULL;
1015 error_init (error);
1016 if (context) {
1017 inflated = inflate_generic_type (image, type, context, error);
1018 return_val_if_nok (error, NULL);
1021 if (!inflated)
1022 return type;
1024 UnlockedIncrement (&mono_stats.inflated_type_count);
1025 return inflated;
1029 * mono_class_inflate_generic_class:
1031 * Inflate the class @gklass with @context. Set @error on failure.
1033 MonoClass*
1034 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
1036 MonoClass *res;
1037 MonoType *inflated;
1039 inflated = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (gklass), context, error);
1040 return_val_if_nok (error, NULL);
1042 res = mono_class_from_mono_type_internal (inflated);
1043 mono_metadata_free_type (inflated);
1045 return res;
1048 static MonoGenericContext
1049 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
1051 MonoGenericInst *class_inst = NULL;
1052 MonoGenericInst *method_inst = NULL;
1053 MonoGenericContext res = { NULL, NULL };
1055 error_init (error);
1057 if (context->class_inst) {
1058 class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
1059 if (!is_ok (error))
1060 goto fail;
1063 if (context->method_inst) {
1064 method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with, error);
1065 if (!is_ok (error))
1066 goto fail;
1069 res.class_inst = class_inst;
1070 res.method_inst = method_inst;
1071 fail:
1072 return res;
1076 * mono_class_inflate_generic_method:
1077 * \param method a generic method
1078 * \param context a generics context
1080 * Instantiate the generic method \p method using the generics context \p context.
1082 * \returns The new instantiated method
1084 MonoMethod *
1085 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
1087 ERROR_DECL (error);
1088 error_init (error);
1089 MonoMethod *res = mono_class_inflate_generic_method_full_checked (method, NULL, context, error);
1090 mono_error_assert_msg_ok (error, "Could not inflate generic method");
1091 return res;
1094 MonoMethod *
1095 mono_class_inflate_generic_method_checked (MonoMethod *method, MonoGenericContext *context, MonoError *error)
1097 return mono_class_inflate_generic_method_full_checked (method, NULL, context, error);
1101 * mono_class_inflate_generic_method_full_checked:
1102 * Instantiate method \p method with the generic context \p context.
1103 * On failure returns NULL and sets \p error.
1105 * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
1106 * Use mono_method_signature_internal () and mono_method_get_header () to get the correct values.
1108 MonoMethod*
1109 mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error)
1111 MonoMethod *result;
1112 MonoMethodInflated *iresult, *cached;
1113 MonoMethodSignature *sig;
1114 MonoGenericContext tmp_context;
1116 error_init (error);
1118 /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
1119 while (method->is_inflated) {
1120 MonoGenericContext *method_context = mono_method_get_context (method);
1121 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1123 tmp_context = inflate_generic_context (method_context, context, error);
1124 return_val_if_nok (error, NULL);
1126 context = &tmp_context;
1128 if (mono_metadata_generic_context_equal (method_context, context))
1129 return method;
1131 method = imethod->declaring;
1135 * A method only needs to be inflated if the context has argument for which it is
1136 * parametric. Eg:
1138 * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
1139 * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
1142 if (!((method->is_generic && context->method_inst) ||
1143 (mono_class_is_gtd (method->klass) && context->class_inst)))
1144 return method;
1146 iresult = g_new0 (MonoMethodInflated, 1);
1147 iresult->context = *context;
1148 iresult->declaring = method;
1150 if (!context->method_inst && method->is_generic)
1151 iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
1153 if (!context->class_inst) {
1154 g_assert (!mono_class_is_ginst (iresult->declaring->klass));
1155 if (mono_class_is_gtd (iresult->declaring->klass))
1156 iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst;
1158 /* This can happen with some callers like mono_object_get_virtual_method_internal () */
1159 if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass))
1160 iresult->context.class_inst = NULL;
1162 MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
1164 // check cache
1165 mono_image_set_lock (set);
1166 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1167 mono_image_set_unlock (set);
1169 if (cached) {
1170 g_free (iresult);
1171 return (MonoMethod*)cached;
1174 UnlockedIncrement (&mono_stats.inflated_method_count);
1176 UnlockedAdd (&mono_inflated_methods_size, sizeof (MonoMethodInflated));
1178 sig = mono_method_signature_internal (method);
1179 if (!sig) {
1180 char *name = mono_type_get_full_name (method->klass);
1181 mono_error_set_bad_image (error, mono_method_get_image (method), "Could not resolve signature of method %s:%s", name, method->name);
1182 g_free (name);
1183 goto fail;
1186 if (sig->pinvoke) {
1187 memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
1188 } else {
1189 memcpy (&iresult->method.method, method, sizeof (MonoMethod));
1192 result = (MonoMethod *) iresult;
1193 result->is_inflated = TRUE;
1194 result->is_generic = FALSE;
1195 result->sre_method = FALSE;
1196 result->signature = NULL;
1198 if (method->wrapper_type) {
1199 MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
1200 MonoMethodWrapper *resw = (MonoMethodWrapper*)result;
1201 int len = GPOINTER_TO_INT (((void**)mw->method_data) [0]);
1203 resw->method_data = (void **)g_malloc (sizeof (gpointer) * (len + 1));
1204 memcpy (resw->method_data, mw->method_data, sizeof (gpointer) * (len + 1));
1207 if (iresult->context.method_inst) {
1208 MonoGenericInst *method_inst = iresult->context.method_inst;
1209 /* Set the generic_container of the result to the generic_container of method */
1210 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
1212 if (generic_container && method_inst == generic_container->context.method_inst) {
1213 result->is_generic = 1;
1214 mono_method_set_generic_container (result, generic_container);
1217 /* Check that the method is not instantiated with any invalid types */
1218 for (int i = 0; i < method_inst->type_argc; i++) {
1219 if (!mono_type_is_valid_generic_argument (method_inst->type_argv [i])) {
1220 mono_error_set_bad_image (error, mono_method_get_image (method), "MVAR %d cannot be expanded with type 0x%x",
1221 i, method_inst->type_argv [i]->type);
1222 goto fail;
1227 if (klass_hint) {
1228 MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint);
1229 if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst))
1230 klass_hint = NULL;
1233 if (mono_class_is_gtd (method->klass))
1234 result->klass = klass_hint;
1236 if (!result->klass) {
1237 MonoType *inflated = inflate_generic_type (NULL, m_class_get_byval_arg (method->klass), context, error);
1238 if (!is_ok (error))
1239 goto fail;
1241 result->klass = inflated ? mono_class_from_mono_type_internal (inflated) : method->klass;
1242 if (inflated)
1243 mono_metadata_free_type (inflated);
1247 * FIXME: This should hold, but it doesn't:
1249 * if (result->is_inflated && mono_method_get_context (result)->method_inst &&
1250 * mono_method_get_context (result)->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)result)->declaring)->context.method_inst) {
1251 * g_assert (result->is_generic);
1254 * Fixing this here causes other things to break, hence a very
1255 * ugly hack in mini-trampolines.c - see
1256 * is_generic_method_definition().
1259 // check cache
1260 mono_image_set_lock (set);
1261 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1262 if (!cached) {
1263 g_hash_table_insert (set->gmethod_cache, iresult, iresult);
1264 iresult->owner = set;
1265 cached = iresult;
1267 mono_image_set_unlock (set);
1269 return (MonoMethod*)cached;
1271 fail:
1272 g_free (iresult);
1273 return NULL;
1277 * mono_get_inflated_method:
1279 * Obsolete. We keep it around since it's mentioned in the public API.
1281 MonoMethod*
1282 mono_get_inflated_method (MonoMethod *method)
1284 return method;
1288 * mono_method_get_context_general:
1289 * @method: a method
1290 * @uninflated: handle uninflated methods?
1292 * Returns the generic context of a method or NULL if it doesn't have
1293 * one. For an inflated method that's the context stored in the
1294 * method. Otherwise it's in the method's generic container or in the
1295 * generic container of the method's class.
1297 MonoGenericContext*
1298 mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
1300 if (method->is_inflated) {
1301 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1302 return &imethod->context;
1304 if (!uninflated)
1305 return NULL;
1306 if (method->is_generic)
1307 return &(mono_method_get_generic_container (method)->context);
1308 if (mono_class_is_gtd (method->klass))
1309 return &mono_class_get_generic_container (method->klass)->context;
1310 return NULL;
1314 * mono_method_get_context:
1315 * @method: a method
1317 * Returns the generic context for method if it's inflated, otherwise
1318 * NULL.
1320 MonoGenericContext*
1321 mono_method_get_context (MonoMethod *method)
1323 return mono_method_get_context_general (method, FALSE);
1327 * mono_method_get_generic_container:
1329 * Returns the generic container of METHOD, which should be a generic method definition.
1330 * Returns NULL if METHOD is not a generic method definition.
1331 * LOCKING: Acquires the loader lock.
1333 MonoGenericContainer*
1334 mono_method_get_generic_container (MonoMethod *method)
1336 MonoGenericContainer *container;
1338 if (!method->is_generic)
1339 return NULL;
1341 container = (MonoGenericContainer *)mono_image_property_lookup (mono_method_get_image (method), method, MONO_METHOD_PROP_GENERIC_CONTAINER);
1342 g_assert (container);
1344 return container;
1348 * mono_method_set_generic_container:
1350 * Sets the generic container of METHOD to CONTAINER.
1351 * LOCKING: Acquires the image lock.
1353 void
1354 mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
1356 g_assert (method->is_generic);
1358 mono_image_property_insert (mono_method_get_image (method), method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
1361 /**
1362 * mono_class_find_enum_basetype:
1363 * \param class The enum class
1365 * Determine the basetype of an enum by iterating through its fields. We do this
1366 * in a separate function since it is cheaper than calling mono_class_setup_fields.
1368 MonoType*
1369 mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
1371 MonoGenericContainer *container = NULL;
1372 MonoImage *image = m_class_get_image (klass);
1373 const int top = mono_class_get_field_count (klass);
1374 int i, first_field_idx;
1376 g_assert (m_class_is_enumtype (klass));
1378 error_init (error);
1380 container = mono_class_try_get_generic_container (klass);
1381 if (mono_class_is_ginst (klass)) {
1382 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1384 container = mono_class_get_generic_container (gklass);
1385 g_assert (container);
1389 * Fetch all the field information.
1391 first_field_idx = mono_class_get_first_field_idx (klass);
1392 for (i = 0; i < top; i++){
1393 const char *sig;
1394 guint32 cols [MONO_FIELD_SIZE];
1395 int idx = first_field_idx + i;
1396 MonoType *ftype;
1398 /* first_field_idx and idx points into the fieldptr table */
1399 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
1401 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
1402 continue;
1404 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], error))
1405 goto fail;
1407 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
1408 mono_metadata_decode_value (sig, &sig);
1409 /* FIELD signature == 0x06 */
1410 if (*sig != 0x06) {
1411 mono_error_set_bad_image (error, image, "Invalid field signature %x, expected 0x6 but got %x", cols [MONO_FIELD_SIGNATURE], *sig);
1412 goto fail;
1415 ftype = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
1416 if (!ftype)
1417 goto fail;
1419 if (mono_class_is_ginst (klass)) {
1420 //FIXME do we leak here?
1421 ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error);
1422 if (!is_ok (error))
1423 goto fail;
1424 ftype->attrs = cols [MONO_FIELD_FLAGS];
1427 return ftype;
1429 mono_error_set_type_load_class (error, klass, "Could not find base type");
1431 fail:
1432 return NULL;
1436 * Checks for MonoClass::has_failure without resolving all MonoType's into MonoClass'es
1438 gboolean
1439 mono_type_has_exceptions (MonoType *type)
1441 switch (type->type) {
1442 case MONO_TYPE_CLASS:
1443 case MONO_TYPE_VALUETYPE:
1444 case MONO_TYPE_SZARRAY:
1445 return mono_class_has_failure (type->data.klass);
1446 case MONO_TYPE_ARRAY:
1447 return mono_class_has_failure (type->data.array->eklass);
1448 case MONO_TYPE_GENERICINST:
1449 return mono_class_has_failure (mono_class_create_generic_inst (type->data.generic_class));
1450 default:
1451 return FALSE;
1455 void
1456 mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
1458 g_assert (mono_class_has_failure (klass));
1459 MonoErrorBoxed *box = mono_class_get_exception_data ((MonoClass*)klass);
1460 mono_error_set_from_boxed (oerror, box);
1464 * mono_class_alloc:
1466 * Allocate memory for some data belonging to CLASS, either from its image's mempool,
1467 * or from the heap.
1469 gpointer
1470 mono_class_alloc (MonoClass *klass, int size)
1472 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1473 if (gklass)
1474 return mono_image_set_alloc (gklass->owner, size);
1475 else
1476 return mono_image_alloc (m_class_get_image (klass), size);
1479 gpointer
1480 (mono_class_alloc0) (MonoClass *klass, int size)
1482 gpointer res;
1484 res = mono_class_alloc (klass, size);
1485 memset (res, 0, size);
1486 return res;
1489 #define mono_class_new0(klass,struct_type, n_structs) \
1490 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
1493 * mono_class_set_failure_causedby_class:
1494 * \param klass the class that is failing
1495 * \param caused_by the class that caused the failure
1496 * \param msg Why \p klass is failing.
1498 * If \p caused_by has a failure, sets a TypeLoadException failure on
1499 * \p klass with message "\p msg, due to: {\p caused_by message}".
1501 * \returns TRUE if a failiure was set, or FALSE if \p caused_by doesn't have a failure.
1503 gboolean
1504 mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg)
1506 if (mono_class_has_failure (caused_by)) {
1507 ERROR_DECL (cause_error);
1508 mono_error_set_for_class_failure (cause_error, caused_by);
1509 mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (cause_error));
1510 mono_error_cleanup (cause_error);
1511 return TRUE;
1512 } else {
1513 return FALSE;
1519 * mono_type_get_basic_type_from_generic:
1520 * @type: a type
1522 * Returns a closed type corresponding to the possibly open type
1523 * passed to it.
1525 MonoType*
1526 mono_type_get_basic_type_from_generic (MonoType *type)
1528 /* When we do generic sharing we let type variables stand for reference/primitive types. */
1529 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) &&
1530 (!type->data.generic_param->gshared_constraint || type->data.generic_param->gshared_constraint->type == MONO_TYPE_OBJECT))
1531 return mono_get_object_type ();
1532 return type;
1536 * mono_class_get_method_by_index:
1538 * Returns klass->methods [index], initializing klass->methods if neccesary.
1540 * LOCKING: Acquires the loader lock.
1542 MonoMethod*
1543 mono_class_get_method_by_index (MonoClass *klass, int index)
1545 ERROR_DECL (error);
1547 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1548 /* Avoid calling setup_methods () if possible */
1549 if (gklass && !m_class_get_methods (klass)) {
1550 MonoMethod *m;
1552 m = mono_class_inflate_generic_method_full_checked (
1553 m_class_get_methods (gklass->container_class) [index], klass, mono_class_get_context (klass), error);
1554 g_assert (is_ok (error)); /* FIXME don't swallow the error */
1556 * If setup_methods () is called later for this class, no duplicates are created,
1557 * since inflate_generic_method guarantees that only one instance of a method
1558 * is created for each context.
1561 mono_class_setup_methods (klass);
1562 g_assert (m == klass->methods [index]);
1564 return m;
1565 } else {
1566 mono_class_setup_methods (klass);
1567 if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
1568 return NULL;
1569 g_assert (index >= 0 && index < mono_class_get_method_count (klass));
1570 return m_class_get_methods (klass) [index];
1575 * mono_class_get_inflated_method:
1576 * \param klass an inflated class
1577 * \param method a method of \p klass's generic definition
1578 * \param error set on error
1580 * Given an inflated class \p klass and a method \p method which should be a
1581 * method of \p klass's generic definition, return the inflated method
1582 * corresponding to \p method.
1584 * On failure sets \p error and returns NULL.
1586 MonoMethod*
1587 mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method, MonoError *error)
1589 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1590 int i, mcount;
1592 g_assert (method->klass == gklass);
1594 mono_class_setup_methods (gklass);
1595 if (mono_class_has_failure (gklass)) {
1596 mono_error_set_for_class_failure (error, gklass);
1597 return NULL;
1600 MonoMethod **gklass_methods = m_class_get_methods (gklass);
1601 mcount = mono_class_get_method_count (gklass);
1602 for (i = 0; i < mcount; ++i) {
1603 if (gklass_methods [i] == method) {
1604 MonoMethod *inflated_method = NULL;
1605 MonoMethod **klass_methods = m_class_get_methods (klass);
1606 if (klass_methods) {
1607 inflated_method = klass_methods [i];
1608 } else {
1609 inflated_method = mono_class_inflate_generic_method_full_checked (gklass_methods [i], klass, mono_class_get_context (klass), error);
1610 return_val_if_nok (error, NULL);
1612 g_assert (inflated_method);
1613 return inflated_method;
1617 g_assert_not_reached ();
1621 * mono_class_get_vtable_entry:
1623 * Returns klass->vtable [offset], computing it if neccesary. Returns NULL on failure.
1624 * LOCKING: Acquires the loader lock.
1626 MonoMethod*
1627 mono_class_get_vtable_entry (MonoClass *klass, int offset)
1629 MonoMethod *m;
1631 if (m_class_get_rank (klass) == 1) {
1632 MonoClass *klass_parent = m_class_get_parent (klass);
1634 * szarrays do not overwrite any methods of Array, so we can avoid
1635 * initializing their vtables in some cases.
1637 mono_class_setup_vtable (klass_parent);
1638 if (offset < m_class_get_vtable_size (klass_parent))
1639 return m_class_get_vtable (klass_parent) [offset];
1642 if (mono_class_is_ginst (klass)) {
1643 ERROR_DECL (error);
1644 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1645 mono_class_setup_vtable (gklass);
1646 m = m_class_get_vtable (gklass) [offset];
1648 m = mono_class_inflate_generic_method_full_checked (m, klass, mono_class_get_context (klass), error);
1649 g_assert (is_ok (error)); /* FIXME don't swallow this error */
1650 } else {
1651 mono_class_setup_vtable (klass);
1652 if (mono_class_has_failure (klass))
1653 return NULL;
1654 m = m_class_get_vtable (klass) [offset];
1657 return m;
1661 * mono_class_get_vtable_size:
1663 * Return the vtable size for KLASS.
1666 mono_class_get_vtable_size (MonoClass *klass)
1668 mono_class_setup_vtable (klass);
1670 return m_class_get_vtable_size (klass);
1673 static void
1674 collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, GHashTable **ifaces, MonoError *error)
1676 int i;
1677 MonoClass *ic;
1679 mono_class_setup_interfaces (klass, error);
1680 return_if_nok (error);
1682 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
1683 for (i = 0; i < m_class_get_interface_count (klass); i++) {
1684 ic = klass_interfaces [i];
1686 if (*res == NULL)
1687 *res = g_ptr_array_new ();
1688 if (*ifaces == NULL)
1689 *ifaces = g_hash_table_new (NULL, NULL);
1690 if (g_hash_table_lookup (*ifaces, ic))
1691 continue;
1692 /* A gparam is not an implemented interface for the purposes of
1693 * mono_class_get_implemented_interfaces */
1694 if (mono_class_is_gparam (ic))
1695 continue;
1696 g_ptr_array_add (*res, ic);
1697 g_hash_table_insert (*ifaces, ic, ic);
1698 mono_class_init_internal (ic);
1699 if (mono_class_has_failure (ic)) {
1700 mono_error_set_type_load_class (error, ic, "Error Loading class");
1701 return;
1704 collect_implemented_interfaces_aux (ic, res, ifaces, error);
1705 return_if_nok (error);
1709 GPtrArray*
1710 mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error)
1712 GPtrArray *res = NULL;
1713 GHashTable *ifaces = NULL;
1715 collect_implemented_interfaces_aux (klass, &res, &ifaces, error);
1716 if (ifaces)
1717 g_hash_table_destroy (ifaces);
1718 if (!is_ok (error)) {
1719 if (res)
1720 g_ptr_array_free (res, TRUE);
1721 return NULL;
1723 return res;
1726 /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/
1728 mono_class_interface_offset (MonoClass *klass, MonoClass *itf)
1730 int i;
1731 MonoClass **klass_interfaces_packed = m_class_get_interfaces_packed (klass);
1732 for (i = m_class_get_interface_offsets_count (klass) -1 ; i >= 0 ; i-- ){
1733 MonoClass *result = klass_interfaces_packed[i];
1734 if (m_class_get_interface_id(result) == m_class_get_interface_id(itf)) {
1735 return m_class_get_interface_offsets_packed (klass) [i];
1738 return -1;
1742 * mono_class_interface_offset_with_variance:
1744 * Return the interface offset of \p itf in \p klass. Sets \p non_exact_match to TRUE if the match required variance check
1745 * If \p itf is an interface with generic variant arguments, try to find the compatible one.
1747 * Note that this function is responsible for resolving ambiguities. Right now we use whatever ordering interfaces_packed gives us.
1749 * FIXME figure out MS disambiguation rules and fix this function.
1752 mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match)
1754 int i = mono_class_interface_offset (klass, itf);
1755 *non_exact_match = FALSE;
1756 if (i >= 0)
1757 return i;
1759 int klass_interface_offsets_count = m_class_get_interface_offsets_count (klass);
1761 if (m_class_is_array_special_interface (itf) && m_class_get_rank (klass) < 2) {
1762 MonoClass *gtd = mono_class_get_generic_type_definition (itf);
1763 int found = -1;
1765 for (i = 0; i < klass_interface_offsets_count; i++) {
1766 if (mono_class_is_variant_compatible (itf, m_class_get_interfaces_packed (klass) [i], FALSE)) {
1767 found = i;
1768 *non_exact_match = TRUE;
1769 break;
1773 if (found != -1)
1774 return m_class_get_interface_offsets_packed (klass) [found];
1776 for (i = 0; i < klass_interface_offsets_count; i++) {
1777 if (mono_class_get_generic_type_definition (m_class_get_interfaces_packed (klass) [i]) == gtd) {
1778 found = i;
1779 *non_exact_match = TRUE;
1780 break;
1784 if (found == -1)
1785 return -1;
1787 return m_class_get_interface_offsets_packed (klass) [found];
1790 if (!mono_class_has_variant_generic_params (itf))
1791 return -1;
1793 for (i = 0; i < klass_interface_offsets_count; i++) {
1794 if (mono_class_is_variant_compatible (itf, m_class_get_interfaces_packed (klass) [i], FALSE)) {
1795 *non_exact_match = TRUE;
1796 return m_class_get_interface_offsets_packed (klass) [i];
1800 return -1;
1805 * mono_method_get_vtable_slot:
1807 * Returns method->slot, computing it if neccesary. Return -1 on failure.
1808 * LOCKING: Acquires the loader lock.
1810 * FIXME Use proper MonoError machinery here.
1813 mono_method_get_vtable_slot (MonoMethod *method)
1815 if (method->slot == -1) {
1816 mono_class_setup_vtable (method->klass);
1817 if (mono_class_has_failure (method->klass))
1818 return -1;
1819 if (method->slot == -1) {
1820 MonoClass *gklass;
1821 int i, mcount;
1823 if (!mono_class_is_ginst (method->klass)) {
1824 g_assert (method->is_inflated);
1825 return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
1828 /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
1829 g_assert (mono_class_is_ginst (method->klass));
1830 gklass = mono_class_get_generic_class (method->klass)->container_class;
1831 mono_class_setup_methods (method->klass);
1832 MonoMethod **klass_methods = m_class_get_methods (method->klass);
1833 g_assert (klass_methods);
1834 mcount = mono_class_get_method_count (method->klass);
1835 for (i = 0; i < mcount; ++i) {
1836 if (klass_methods [i] == method)
1837 break;
1839 g_assert (i < mcount);
1840 g_assert (m_class_get_methods (gklass));
1841 method->slot = m_class_get_methods (gklass) [i]->slot;
1843 g_assert (method->slot != -1);
1845 return method->slot;
1849 * mono_method_get_vtable_index:
1850 * \param method a method
1852 * Returns the index into the runtime vtable to access the method or,
1853 * in the case of a virtual generic method, the virtual generic method
1854 * thunk. Returns -1 on failure.
1856 * FIXME Use proper MonoError machinery here.
1859 mono_method_get_vtable_index (MonoMethod *method)
1861 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
1862 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
1863 if (imethod->declaring->is_generic)
1864 return mono_method_get_vtable_slot (imethod->declaring);
1866 return mono_method_get_vtable_slot (method);
1870 * mono_class_has_finalizer:
1872 * Return whenever KLASS has a finalizer, initializing klass->has_finalizer in the
1873 * process.
1875 * LOCKING: Acquires the loader lock;
1877 gboolean
1878 mono_class_has_finalizer (MonoClass *klass)
1880 if (!m_class_is_has_finalize_inited (klass))
1881 mono_class_setup_has_finalizer (klass);
1883 return m_class_has_finalize (klass);
1886 gboolean
1887 mono_is_corlib_image (MonoImage *image)
1889 return image == mono_defaults.corlib;
1893 /** Is klass a Nullable<T> ginst? */
1894 gboolean
1895 mono_class_is_nullable (MonoClass *klass)
1897 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1898 return gklass && gklass->container_class == mono_defaults.generic_nullable_class;
1901 /** if klass is T? return T */
1902 MonoClass*
1903 mono_class_get_nullable_param_internal (MonoClass *klass)
1905 g_assert (mono_class_is_nullable (klass));
1906 return mono_class_from_mono_type_internal (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
1909 MonoClass*
1910 mono_class_get_nullable_param (MonoClass *klass)
1912 MonoClass *result = NULL;
1913 MONO_ENTER_GC_UNSAFE;
1914 result = mono_class_get_nullable_param_internal (klass);
1915 MONO_EXIT_GC_UNSAFE;
1916 return result;
1919 gboolean
1920 mono_type_is_primitive (MonoType *type)
1922 return (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_R8) ||
1923 type-> type == MONO_TYPE_I || type->type == MONO_TYPE_U;
1926 static MonoImage *
1927 get_image_for_container (MonoGenericContainer *container)
1929 MonoImage *result;
1930 if (container->is_anonymous) {
1931 result = container->owner.image;
1932 } else {
1933 MonoClass *klass;
1934 if (container->is_method) {
1935 MonoMethod *method = container->owner.method;
1936 g_assert_checked (method);
1937 klass = method->klass;
1938 } else {
1939 klass = container->owner.klass;
1941 g_assert_checked (klass);
1942 result = m_class_get_image (klass);
1944 g_assert (result);
1945 return result;
1948 MonoImage *
1949 mono_get_image_for_generic_param (MonoGenericParam *param)
1951 MonoGenericContainer *container = mono_generic_param_owner (param);
1952 g_assert_checked (container);
1953 return get_image_for_container (container);
1956 // Make a string in the designated image consisting of a single integer.
1957 #define INT_STRING_SIZE 16
1958 char *
1959 mono_make_generic_name_string (MonoImage *image, int num)
1961 char *name = (char *)mono_image_alloc0 (image, INT_STRING_SIZE);
1962 g_snprintf (name, INT_STRING_SIZE, "%d", num);
1963 return name;
1967 * mono_class_from_generic_parameter:
1968 * \param param Parameter to find/construct a class for.
1969 * \param arg2 Is ignored.
1970 * \param arg3 Is ignored.
1972 MonoClass *
1973 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GNUC_UNUSED, gboolean arg3 G_GNUC_UNUSED)
1975 return mono_class_create_generic_parameter (param);
1979 * mono_ptr_class_get:
1981 MonoClass *
1982 mono_ptr_class_get (MonoType *type)
1984 return mono_class_create_ptr (type);
1988 * mono_class_from_mono_type:
1989 * \param type describes the type to return
1990 * \returns a \c MonoClass for the specified \c MonoType, the value is never NULL.
1992 MonoClass *
1993 mono_class_from_mono_type (MonoType *type)
1995 MonoClass *result;
1996 MONO_ENTER_GC_UNSAFE;
1997 result = mono_class_from_mono_type_internal (type);
1998 MONO_EXIT_GC_UNSAFE;
1999 return result;
2002 MonoClass *
2003 mono_class_from_mono_type_internal (MonoType *type)
2005 g_assert (type);
2006 switch (type->type) {
2007 case MONO_TYPE_OBJECT:
2008 return type->data.klass? type->data.klass: mono_defaults.object_class;
2009 case MONO_TYPE_VOID:
2010 return type->data.klass? type->data.klass: mono_defaults.void_class;
2011 case MONO_TYPE_BOOLEAN:
2012 return type->data.klass? type->data.klass: mono_defaults.boolean_class;
2013 case MONO_TYPE_CHAR:
2014 return type->data.klass? type->data.klass: mono_defaults.char_class;
2015 case MONO_TYPE_I1:
2016 return type->data.klass? type->data.klass: mono_defaults.sbyte_class;
2017 case MONO_TYPE_U1:
2018 return type->data.klass? type->data.klass: mono_defaults.byte_class;
2019 case MONO_TYPE_I2:
2020 return type->data.klass? type->data.klass: mono_defaults.int16_class;
2021 case MONO_TYPE_U2:
2022 return type->data.klass? type->data.klass: mono_defaults.uint16_class;
2023 case MONO_TYPE_I4:
2024 return type->data.klass? type->data.klass: mono_defaults.int32_class;
2025 case MONO_TYPE_U4:
2026 return type->data.klass? type->data.klass: mono_defaults.uint32_class;
2027 case MONO_TYPE_I:
2028 return type->data.klass? type->data.klass: mono_defaults.int_class;
2029 case MONO_TYPE_U:
2030 return type->data.klass? type->data.klass: mono_defaults.uint_class;
2031 case MONO_TYPE_I8:
2032 return type->data.klass? type->data.klass: mono_defaults.int64_class;
2033 case MONO_TYPE_U8:
2034 return type->data.klass? type->data.klass: mono_defaults.uint64_class;
2035 case MONO_TYPE_R4:
2036 return type->data.klass? type->data.klass: mono_defaults.single_class;
2037 case MONO_TYPE_R8:
2038 return type->data.klass? type->data.klass: mono_defaults.double_class;
2039 case MONO_TYPE_STRING:
2040 return type->data.klass? type->data.klass: mono_defaults.string_class;
2041 case MONO_TYPE_TYPEDBYREF:
2042 return type->data.klass? type->data.klass: mono_defaults.typed_reference_class;
2043 case MONO_TYPE_ARRAY:
2044 return mono_class_create_bounded_array (type->data.array->eklass, type->data.array->rank, TRUE);
2045 case MONO_TYPE_PTR:
2046 return mono_class_create_ptr (type->data.type);
2047 case MONO_TYPE_FNPTR:
2048 return mono_class_create_fnptr (type->data.method);
2049 case MONO_TYPE_SZARRAY:
2050 return mono_class_create_array (type->data.klass, 1);
2051 case MONO_TYPE_CLASS:
2052 case MONO_TYPE_VALUETYPE:
2053 return type->data.klass;
2054 case MONO_TYPE_GENERICINST:
2055 return mono_class_create_generic_inst (type->data.generic_class);
2056 case MONO_TYPE_MVAR:
2057 case MONO_TYPE_VAR:
2058 return mono_class_create_generic_parameter (type->data.generic_param);
2059 default:
2060 g_warning ("mono_class_from_mono_type_internal: implement me 0x%02x\n", type->type);
2061 g_assert_not_reached ();
2064 // Yes, this returns NULL, even if it is documented as not doing so, but there
2065 // is no way for the code to make it this far, due to the assert above.
2066 return NULL;
2070 * mono_type_retrieve_from_typespec
2071 * \param image context where the image is created
2072 * \param type_spec typespec token
2073 * \param context the generic context used to evaluate generic instantiations in
2075 static MonoType *
2076 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
2078 MonoType *t = mono_type_create_from_typespec_checked (image, type_spec, error);
2080 *did_inflate = FALSE;
2082 if (!t)
2083 return NULL;
2085 if (context && (context->class_inst || context->method_inst)) {
2086 MonoType *inflated = inflate_generic_type (NULL, t, context, error);
2088 if (!is_ok (error)) {
2089 return NULL;
2092 if (inflated) {
2093 t = inflated;
2094 *did_inflate = TRUE;
2097 return t;
2101 * mono_class_create_from_typespec
2102 * \param image context where the image is created
2103 * \param type_spec typespec token
2104 * \param context the generic context used to evaluate generic instantiations in
2106 static MonoClass *
2107 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
2109 MonoClass *ret;
2110 gboolean inflated = FALSE;
2111 MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
2112 return_val_if_nok (error, NULL);
2113 ret = mono_class_from_mono_type_internal (t);
2114 if (inflated)
2115 mono_metadata_free_type (t);
2116 return ret;
2120 * mono_bounded_array_class_get:
2121 * \param element_class element class
2122 * \param rank the dimension of the array class
2123 * \param bounded whenever the array has non-zero bounds
2124 * \returns A class object describing the array with element type \p element_type and
2125 * dimension \p rank.
2127 MonoClass *
2128 mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
2130 return mono_class_create_bounded_array (eclass, rank, bounded);
2134 * mono_array_class_get:
2135 * \param element_class element class
2136 * \param rank the dimension of the array class
2137 * \returns A class object describing the array with element type \p element_type and
2138 * dimension \p rank.
2140 MonoClass *
2141 mono_array_class_get (MonoClass *eclass, guint32 rank)
2143 return mono_class_create_array (eclass, rank);
2147 * mono_class_instance_size:
2148 * \param klass a class
2150 * Use to get the size of a class in bytes.
2152 * \returns The size of an object instance
2154 gint32
2155 mono_class_instance_size (MonoClass *klass)
2157 if (!m_class_is_size_inited (klass))
2158 mono_class_init_internal (klass);
2160 return m_class_get_instance_size (klass);
2164 * mono_class_min_align:
2165 * \param klass a class
2167 * Use to get the computed minimum alignment requirements for the specified class.
2169 * Returns: minimum alignment requirements
2171 gint32
2172 mono_class_min_align (MonoClass *klass)
2174 if (!m_class_is_size_inited (klass))
2175 mono_class_init_internal (klass);
2177 return m_class_get_min_align (klass);
2181 * mono_class_data_size:
2182 * \param klass a class
2184 * \returns The size of the static class data
2186 gint32
2187 mono_class_data_size (MonoClass *klass)
2189 if (!m_class_is_inited (klass))
2190 mono_class_init_internal (klass);
2191 /* This can happen with dynamically created types */
2192 if (!m_class_is_fields_inited (klass))
2193 mono_class_setup_fields (klass);
2195 /* in arrays, sizes.class_size is unioned with element_size
2196 * and arrays have no static fields
2198 if (m_class_get_rank (klass))
2199 return 0;
2200 return m_class_get_sizes (klass).class_size;
2204 * Auxiliary routine to mono_class_get_field
2206 * Takes a field index instead of a field token.
2208 static MonoClassField *
2209 mono_class_get_field_idx (MonoClass *klass, int idx)
2211 mono_class_setup_fields (klass);
2212 if (mono_class_has_failure (klass))
2213 return NULL;
2215 while (klass) {
2216 int first_field_idx = mono_class_get_first_field_idx (klass);
2217 int fcount = mono_class_get_field_count (klass);
2218 MonoImage *klass_image = m_class_get_image (klass);
2219 MonoClassField *klass_fields = m_class_get_fields (klass);
2220 if (klass_image->uncompressed_metadata) {
2222 * first_field_idx points to the FieldPtr table, while idx points into the
2223 * Field table, so we have to do a search.
2225 /*FIXME this is broken for types with multiple fields with the same name.*/
2226 const char *name = mono_metadata_string_heap (klass_image, mono_metadata_decode_row_col (&klass_image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
2227 int i;
2229 for (i = 0; i < fcount; ++i)
2230 if (mono_field_get_name (&klass_fields [i]) == name)
2231 return &klass_fields [i];
2232 g_assert_not_reached ();
2233 } else {
2234 if (fcount) {
2235 if ((idx >= first_field_idx) && (idx < first_field_idx + fcount)){
2236 return &klass_fields [idx - first_field_idx];
2240 klass = m_class_get_parent (klass);
2242 return NULL;
2246 * mono_class_get_field:
2247 * \param class the class to lookup the field.
2248 * \param field_token the field token
2250 * \returns A \c MonoClassField representing the type and offset of
2251 * the field, or a NULL value if the field does not belong to this
2252 * class.
2254 MonoClassField *
2255 mono_class_get_field (MonoClass *klass, guint32 field_token)
2257 int idx = mono_metadata_token_index (field_token);
2259 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
2261 return mono_class_get_field_idx (klass, idx - 1);
2265 * mono_class_get_field_from_name:
2266 * \param klass the class to lookup the field.
2267 * \param name the field name
2269 * Search the class \p klass and its parents for a field with the name \p name.
2271 * \returns The \c MonoClassField pointer of the named field or NULL
2273 MonoClassField *
2274 mono_class_get_field_from_name (MonoClass *klass, const char *name)
2276 MonoClassField *result;
2277 MONO_ENTER_GC_UNSAFE;
2278 result = mono_class_get_field_from_name_full (klass, name, NULL);
2279 MONO_EXIT_GC_UNSAFE;
2280 return result;
2284 * mono_class_get_field_from_name_full:
2285 * \param klass the class to lookup the field.
2286 * \param name the field name
2287 * \param type the type of the fields. This optional.
2289 * Search the class \p klass and it's parents for a field with the name \p name and type \p type.
2291 * If \p klass is an inflated generic type, the type comparison is done with the equivalent field
2292 * of its generic type definition.
2294 * \returns The MonoClassField pointer of the named field or NULL
2296 MonoClassField *
2297 mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
2299 MONO_REQ_GC_UNSAFE_MODE;
2301 int i;
2303 mono_class_setup_fields (klass);
2304 if (mono_class_has_failure (klass))
2305 return NULL;
2307 while (klass) {
2308 int fcount = mono_class_get_field_count (klass);
2309 for (i = 0; i < fcount; ++i) {
2310 MonoClassField *field = &m_class_get_fields (klass) [i];
2312 if (strcmp (name, mono_field_get_name (field)) != 0)
2313 continue;
2315 if (type) {
2316 MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
2317 if (!mono_metadata_type_equal_full (type, field_type, TRUE))
2318 continue;
2320 return field;
2322 klass = m_class_get_parent (klass);
2324 return NULL;
2328 * mono_class_get_field_token:
2329 * \param field the field we need the token of
2331 * Get the token of a field. Note that the tokesn is only valid for the image
2332 * the field was loaded from. Don't use this function for fields in dynamic types.
2334 * \returns The token representing the field in the image it was loaded from.
2336 guint32
2337 mono_class_get_field_token (MonoClassField *field)
2339 MonoClass *klass = field->parent;
2340 int i;
2342 mono_class_setup_fields (klass);
2344 while (klass) {
2345 MonoClassField *klass_fields = m_class_get_fields (klass);
2346 if (!klass_fields)
2347 return 0;
2348 int first_field_idx = mono_class_get_first_field_idx (klass);
2349 int fcount = mono_class_get_field_count (klass);
2350 for (i = 0; i < fcount; ++i) {
2351 if (&klass_fields [i] == field) {
2352 int idx = first_field_idx + i + 1;
2354 if (m_class_get_image (klass)->uncompressed_metadata)
2355 idx = mono_metadata_translate_token_index (m_class_get_image (klass), MONO_TABLE_FIELD, idx);
2356 return mono_metadata_make_token (MONO_TABLE_FIELD, idx);
2359 klass = m_class_get_parent (klass);
2362 g_assert_not_reached ();
2363 return 0;
2366 static int
2367 mono_field_get_index (MonoClassField *field)
2369 int index = field - m_class_get_fields (field->parent);
2370 g_assert (index >= 0 && index < mono_class_get_field_count (field->parent));
2372 return index;
2376 * mono_class_get_field_default_value:
2378 * Return the default value of the field as a pointer into the metadata blob.
2380 const char*
2381 mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
2383 guint32 cindex;
2384 guint32 constant_cols [MONO_CONSTANT_SIZE];
2385 int field_index;
2386 MonoClass *klass = field->parent;
2387 MonoFieldDefaultValue *def_values;
2389 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2391 def_values = mono_class_get_field_def_values (klass);
2392 if (!def_values) {
2393 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
2395 mono_class_set_field_def_values (klass, def_values);
2398 field_index = mono_field_get_index (field);
2400 if (!def_values [field_index].data) {
2401 MonoImage *field_parent_image = m_class_get_image (field->parent);
2402 cindex = mono_metadata_get_constant_index (field_parent_image, mono_class_get_field_token (field), 0);
2403 if (!cindex)
2404 return NULL;
2406 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
2408 mono_metadata_decode_row (&field_parent_image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
2409 def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
2410 mono_memory_barrier ();
2411 def_values [field_index].data = (const char *)mono_metadata_blob_heap (field_parent_image, constant_cols [MONO_CONSTANT_VALUE]);
2414 *def_type = def_values [field_index].def_type;
2415 return def_values [field_index].data;
2418 static int
2419 mono_property_get_index (MonoProperty *prop)
2421 MonoClassPropertyInfo *info = mono_class_get_property_info (prop->parent);
2422 int index = prop - info->properties;
2424 g_assert (index >= 0 && index < info->count);
2426 return index;
2430 * mono_class_get_property_default_value:
2432 * Return the default value of the field as a pointer into the metadata blob.
2434 const char*
2435 mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type)
2437 guint32 cindex;
2438 guint32 constant_cols [MONO_CONSTANT_SIZE];
2439 MonoClass *klass = property->parent;
2440 MonoImage *klass_image = m_class_get_image (klass);
2442 g_assert (property->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT);
2444 * We don't cache here because it is not used by C# so it's quite rare, but
2445 * we still do the lookup in klass->ext because that is where the data
2446 * is stored for dynamic assemblies.
2449 if (image_is_dynamic (klass_image)) {
2450 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
2451 int prop_index = mono_property_get_index (property);
2452 if (info->def_values && info->def_values [prop_index].data) {
2453 *def_type = info->def_values [prop_index].def_type;
2454 return info->def_values [prop_index].data;
2456 return NULL;
2458 cindex = mono_metadata_get_constant_index (klass_image, mono_class_get_property_token (property), 0);
2459 if (!cindex)
2460 return NULL;
2462 mono_metadata_decode_row (&klass_image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
2463 *def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
2464 return (const char *)mono_metadata_blob_heap (klass_image, constant_cols [MONO_CONSTANT_VALUE]);
2468 * mono_class_get_event_token:
2470 guint32
2471 mono_class_get_event_token (MonoEvent *event)
2473 MonoClass *klass = event->parent;
2474 int i;
2476 while (klass) {
2477 MonoClassEventInfo *info = mono_class_get_event_info (klass);
2478 if (info) {
2479 for (i = 0; i < info->count; ++i) {
2480 if (&info->events [i] == event)
2481 return mono_metadata_make_token (MONO_TABLE_EVENT, info->first + i + 1);
2484 klass = m_class_get_parent (klass);
2487 g_assert_not_reached ();
2488 return 0;
2491 MonoProperty*
2492 mono_class_get_property_from_name_internal (MonoClass *klass, const char *name)
2494 MONO_REQ_GC_UNSAFE_MODE;
2495 while (klass) {
2496 MonoProperty* p;
2497 gpointer iter = NULL;
2498 while ((p = mono_class_get_properties (klass, &iter))) {
2499 if (! strcmp (name, p->name))
2500 return p;
2502 klass = m_class_get_parent (klass);
2504 return NULL;
2508 * mono_class_get_property_token:
2509 * \param prop MonoProperty to query
2511 * \returns The ECMA token for the specified property.
2513 guint32
2514 mono_class_get_property_token (MonoProperty *prop)
2516 MonoClass *klass = prop->parent;
2517 while (klass) {
2518 MonoProperty* p;
2519 int i = 0;
2520 gpointer iter = NULL;
2521 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
2522 while ((p = mono_class_get_properties (klass, &iter))) {
2523 if (&info->properties [i] == prop)
2524 return mono_metadata_make_token (MONO_TABLE_PROPERTY, info->first + i + 1);
2526 i ++;
2528 klass = m_class_get_parent (klass);
2531 g_assert_not_reached ();
2532 return 0;
2536 * mono_class_name_from_token:
2538 char *
2539 mono_class_name_from_token (MonoImage *image, guint32 type_token)
2541 const char *name, *nspace;
2542 if (image_is_dynamic (image))
2543 return g_strdup_printf ("DynamicType 0x%08x", type_token);
2545 switch (type_token & 0xff000000){
2546 case MONO_TOKEN_TYPE_DEF: {
2547 guint32 cols [MONO_TYPEDEF_SIZE];
2548 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
2549 guint tidx = mono_metadata_token_index (type_token);
2551 if (tidx > tt->rows)
2552 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2554 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
2555 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2556 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2557 if (strlen (nspace) == 0)
2558 return g_strdup_printf ("%s", name);
2559 else
2560 return g_strdup_printf ("%s.%s", nspace, name);
2563 case MONO_TOKEN_TYPE_REF: {
2564 ERROR_DECL (error);
2565 guint32 cols [MONO_TYPEREF_SIZE];
2566 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2567 guint tidx = mono_metadata_token_index (type_token);
2569 if (tidx > t->rows)
2570 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2572 if (!mono_verifier_verify_typeref_row (image, tidx - 1, error)) {
2573 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (error));
2574 mono_error_cleanup (error);
2575 return msg;
2578 mono_metadata_decode_row (t, tidx-1, cols, MONO_TYPEREF_SIZE);
2579 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2580 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2581 if (strlen (nspace) == 0)
2582 return g_strdup_printf ("%s", name);
2583 else
2584 return g_strdup_printf ("%s.%s", nspace, name);
2587 case MONO_TOKEN_TYPE_SPEC:
2588 return g_strdup_printf ("Typespec 0x%08x", type_token);
2589 default:
2590 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2594 static char *
2595 mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
2597 if (image_is_dynamic (image))
2598 return g_strdup_printf ("DynamicAssembly %s", image->name);
2600 switch (type_token & 0xff000000){
2601 case MONO_TOKEN_TYPE_DEF:
2602 if (image->assembly)
2603 return mono_stringify_assembly_name (&image->assembly->aname);
2604 else if (image->assembly_name)
2605 return g_strdup (image->assembly_name);
2606 return g_strdup_printf ("%s", image->name ? image->name : "[Could not resolve assembly name");
2607 case MONO_TOKEN_TYPE_REF: {
2608 ERROR_DECL (error);
2609 MonoAssemblyName aname;
2610 guint32 cols [MONO_TYPEREF_SIZE];
2611 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2612 guint32 idx = mono_metadata_token_index (type_token);
2614 if (idx > t->rows)
2615 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
2617 if (!mono_verifier_verify_typeref_row (image, idx - 1, error)) {
2618 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (error));
2619 mono_error_cleanup (error);
2620 return msg;
2622 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
2624 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
2625 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
2626 case MONO_RESOLUTION_SCOPE_MODULE:
2627 /* FIXME: */
2628 return g_strdup ("");
2629 case MONO_RESOLUTION_SCOPE_MODULEREF:
2630 /* FIXME: */
2631 return g_strdup ("");
2632 case MONO_RESOLUTION_SCOPE_TYPEREF:
2633 /* FIXME: */
2634 return g_strdup ("");
2635 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
2636 mono_assembly_get_assemblyref (image, idx - 1, &aname);
2637 return mono_stringify_assembly_name (&aname);
2638 default:
2639 g_assert_not_reached ();
2641 break;
2643 case MONO_TOKEN_TYPE_SPEC:
2644 /* FIXME: */
2645 return g_strdup ("");
2646 default:
2647 g_assert_not_reached ();
2650 return NULL;
2654 * mono_class_get_full:
2655 * \param image the image where the class resides
2656 * \param type_token the token for the class
2657 * \param context the generic context used to evaluate generic instantiations in
2658 * \deprecated Functions that expose \c MonoGenericContext are going away in mono 4.0
2659 * \returns The \c MonoClass that represents \p type_token in \p image
2661 MonoClass *
2662 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
2664 ERROR_DECL (error);
2665 MonoClass *klass;
2666 klass = mono_class_get_checked (image, type_token, error);
2668 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
2669 klass = mono_class_inflate_generic_class_checked (klass, context, error);
2671 mono_error_assert_ok (error);
2672 return klass;
2676 MonoClass *
2677 mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
2679 MonoClass *klass;
2681 error_init (error);
2682 klass = mono_class_get_checked (image, type_token, error);
2684 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
2685 klass = mono_class_inflate_generic_class_checked (klass, context, error);
2687 return klass;
2690 * mono_class_get_checked:
2691 * \param image the image where the class resides
2692 * \param type_token the token for the class
2693 * \param error error object to return any error
2695 * \returns The MonoClass that represents \p type_token in \p image, or NULL on error.
2697 MonoClass *
2698 mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
2700 MonoClass *klass = NULL;
2702 error_init (error);
2704 if (image_is_dynamic (image)) {
2705 int table = mono_metadata_token_table (type_token);
2707 if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
2708 mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
2709 return NULL;
2711 klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
2712 goto done;
2715 switch (type_token & 0xff000000){
2716 case MONO_TOKEN_TYPE_DEF:
2717 klass = mono_class_create_from_typedef (image, type_token, error);
2718 break;
2719 case MONO_TOKEN_TYPE_REF:
2720 klass = mono_class_from_typeref_checked (image, type_token, error);
2721 break;
2722 case MONO_TOKEN_TYPE_SPEC:
2723 klass = mono_class_create_from_typespec (image, type_token, NULL, error);
2724 break;
2725 default:
2726 mono_error_set_bad_image (error, image, "Unknown type token %x", type_token & 0xff000000);
2729 done:
2730 /* Generic case, should be avoided for when a better error is possible. */
2731 if (!klass && is_ok (error)) {
2732 char *name = mono_class_name_from_token (image, type_token);
2733 char *assembly = mono_assembly_name_from_token (image, type_token);
2734 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);
2737 return klass;
2742 * mono_type_get_checked:
2743 * \param image the image where the type resides
2744 * \param type_token the token for the type
2745 * \param context the generic context used to evaluate generic instantiations in
2746 * \param error Error handling context
2748 * This functions exists to fullfill the fact that sometimes it's desirable to have access to the
2750 * \returns The MonoType that represents \p type_token in \p image
2752 MonoType *
2753 mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
2755 MonoType *type = NULL;
2756 gboolean inflated = FALSE;
2758 error_init (error);
2760 //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
2761 if (image_is_dynamic (image)) {
2762 MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
2763 return_val_if_nok (error, NULL);
2764 return m_class_get_byval_arg (klass);
2767 if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
2768 MonoClass *klass = mono_class_get_checked (image, type_token, error);
2770 if (!klass)
2771 return NULL;
2772 if (m_class_has_failure (klass)) {
2773 mono_error_set_for_class_failure (error, klass);
2774 return NULL;
2776 return m_class_get_byval_arg (klass);
2779 type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
2781 if (!type) {
2782 return NULL;
2785 if (inflated) {
2786 MonoType *tmp = type;
2787 type = m_class_get_byval_arg (mono_class_from_mono_type_internal (type));
2788 /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
2789 * A MonoClass::_byval_arg of a generic type definion has type CLASS.
2790 * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with _byval_arg.
2792 * The long term solution is to chaise this places and make then set MonoType::type correctly.
2793 * */
2794 if (type->type != tmp->type)
2795 type = tmp;
2796 else
2797 mono_metadata_free_type (tmp);
2799 return type;
2803 * mono_class_get:
2804 * \param image image where the class token will be looked up.
2805 * \param type_token a type token from the image
2806 * \returns the \c MonoClass with the given \p type_token on the \p image
2808 MonoClass *
2809 mono_class_get (MonoImage *image, guint32 type_token)
2811 ERROR_DECL (error);
2812 error_init (error);
2813 MonoClass *result = mono_class_get_checked (image, type_token, error);
2814 mono_error_assert_ok (error);
2815 return result;
2819 * mono_image_init_name_cache:
2821 * Initializes the class name cache stored in image->name_cache.
2823 * LOCKING: Acquires the corresponding image lock.
2825 void
2826 mono_image_init_name_cache (MonoImage *image)
2828 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
2829 guint32 cols [MONO_TYPEDEF_SIZE];
2830 const char *name;
2831 const char *nspace;
2832 guint32 i, visib, nspace_index;
2833 GHashTable *name_cache2, *nspace_table, *the_name_cache;
2835 if (image->name_cache)
2836 return;
2838 the_name_cache = g_hash_table_new (g_str_hash, g_str_equal);
2840 if (image_is_dynamic (image)) {
2841 mono_image_lock (image);
2842 if (image->name_cache) {
2843 /* Somebody initialized it before us */
2844 g_hash_table_destroy (the_name_cache);
2845 } else {
2846 mono_atomic_store_release (&image->name_cache, the_name_cache);
2848 mono_image_unlock (image);
2849 return;
2852 /* Temporary hash table to avoid lookups in the nspace_table */
2853 name_cache2 = g_hash_table_new (NULL, NULL);
2855 for (i = 1; i <= t->rows; ++i) {
2856 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
2857 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2859 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
2860 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
2862 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
2863 continue;
2864 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2865 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2867 nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
2868 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
2869 if (!nspace_table) {
2870 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
2871 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
2872 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
2873 nspace_table);
2875 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
2878 /* Load type names from EXPORTEDTYPES table */
2880 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
2881 guint32 cols [MONO_EXP_TYPE_SIZE];
2882 int i;
2884 for (i = 0; i < t->rows; ++i) {
2885 mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
2887 guint32 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
2888 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_EXP_TYPE)
2889 /* Nested type */
2890 continue;
2892 name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
2893 nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
2895 nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
2896 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
2897 if (!nspace_table) {
2898 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
2899 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
2900 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
2901 nspace_table);
2903 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
2907 g_hash_table_destroy (name_cache2);
2909 mono_image_lock (image);
2910 if (image->name_cache) {
2911 /* Somebody initialized it before us */
2912 g_hash_table_destroy (the_name_cache);
2913 } else {
2914 mono_atomic_store_release (&image->name_cache, the_name_cache);
2916 mono_image_unlock (image);
2919 /*FIXME Only dynamic assemblies should allow this operation.*/
2921 * mono_image_add_to_name_cache:
2923 void
2924 mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
2925 const char *name, guint32 index)
2927 GHashTable *nspace_table;
2928 GHashTable *name_cache;
2929 guint32 old_index;
2931 mono_image_init_name_cache (image);
2932 mono_image_lock (image);
2934 name_cache = image->name_cache;
2935 if (!(nspace_table = (GHashTable *)g_hash_table_lookup (name_cache, nspace))) {
2936 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
2937 g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
2940 if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
2941 g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
2943 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
2945 mono_image_unlock (image);
2948 typedef struct {
2949 gconstpointer key;
2950 GSList *values;
2951 } FindAllUserData;
2953 static void
2954 find_all_nocase (gpointer key, gpointer value, gpointer user_data)
2956 char *name = (char*)key;
2957 FindAllUserData *data = (FindAllUserData*)user_data;
2958 if (mono_utf8_strcasecmp (name, (char*)data->key) == 0)
2959 data->values = g_slist_prepend (data->values, value);
2962 typedef struct {
2963 gconstpointer key;
2964 gpointer value;
2965 } FindUserData;
2967 static void
2968 find_nocase (gpointer key, gpointer value, gpointer user_data)
2970 char *name = (char*)key;
2971 FindUserData *data = (FindUserData*)user_data;
2973 if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
2974 data->value = value;
2978 * mono_class_from_name_case:
2979 * \param image The MonoImage where the type is looked up in
2980 * \param name_space the type namespace
2981 * \param name the type short name.
2982 * \deprecated use the mono_class_from_name_case_checked variant instead.
2984 * Obtains a \c MonoClass with a given namespace and a given name which
2985 * is located in the given \c MonoImage. The namespace and name
2986 * lookups are case insensitive.
2988 MonoClass *
2989 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
2991 ERROR_DECL (error);
2992 MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, error);
2993 mono_error_cleanup (error);
2995 return res;
2999 * mono_class_from_name_case_checked:
3000 * \param image The MonoImage where the type is looked up in
3001 * \param name_space the type namespace
3002 * \param name the type short name.
3003 * \param error if
3005 * Obtains a MonoClass with a given namespace and a given name which
3006 * is located in the given MonoImage. The namespace and name
3007 * lookups are case insensitive.
3009 * \returns The MonoClass if the given namespace and name were found, or NULL if it
3010 * was not found. The \p error object will contain information about the problem
3011 * in that case.
3013 MonoClass *
3014 mono_class_from_name_case_checked (MonoImage *image, const char *name_space, const char *name, MonoError *error)
3016 MonoClass *klass;
3017 GHashTable *visited_images;
3019 visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
3021 klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, FALSE, error);
3023 g_hash_table_destroy (visited_images);
3025 return klass;
3028 static MonoClass*
3029 return_nested_in (MonoClass *klass, char *nested, gboolean case_sensitive)
3031 MonoClass *found;
3032 char *s = strchr (nested, '/');
3033 gpointer iter = NULL;
3035 if (s) {
3036 *s = 0;
3037 s++;
3040 while ((found = mono_class_get_nested_types (klass, &iter))) {
3041 const char *name = m_class_get_name (found);
3042 gint strcmp_result;
3043 if (case_sensitive)
3044 strcmp_result = strcmp (name, nested);
3045 else
3046 strcmp_result = mono_utf8_strcasecmp (name, nested);
3048 if (strcmp_result == 0) {
3049 if (s)
3050 return return_nested_in (found, s, case_sensitive);
3051 return found;
3054 return NULL;
3057 static MonoClass*
3058 search_modules (MonoImage *image, const char *name_space, const char *name, gboolean case_sensitive, MonoError *error)
3060 MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
3061 MonoImage *file_image;
3062 MonoClass *klass;
3063 int i;
3065 error_init (error);
3068 * The EXPORTEDTYPES table only contains public types, so have to search the
3069 * modules as well.
3070 * Note: image->modules contains the contents of the MODULEREF table, while
3071 * the real module list is in the FILE table.
3073 for (i = 0; i < file_table->rows; i++) {
3074 guint32 cols [MONO_FILE_SIZE];
3075 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
3076 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
3077 continue;
3079 file_image = mono_image_load_file_for_image_checked (image, i + 1, error);
3080 if (file_image) {
3081 if (case_sensitive)
3082 klass = mono_class_from_name_checked (file_image, name_space, name, error);
3083 else
3084 klass = mono_class_from_name_case_checked (file_image, name_space, name, error);
3086 if (klass || !is_ok (error))
3087 return klass;
3091 return NULL;
3094 static MonoClass *
3095 mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, gboolean case_sensitive, MonoError *error)
3097 GHashTable *nspace_table = NULL;
3098 MonoImage *loaded_image = NULL;
3099 guint32 token = 0;
3100 int i;
3101 MonoClass *klass;
3102 char *nested;
3103 char buf [1024];
3105 error_init (error);
3107 // Checking visited images avoids stack overflows when cyclic references exist.
3108 if (g_hash_table_lookup (visited_images, image))
3109 return NULL;
3111 g_hash_table_insert (visited_images, image, GUINT_TO_POINTER(1));
3113 if ((nested = (char*)strchr (name, '/'))) {
3114 int pos = nested - name;
3115 int len = strlen (name);
3116 if (len > 1023)
3117 return NULL;
3118 memcpy (buf, name, len + 1);
3119 buf [pos] = 0;
3120 nested = buf + pos + 1;
3121 name = buf;
3124 /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */
3125 // The AOT cache in get_class_from_name is case-sensitive, so don't bother with it for case-insensitive lookups
3126 if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0 && case_sensitive) {
3127 gboolean res = get_class_from_name (image, name_space, name, &klass);
3128 if (res) {
3129 if (!klass) {
3130 klass = search_modules (image, name_space, name, case_sensitive, error);
3131 if (!is_ok (error))
3132 return NULL;
3134 if (nested)
3135 return klass ? return_nested_in (klass, nested, case_sensitive) : NULL;
3136 else
3137 return klass;
3141 mono_image_init_name_cache (image);
3142 mono_image_lock (image);
3144 if (case_sensitive) {
3145 nspace_table = (GHashTable *)g_hash_table_lookup (image->name_cache, name_space);
3147 if (nspace_table)
3148 token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
3149 } else {
3150 FindAllUserData all_user_data = { name_space, NULL };
3151 FindUserData user_data = { name, NULL };
3152 GSList *values;
3154 // We're forced to check all matching namespaces, not just the first one found,
3155 // because our desired type could be in any of the ones that match case-insensitively.
3156 g_hash_table_foreach (image->name_cache, find_all_nocase, &all_user_data);
3158 values = all_user_data.values;
3159 while (values && !user_data.value) {
3160 nspace_table = (GHashTable*)values->data;
3161 g_hash_table_foreach (nspace_table, find_nocase, &user_data);
3162 values = values->next;
3165 g_slist_free (all_user_data.values);
3167 if (user_data.value)
3168 token = GPOINTER_TO_UINT (user_data.value);
3171 mono_image_unlock (image);
3173 if (!token && image_is_dynamic (image) && image->modules) {
3174 /* Search modules as well */
3175 for (i = 0; i < image->module_count; ++i) {
3176 MonoImage *module = image->modules [i];
3178 if (case_sensitive)
3179 klass = mono_class_from_name_checked (module, name_space, name, error);
3180 else
3181 klass = mono_class_from_name_case_checked (module, name_space, name, error);
3183 if (klass || !is_ok (error))
3184 return klass;
3188 if (!token) {
3189 klass = search_modules (image, name_space, name, case_sensitive, error);
3190 if (klass || !is_ok (error))
3191 return klass;
3192 return NULL;
3195 if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
3196 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
3197 guint32 cols [MONO_EXP_TYPE_SIZE];
3198 guint32 idx, impl;
3200 idx = mono_metadata_token_index (token);
3202 mono_metadata_decode_row (t, idx - 1, cols, MONO_EXP_TYPE_SIZE);
3204 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
3205 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
3206 loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error);
3207 if (!loaded_image)
3208 return NULL;
3209 klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, case_sensitive, error);
3210 if (nested)
3211 return klass ? return_nested_in (klass, nested, case_sensitive) : NULL;
3212 return klass;
3213 } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
3214 guint32 assembly_idx;
3216 assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
3218 mono_assembly_load_reference (image, assembly_idx - 1);
3219 g_assert (image->references [assembly_idx - 1]);
3220 if (image->references [assembly_idx - 1] == (gpointer)-1)
3221 return NULL;
3222 klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, case_sensitive, error);
3223 if (nested)
3224 return klass ? return_nested_in (klass, nested, case_sensitive) : NULL;
3225 return klass;
3226 } else {
3227 g_assert_not_reached ();
3231 token = MONO_TOKEN_TYPE_DEF | token;
3233 klass = mono_class_get_checked (image, token, error);
3234 if (nested)
3235 return return_nested_in (klass, nested, case_sensitive);
3236 return klass;
3240 * mono_class_from_name_checked:
3241 * \param image The MonoImage where the type is looked up in
3242 * \param name_space the type namespace
3243 * \param name the type short name.
3245 * Obtains a MonoClass with a given namespace and a given name which
3246 * is located in the given MonoImage.
3248 * Works like mono_class_from_name, but error handling is tricky. It can return NULL and have no error
3249 * set if the class was not found or it will return NULL and set the error if there was a loading error.
3251 MonoClass *
3252 mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
3254 MonoClass *klass;
3255 GHashTable *visited_images;
3257 visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
3259 klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, TRUE, error);
3261 g_hash_table_destroy (visited_images);
3263 return klass;
3267 * mono_class_from_name:
3268 * \param image The \c MonoImage where the type is looked up in
3269 * \param name_space the type namespace
3270 * \param name the type short name.
3272 * Obtains a \c MonoClass with a given namespace and a given name which
3273 * is located in the given \c MonoImage.
3275 * To reference nested classes, use the "/" character as a separator.
3276 * For example use \c "Foo/Bar" to reference the class \c Bar that is nested
3277 * inside \c Foo, like this: "class Foo { class Bar {} }".
3279 MonoClass *
3280 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
3282 MonoClass *klass;
3283 MONO_ENTER_GC_UNSAFE;
3284 ERROR_DECL (error);
3286 klass = mono_class_from_name_checked (image, name_space, name, error);
3287 mono_error_cleanup (error); /* FIXME Don't swallow the error */
3288 MONO_EXIT_GC_UNSAFE;
3289 return klass;
3293 * mono_class_load_from_name:
3294 * \param image The MonoImage where the type is looked up in
3295 * \param name_space the type namespace
3296 * \param name the type short name.
3298 * This function works exactly like mono_class_from_name but it will abort if the class is not found.
3299 * This function should be used by the runtime for critical types to which there's no way to recover but crash
3300 * If they are missing. Thing of System.Object or System.String.
3302 MonoClass *
3303 mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
3305 ERROR_DECL (error);
3306 MonoClass *klass;
3308 klass = mono_class_from_name_checked (image, name_space, name, error);
3309 if (!klass)
3310 g_error ("Runtime critical type %s.%s not found", name_space, name);
3311 mono_error_assertf_ok (error, "Could not load runtime critical type %s.%s", name_space, name);
3312 return klass;
3316 * mono_class_try_load_from_name:
3317 * \param image The MonoImage where the type is looked up in
3318 * \param name_space the type namespace
3319 * \param name the type short name.
3321 * This function tries to load a type, returning the class was found or NULL otherwise.
3322 * This function should be used by the runtime when probing for optional types, those that could have being linked out.
3324 * Big design consideration. This function aborts if there was an error loading the type. This prevents us from missing
3325 * a type that we would otherwise assume to be available but was not due some error.
3328 MonoClass*
3329 mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name)
3331 ERROR_DECL (error);
3332 MonoClass *klass;
3334 klass = mono_class_from_name_checked (image, name_space, name, error);
3335 mono_error_assertf_ok (error, "Could not load runtime critical type %s.%s", name_space, name);
3336 return klass;
3339 static gboolean
3340 mono_interface_implements_interface (MonoClass *interface_implementer, MonoClass *interface_implemented)
3342 int i;
3343 ERROR_DECL (error);
3344 mono_class_setup_interfaces (interface_implementer, error);
3345 if (!is_ok (error)) {
3346 mono_error_cleanup (error);
3347 return FALSE;
3349 MonoClass **klass_interfaces = m_class_get_interfaces (interface_implementer);
3350 for (i = 0; i < m_class_get_interface_count (interface_implementer); i++) {
3351 MonoClass *ic = klass_interfaces [i];
3352 if (mono_class_is_ginst (ic))
3353 ic = mono_class_get_generic_type_definition (ic);
3354 if (ic == interface_implemented)
3355 return TRUE;
3357 return FALSE;
3360 gboolean
3361 mono_class_is_subclass_of_internal (MonoClass *klass, MonoClass *klassc,
3362 gboolean check_interfaces)
3364 MONO_REQ_GC_UNSAFE_MODE;
3365 /* FIXME test for interfaces with variant generic arguments */
3366 mono_class_init_internal (klass);
3367 mono_class_init_internal (klassc);
3369 if (check_interfaces && MONO_CLASS_IS_INTERFACE_INTERNAL (klassc) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
3370 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, m_class_get_interface_id (klassc)))
3371 return TRUE;
3372 } else if (check_interfaces && MONO_CLASS_IS_INTERFACE_INTERNAL (klassc) && MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
3373 int i;
3375 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
3376 for (i = 0; i < m_class_get_interface_count (klass); i ++) {
3377 MonoClass *ic = klass_interfaces [i];
3378 if (ic == klassc)
3379 return TRUE;
3381 } else {
3382 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) && mono_class_has_parent (klass, klassc))
3383 return TRUE;
3387 * MS.NET thinks interfaces are a subclass of Object, so we think it as
3388 * well.
3390 if (klassc == mono_defaults.object_class)
3391 return TRUE;
3393 return FALSE;
3396 static gboolean
3397 mono_type_is_generic_argument (MonoType *type)
3399 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
3402 gboolean
3403 mono_class_has_variant_generic_params (MonoClass *klass)
3405 int i;
3406 MonoGenericContainer *container;
3408 if (!mono_class_is_ginst (klass))
3409 return FALSE;
3411 container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
3413 for (i = 0; i < container->type_argc; ++i)
3414 if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
3415 return TRUE;
3417 return FALSE;
3420 static gboolean
3421 mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
3423 if (target == candidate)
3424 return TRUE;
3426 if (check_for_reference_conv &&
3427 mono_type_is_generic_argument (m_class_get_byval_arg (target)) &&
3428 mono_type_is_generic_argument (m_class_get_byval_arg (candidate))) {
3429 MonoGenericParam *gparam = m_class_get_byval_arg (candidate)->data.generic_param;
3430 MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
3432 if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
3433 return FALSE;
3435 if (!mono_class_is_assignable_from_internal (target, candidate))
3436 return FALSE;
3437 return TRUE;
3441 * @container the generic container from the GTD
3442 * @klass: the class to be assigned to
3443 * @oklass: the source class
3445 * Both @klass and @oklass must be instances of the same generic interface.
3447 * Returns: TRUE if @klass can be assigned to a @klass variable
3449 gboolean
3450 mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
3452 int j;
3453 MonoType **klass_argv, **oklass_argv;
3454 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
3455 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
3457 if (klass == oklass)
3458 return TRUE;
3460 /*Viable candidates are instances of the same generic interface*/
3461 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
3462 return FALSE;
3464 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
3465 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
3467 for (j = 0; j < container->type_argc; ++j) {
3468 MonoClass *param1_class = mono_class_from_mono_type_internal (klass_argv [j]);
3469 MonoClass *param2_class = mono_class_from_mono_type_internal (oklass_argv [j]);
3471 if (m_class_is_valuetype (param1_class) != m_class_is_valuetype (param2_class) || (m_class_is_valuetype (param1_class) && param1_class != param2_class))
3472 return FALSE;
3475 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
3476 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
3478 if (param1_class != param2_class) {
3479 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
3480 if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
3481 return FALSE;
3482 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
3483 if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
3484 return FALSE;
3485 } else
3486 return FALSE;
3489 return TRUE;
3492 static gboolean
3493 mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
3495 MonoGenericParam *gparam, *ogparam;
3496 MonoGenericParamInfo *tinfo, *cinfo;
3497 MonoClass **candidate_class;
3498 gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
3499 int tmask, cmask;
3501 if (target == candidate)
3502 return TRUE;
3503 MonoType *target_byval_arg = m_class_get_byval_arg (target);
3504 MonoType *candidate_byval_arg = m_class_get_byval_arg (candidate);
3505 if (target_byval_arg->type != candidate_byval_arg->type)
3506 return FALSE;
3508 gparam = target_byval_arg->data.generic_param;
3509 ogparam = candidate_byval_arg->data.generic_param;
3510 tinfo = mono_generic_param_info (gparam);
3511 cinfo = mono_generic_param_info (ogparam);
3513 class_constraint_satisfied = FALSE;
3514 valuetype_constraint_satisfied = FALSE;
3516 /*candidate must have a super set of target's special constraints*/
3517 tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
3518 cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
3520 if (cinfo->constraints) {
3521 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
3522 MonoClass *cc = *candidate_class;
3523 MonoType *cc_byval_arg = m_class_get_byval_arg (cc);
3525 if (mono_type_is_reference (cc_byval_arg) && !MONO_CLASS_IS_INTERFACE_INTERNAL (cc))
3526 class_constraint_satisfied = TRUE;
3527 else if (!mono_type_is_reference (cc_byval_arg) && !MONO_CLASS_IS_INTERFACE_INTERNAL (cc))
3528 valuetype_constraint_satisfied = TRUE;
3531 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
3532 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
3534 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
3535 return FALSE;
3536 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
3537 return FALSE;
3538 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
3539 valuetype_constraint_satisfied)) {
3540 return FALSE;
3544 /*candidate type constraints must be a superset of target's*/
3545 if (tinfo->constraints) {
3546 MonoClass **target_class;
3547 for (target_class = tinfo->constraints; *target_class; ++target_class) {
3548 MonoClass *tc = *target_class;
3549 MonoType *tc_byval_arg = m_class_get_byval_arg (tc);
3552 * A constraint from @target might inflate into @candidate itself and in that case we don't need
3553 * check it's constraints since it satisfy the constraint by itself.
3555 if (mono_metadata_type_equal (tc_byval_arg, candidate_byval_arg))
3556 continue;
3558 if (!cinfo->constraints)
3559 return FALSE;
3561 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
3562 MonoClass *cc = *candidate_class;
3564 if (mono_class_is_assignable_from_internal (tc, cc))
3565 break;
3568 * This happens when we have the following:
3570 * Bar<K> where K : IFace
3571 * Foo<T, U> where T : U where U : IFace
3572 * ...
3573 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
3576 if (mono_type_is_generic_argument (m_class_get_byval_arg (cc))) {
3577 if (mono_gparam_is_assignable_from (target, cc))
3578 break;
3581 if (!*candidate_class)
3582 return FALSE;
3586 /*candidate itself must have a constraint that satisfy target*/
3587 if (cinfo->constraints) {
3588 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
3589 MonoClass *cc = *candidate_class;
3590 if (mono_class_is_assignable_from_internal (target, cc))
3591 return TRUE;
3594 return FALSE;
3598 * mono_class_is_assignable_from_internal:
3599 * \param klass the class to be assigned to
3600 * \param oklass the source class
3602 * \returns TRUE if an instance of class \p oklass can be assigned to an
3603 * instance of class \p klass
3605 gboolean
3606 mono_class_is_assignable_from_internal (MonoClass *klass, MonoClass *oklass)
3608 gboolean result = FALSE;
3609 ERROR_DECL (error);
3610 mono_class_is_assignable_from_checked (klass, oklass, &result, error);
3611 mono_error_cleanup (error);
3612 return result;
3616 * mono_class_is_assignable_from:
3617 * \param klass the class to be assigned to
3618 * \param oklass the source class
3620 * \returns TRUE if an instance of class \p oklass can be assigned to an
3621 * instance of class \p klass
3623 mono_bool
3624 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
3626 gboolean result;
3627 MONO_ENTER_GC_UNSAFE;
3628 result = mono_class_is_assignable_from_internal (klass, oklass);
3629 MONO_EXIT_GC_UNSAFE;
3630 return result;
3634 * mono_class_is_assignable_from_checked:
3635 * \param klass the class to be assigned to
3636 * \param oklass the source class
3637 * \param result set if there was no error
3638 * \param error set if there was an error
3640 * Sets \p result to TRUE if an instance of class \p oklass can be assigned to
3641 * an instance of class \p klass or FALSE if it cannot. On error, no \p error
3642 * is set and \p result is not valid.
3644 void
3645 mono_class_is_assignable_from_checked (MonoClass *klass, MonoClass *oklass, gboolean *result, MonoError *error)
3647 g_assert (result);
3648 if (klass == oklass) {
3649 *result = TRUE;
3650 return;
3653 MONO_REQ_GC_UNSAFE_MODE;
3654 /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
3655 if (!m_class_is_inited (klass))
3656 mono_class_init_internal (klass);
3658 if (!m_class_is_inited (oklass))
3659 mono_class_init_internal (oklass);
3661 if (mono_class_has_failure (klass)) {
3662 mono_error_set_for_class_failure (error, klass);
3663 *result = FALSE;
3664 return;
3667 if (mono_class_has_failure (oklass)) {
3668 mono_error_set_for_class_failure (error, oklass);
3669 *result = FALSE;
3670 return;
3673 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
3674 MonoType *oklass_byval_arg = m_class_get_byval_arg (oklass);
3676 if (mono_type_is_generic_argument (klass_byval_arg)) {
3677 if (!mono_type_is_generic_argument (oklass_byval_arg)) {
3678 *result = FALSE;
3679 return;
3681 *result = mono_gparam_is_assignable_from (klass, oklass);
3682 return;
3685 /* This can happen if oklass is a tyvar that has a constraint which is another tyvar which in turn
3686 * has a constraint which is a class type:
3688 * class Foo { }
3689 * class G<T1, T2> where T1 : T2 where T2 : Foo { }
3691 * In this case, Foo is assignable from T1.
3693 if (mono_type_is_generic_argument (oklass_byval_arg)) {
3694 MonoGenericParam *gparam = oklass_byval_arg->data.generic_param;
3695 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
3696 int i;
3698 if (constraints) {
3699 for (i = 0; constraints [i]; ++i) {
3700 if (mono_class_is_assignable_from_internal (klass, constraints [i])) {
3701 *result = TRUE;
3702 return;
3707 *result = mono_class_has_parent (oklass, klass);
3708 return;
3711 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
3713 /* interface_offsets might not be set for dynamic classes */
3714 if (mono_class_get_ref_info_handle (oklass) && !m_class_get_interface_bitmap (oklass)) {
3716 * oklass might be a generic type parameter but they have
3717 * interface_offsets set.
3719 gboolean assign_result = mono_reflection_call_is_assignable_to (oklass, klass, error);
3720 return_if_nok (error);
3721 *result = assign_result;
3722 return;
3724 if (!m_class_get_interface_bitmap (oklass)) {
3725 /* Happens with generic instances of not-yet created dynamic types */
3726 *result = FALSE;
3727 return;
3729 if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, m_class_get_interface_id (klass))) {
3730 *result = TRUE;
3731 return;
3734 if (m_class_is_array_special_interface (klass) && m_class_get_rank (oklass) == 1) {
3735 if (mono_class_is_gtd (klass)) {
3736 /* klass is an array special gtd like
3737 * IList`1<>, and oklass is X[] for some X.
3738 * Moreover we know that X isn't !0 (the gparam
3739 * of IList`1) because in that case we would
3740 * have returned TRUE for
3741 * MONO_CLASS_IMPLEMENTS_INTERFACE, above.
3743 *result = FALSE;
3744 return;
3746 // FIXME: IEnumerator`1 should not be an array special interface.
3747 // The correct fix is to make
3748 // ((IEnumerable<U>) (new T[] {...})).GetEnumerator()
3749 // return an IEnumerator<U> (like .NET does) instead of IEnumerator<T>
3750 // and to stop marking IEnumerable`1 as an array_special_interface.
3751 if (mono_class_get_generic_type_definition (klass) == mono_defaults.generic_ienumerator_class) {
3752 *result = FALSE;
3753 return;
3756 //XXX we could offset this by having the cast target computed at JIT time
3757 //XXX we could go even further and emit a wrapper that would do the extra type check
3758 MonoClass *iface_klass = mono_class_from_mono_type_internal (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
3759 MonoClass *obj_klass = m_class_get_cast_class (oklass); //This gets us the cast class of element type of the array
3761 // 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
3762 // We can't apply it for ref types as this would go wrong with arrays - IList<byte[]> would have byte tested
3763 if (!mono_class_is_nullable (iface_klass)) {
3764 if (m_class_is_valuetype (iface_klass))
3765 iface_klass = m_class_get_cast_class (iface_klass);
3767 //array covariant casts only operates on scalar to scalar
3768 //This is so int[] can't be casted to IComparable<int>[]
3769 if (!(m_class_is_valuetype (obj_klass) && !m_class_is_valuetype (iface_klass)) && mono_class_is_assignable_from_internal (iface_klass, obj_klass)) {
3770 *result = TRUE;
3771 return;
3776 if (mono_class_has_variant_generic_params (klass)) {
3777 int i;
3778 mono_class_setup_interfaces (oklass, error);
3779 return_if_nok (error);
3781 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
3782 for (i = 0; i < m_class_get_interface_offsets_count (oklass); ++i) {
3783 MonoClass *iface = m_class_get_interfaces_packed (oklass) [i];
3785 if (mono_class_is_variant_compatible (klass, iface, FALSE)) {
3786 *result = TRUE;
3787 return;
3792 *result = FALSE;
3793 return;
3794 } else if (m_class_is_delegate (klass)) {
3795 if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE)) {
3796 *result = TRUE;
3797 return;
3799 } else if (m_class_get_rank (klass)) {
3800 MonoClass *eclass, *eoclass;
3802 if (m_class_get_rank (oklass) != m_class_get_rank (klass)) {
3803 *result = FALSE;
3804 return;
3807 /* vectors vs. one dimensional arrays */
3808 if (oklass_byval_arg->type != klass_byval_arg->type) {
3809 *result = FALSE;
3810 return;
3813 eclass = m_class_get_cast_class (klass);
3814 eoclass = m_class_get_cast_class (oklass);
3817 * a is b does not imply a[] is b[] when a is a valuetype, and
3818 * b is a reference type.
3821 if (m_class_is_valuetype (eoclass)) {
3822 if ((eclass == mono_defaults.enum_class) ||
3823 (eclass == m_class_get_parent (mono_defaults.enum_class)) ||
3824 (!m_class_is_valuetype (eclass))) {
3825 *result = FALSE;
3826 return;
3831 * a is b does not imply a[] is b[] in the case where b is an interface and
3832 * a is a generic parameter, unless a has an additional class constraint.
3833 * For example (C#):
3834 * ```
3835 * interface I {}
3836 * class G<T> where T : I {}
3837 * class H<U> where U : class, I {}
3838 * public class P {
3839 * public static void Main() {
3840 * var t = typeof(G<>).GetTypeInfo().GenericTypeParameters[0].MakeArrayType();
3841 * var i = typeof(I).MakeArrayType();
3842 * var u = typeof(H<>).GetTypeInfo().GenericTypeParameters[0].MakeArrayType();
3843 * Console.WriteLine("I[] assignable from T[] ? {0}", i.IsAssignableFrom(t));
3844 * Console.WriteLine("I[] assignable from U[] ? {0}", i.IsAssignableFrom(u));
3847 * ```
3848 * This should print:
3849 * I[] assignable from T[] ? False
3850 * I[] assignable from U[] ? True
3853 if (MONO_CLASS_IS_INTERFACE_INTERNAL (eclass)) {
3854 MonoType *eoclass_byval_arg = m_class_get_byval_arg (eoclass);
3855 if (mono_type_is_generic_argument (eoclass_byval_arg)) {
3856 MonoGenericParam *eoparam = eoclass_byval_arg->data.generic_param;
3857 MonoGenericParamInfo *eoinfo = mono_generic_param_info (eoparam);
3858 int eomask = eoinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
3859 // check for class constraint
3860 if ((eomask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0) {
3861 *result = FALSE;
3862 return;
3867 if (mono_class_is_nullable (eclass) ^ mono_class_is_nullable (eoclass)) {
3868 *result = FALSE;
3869 return;
3872 mono_class_is_assignable_from_checked (eclass, eoclass, result, error);
3873 return;
3874 } else if (mono_class_is_nullable (klass)) {
3875 if (mono_class_is_nullable (oklass))
3876 mono_class_is_assignable_from_checked (m_class_get_cast_class (klass), m_class_get_cast_class (oklass), result, error);
3877 else
3878 mono_class_is_assignable_from_checked (m_class_get_cast_class (klass), oklass, result, error);
3879 return;
3880 } else if (klass == mono_defaults.object_class) {
3881 if (m_class_get_class_kind (oklass) == MONO_CLASS_POINTER)
3882 *result = FALSE;
3883 else
3884 *result = TRUE;
3885 return;
3888 *result = mono_class_has_parent (oklass, klass);
3891 /*Check if @oklass is variant compatible with @klass.*/
3892 static gboolean
3893 mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
3895 int j;
3896 MonoType **klass_argv, **oklass_argv;
3897 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
3898 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
3900 /*Viable candidates are instances of the same generic interface*/
3901 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
3902 return FALSE;
3904 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
3905 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
3907 for (j = 0; j < container->type_argc; ++j) {
3908 MonoClass *param1_class = mono_class_from_mono_type_internal (klass_argv [j]);
3909 MonoClass *param2_class = mono_class_from_mono_type_internal (oklass_argv [j]);
3911 if (m_class_is_valuetype (param1_class) != m_class_is_valuetype (param2_class))
3912 return FALSE;
3915 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
3916 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
3918 if (param1_class != param2_class) {
3919 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
3920 if (!mono_class_is_assignable_from_slow (param1_class, param2_class))
3921 return FALSE;
3922 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
3923 if (!mono_class_is_assignable_from_slow (param2_class, param1_class))
3924 return FALSE;
3925 } else
3926 return FALSE;
3929 return TRUE;
3931 /*Check if @candidate implements the interface @target*/
3932 static gboolean
3933 mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
3935 ERROR_DECL (error);
3936 int i;
3937 gboolean is_variant = mono_class_has_variant_generic_params (target);
3939 if (is_variant && MONO_CLASS_IS_INTERFACE_INTERNAL (candidate)) {
3940 if (mono_class_is_variant_compatible_slow (target, candidate))
3941 return TRUE;
3944 do {
3945 if (candidate == target)
3946 return TRUE;
3948 /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
3949 if (image_is_dynamic (m_class_get_image (candidate)) && !m_class_was_typebuilder (candidate)) {
3950 MonoReflectionTypeBuilder *tb = mono_class_get_ref_info_raw (candidate); /* FIXME use handles */
3951 int j;
3952 if (tb && tb->interfaces) {
3953 for (j = mono_array_length_internal (tb->interfaces) - 1; j >= 0; --j) {
3954 MonoReflectionType *iface = mono_array_get_internal (tb->interfaces, MonoReflectionType*, j);
3955 MonoClass *iface_class;
3957 /* we can't realize the type here since it can do pretty much anything. */
3958 if (!iface->type)
3959 continue;
3960 iface_class = mono_class_from_mono_type_internal (iface->type);
3961 if (iface_class == target)
3962 return TRUE;
3963 if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class))
3964 return TRUE;
3965 if (mono_class_implement_interface_slow (target, iface_class))
3966 return TRUE;
3969 } else {
3970 /*setup_interfaces don't mono_class_init_internal anything*/
3971 /*FIXME this doesn't handle primitive type arrays.
3972 ICollection<sbyte> x byte [] won't work because candidate->interfaces, for byte[], won't have IList<sbyte>.
3973 A possible way to fix this would be to move that to setup_interfaces from setup_interface_offsets.
3975 mono_class_setup_interfaces (candidate, error);
3976 if (!is_ok (error)) {
3977 mono_error_cleanup (error);
3978 return FALSE;
3981 int candidate_interface_count = m_class_get_interface_count (candidate);
3982 MonoClass **candidate_interfaces = m_class_get_interfaces (candidate);
3983 for (i = 0; i < candidate_interface_count; ++i) {
3984 if (candidate_interfaces [i] == target)
3985 return TRUE;
3987 if (is_variant && mono_class_is_variant_compatible_slow (target, candidate_interfaces [i]))
3988 return TRUE;
3990 if (mono_class_implement_interface_slow (target, candidate_interfaces [i]))
3991 return TRUE;
3994 candidate = m_class_get_parent (candidate);
3995 } while (candidate);
3997 return FALSE;
4001 * Check if @oklass can be assigned to @klass.
4002 * This function does the same as mono_class_is_assignable_from_internal but is safe to be used from mono_class_init_internal context.
4004 gboolean
4005 mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
4007 if (candidate == target)
4008 return TRUE;
4009 if (target == mono_defaults.object_class)
4010 return TRUE;
4012 if (mono_class_has_parent (candidate, target))
4013 return TRUE;
4015 /*If target is not an interface there is no need to check them.*/
4016 if (MONO_CLASS_IS_INTERFACE_INTERNAL (target))
4017 return mono_class_implement_interface_slow (target, candidate);
4019 if (m_class_is_delegate (target) && mono_class_has_variant_generic_params (target))
4020 return mono_class_is_variant_compatible (target, candidate, FALSE);
4022 if (m_class_get_rank (target)) {
4023 MonoClass *eclass, *eoclass;
4025 if (m_class_get_rank (target) != m_class_get_rank (candidate))
4026 return FALSE;
4028 /* vectors vs. one dimensional arrays */
4029 if (m_class_get_byval_arg (target)->type != m_class_get_byval_arg (candidate)->type)
4030 return FALSE;
4032 eclass = m_class_get_cast_class (target);
4033 eoclass = m_class_get_cast_class (candidate);
4036 * a is b does not imply a[] is b[] when a is a valuetype, and
4037 * b is a reference type.
4040 if (m_class_is_valuetype (eoclass)) {
4041 if ((eclass == mono_defaults.enum_class) ||
4042 (eclass == m_class_get_parent (mono_defaults.enum_class)) ||
4043 (eclass == mono_defaults.object_class))
4044 return FALSE;
4047 return mono_class_is_assignable_from_slow (eclass, eoclass);
4049 /*FIXME properly handle nullables */
4050 /*FIXME properly handle (M)VAR */
4051 return FALSE;
4055 * mono_generic_param_get_base_type:
4057 * Return the base type of the given generic parameter from its constraints.
4059 * Could be another generic parameter, or it could be Object or ValueType.
4061 MonoClass*
4062 mono_generic_param_get_base_type (MonoClass *klass)
4064 MonoType *type = m_class_get_byval_arg (klass);
4065 g_assert (mono_type_is_generic_argument (type));
4067 MonoGenericParam *gparam = type->data.generic_param;
4069 g_assert (gparam->owner && !gparam->owner->is_anonymous);
4071 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
4073 MonoClass *base_class = mono_defaults.object_class;
4075 if (constraints) {
4076 int i;
4077 for (i = 0; constraints [i]; ++i) {
4078 MonoClass *constraint = constraints[i];
4080 if (MONO_CLASS_IS_INTERFACE_INTERNAL (constraint))
4081 continue;
4083 MonoType *constraint_type = m_class_get_byval_arg (constraint);
4084 if (mono_type_is_generic_argument (constraint_type)) {
4085 MonoGenericParam *constraint_param = constraint_type->data.generic_param;
4086 MonoGenericParamInfo *constraint_info = mono_generic_param_info (constraint_param);
4087 if ((constraint_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0 &&
4088 (constraint_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) == 0)
4089 continue;
4092 base_class = constraint;
4097 if (base_class == mono_defaults.object_class)
4099 MonoGenericParamInfo *gparam_info = mono_generic_param_info (gparam);
4100 if ((gparam_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0) {
4101 base_class = mono_class_get_valuetype_class ();
4105 return base_class;
4109 * mono_class_get_cctor:
4110 * \param klass A MonoClass pointer
4112 * \returns The static constructor of \p klass if it exists, NULL otherwise.
4114 MonoMethod*
4115 mono_class_get_cctor (MonoClass *klass)
4117 MonoMethod *result = NULL;
4118 ERROR_DECL (error);
4119 MonoCachedClassInfo cached_info;
4121 if (image_is_dynamic (m_class_get_image (klass))) {
4123 * has_cctor is not set for these classes because mono_class_init_internal () is
4124 * not run for them.
4126 result = mono_class_get_method_from_name_checked (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME, error);
4127 mono_error_assert_msg_ok (error, "Could not lookup class cctor in dynamic image");
4128 return result;
4131 mono_class_init_internal (klass);
4133 if (!m_class_has_cctor (klass))
4134 return result;
4136 if (mono_class_is_ginst (klass) && !m_class_get_methods (klass)) {
4137 result = mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class), error);
4138 mono_error_assert_msg_ok (error, "Could not lookup inflated class cctor"); /* FIXME do proper error handling */
4139 return result;
4142 if (mono_class_get_cached_class_info (klass, &cached_info)) {
4143 result = mono_get_method_checked (m_class_get_image (klass), cached_info.cctor_token, klass, NULL, error);
4144 mono_error_assert_msg_ok (error, "Could not lookup class cctor from cached metadata");
4145 return result;
4148 result = mono_class_get_method_from_name_checked (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME, error);
4149 mono_error_assert_msg_ok (error, "Could not lookup class cctor");
4150 return result;
4154 * mono_class_get_finalizer:
4155 * \param klass: The MonoClass pointer
4157 * \returns The finalizer method of \p klass if it exists, NULL otherwise.
4159 MonoMethod*
4160 mono_class_get_finalizer (MonoClass *klass)
4162 MonoCachedClassInfo cached_info;
4164 if (!m_class_is_inited (klass))
4165 mono_class_init_internal (klass);
4166 if (!mono_class_has_finalizer (klass))
4167 return NULL;
4169 if (mono_class_get_cached_class_info (klass, &cached_info)) {
4170 ERROR_DECL (error);
4171 MonoMethod *result = mono_get_method_checked (cached_info.finalize_image, cached_info.finalize_token, NULL, NULL, error);
4172 mono_error_assert_msg_ok (error, "Could not lookup finalizer from cached metadata");
4173 return result;
4174 }else {
4175 mono_class_setup_vtable (klass);
4176 return m_class_get_vtable (klass) [mono_class_get_object_finalize_slot ()];
4181 * mono_class_needs_cctor_run:
4182 * \param klass the MonoClass pointer
4183 * \param caller a MonoMethod describing the caller
4185 * Determines whenever the class has a static constructor and whenever it
4186 * needs to be called when executing CALLER.
4188 gboolean
4189 mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
4191 MonoMethod *method;
4193 method = mono_class_get_cctor (klass);
4194 if (method)
4195 return (method == caller) ? FALSE : TRUE;
4196 else
4197 return FALSE;
4201 * mono_class_array_element_size:
4202 * \param klass
4204 * \returns The number of bytes an element of type \p klass uses when stored into an array.
4206 gint32
4207 mono_class_array_element_size (MonoClass *klass)
4209 MonoType *type = m_class_get_byval_arg (klass);
4211 handle_enum:
4212 switch (type->type) {
4213 case MONO_TYPE_I1:
4214 case MONO_TYPE_U1:
4215 case MONO_TYPE_BOOLEAN:
4216 return 1;
4217 case MONO_TYPE_I2:
4218 case MONO_TYPE_U2:
4219 case MONO_TYPE_CHAR:
4220 return 2;
4221 case MONO_TYPE_I4:
4222 case MONO_TYPE_U4:
4223 case MONO_TYPE_R4:
4224 return 4;
4225 case MONO_TYPE_I:
4226 case MONO_TYPE_U:
4227 case MONO_TYPE_PTR:
4228 case MONO_TYPE_CLASS:
4229 case MONO_TYPE_STRING:
4230 case MONO_TYPE_OBJECT:
4231 case MONO_TYPE_SZARRAY:
4232 case MONO_TYPE_ARRAY:
4233 return TARGET_SIZEOF_VOID_P;
4234 case MONO_TYPE_I8:
4235 case MONO_TYPE_U8:
4236 case MONO_TYPE_R8:
4237 return 8;
4238 case MONO_TYPE_VALUETYPE:
4239 if (m_class_is_enumtype (type->data.klass)) {
4240 type = mono_class_enum_basetype_internal (type->data.klass);
4241 klass = m_class_get_element_class (klass);
4242 goto handle_enum;
4244 return mono_class_value_size (klass, NULL);
4245 case MONO_TYPE_GENERICINST:
4246 type = m_class_get_byval_arg (type->data.generic_class->container_class);
4247 goto handle_enum;
4248 case MONO_TYPE_VAR:
4249 case MONO_TYPE_MVAR: {
4250 int align;
4252 return mono_type_size (type, &align);
4254 case MONO_TYPE_VOID:
4255 return 0;
4257 default:
4258 g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
4260 return -1;
4264 * mono_array_element_size:
4265 * \param ac pointer to a \c MonoArrayClass
4267 * \returns The size of single array element.
4269 * LOCKING: Acquires the loader lock.
4271 gint32
4272 mono_array_element_size (MonoClass *ac)
4274 g_assert (m_class_get_rank (ac));
4275 if (G_UNLIKELY (!m_class_is_size_inited (ac))) {
4276 mono_class_setup_fields (ac);
4278 return m_class_get_sizes (ac).element_size;
4282 * mono_ldtoken:
4284 gpointer
4285 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
4286 MonoGenericContext *context)
4288 ERROR_DECL (error);
4289 gpointer res = mono_ldtoken_checked (image, token, handle_class, context, error);
4290 mono_error_assert_ok (error);
4291 return res;
4294 gpointer
4295 mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
4296 MonoGenericContext *context, MonoError *error)
4298 error_init (error);
4300 if (image_is_dynamic (image)) {
4301 MonoClass *tmp_handle_class;
4302 gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
4304 mono_error_assert_ok (error);
4305 g_assert (tmp_handle_class);
4306 if (handle_class)
4307 *handle_class = tmp_handle_class;
4309 if (tmp_handle_class == mono_defaults.typehandle_class)
4310 return m_class_get_byval_arg ((MonoClass*)obj);
4311 else
4312 return obj;
4315 switch (token & 0xff000000) {
4316 case MONO_TOKEN_TYPE_DEF:
4317 case MONO_TOKEN_TYPE_REF:
4318 case MONO_TOKEN_TYPE_SPEC: {
4319 MonoType *type;
4320 if (handle_class)
4321 *handle_class = mono_defaults.typehandle_class;
4322 type = mono_type_get_checked (image, token, context, error);
4323 if (!type)
4324 return NULL;
4326 mono_class_init_internal (mono_class_from_mono_type_internal (type));
4327 /* We return a MonoType* as handle */
4328 return type;
4330 case MONO_TOKEN_FIELD_DEF: {
4331 MonoClass *klass;
4332 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
4333 if (!type) {
4334 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
4335 return NULL;
4337 if (handle_class)
4338 *handle_class = mono_defaults.fieldhandle_class;
4339 klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_DEF | type, context, error);
4340 if (!klass)
4341 return NULL;
4343 mono_class_init_internal (klass);
4344 return mono_class_get_field (klass, token);
4346 case MONO_TOKEN_METHOD_DEF:
4347 case MONO_TOKEN_METHOD_SPEC: {
4348 MonoMethod *meth;
4349 meth = mono_get_method_checked (image, token, NULL, context, error);
4350 if (handle_class)
4351 *handle_class = mono_defaults.methodhandle_class;
4352 if (!meth)
4353 return NULL;
4355 return meth;
4357 case MONO_TOKEN_MEMBER_REF: {
4358 guint32 cols [MONO_MEMBERREF_SIZE];
4359 const char *sig;
4360 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE);
4361 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
4362 mono_metadata_decode_blob_size (sig, &sig);
4363 if (*sig == 0x6) { /* it's a field */
4364 MonoClass *klass;
4365 MonoClassField *field;
4366 field = mono_field_from_token_checked (image, token, &klass, context, error);
4367 if (handle_class)
4368 *handle_class = mono_defaults.fieldhandle_class;
4369 return field;
4370 } else {
4371 MonoMethod *meth;
4372 meth = mono_get_method_checked (image, token, NULL, context, error);
4373 if (handle_class)
4374 *handle_class = mono_defaults.methodhandle_class;
4375 return meth;
4378 default:
4379 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
4381 return NULL;
4384 gpointer
4385 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
4387 MonoClass *handle_class;
4388 error_init (error);
4389 return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
4392 gpointer
4393 mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
4395 return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
4398 static MonoGetCachedClassInfo get_cached_class_info = NULL;
4400 void
4401 mono_install_get_cached_class_info (MonoGetCachedClassInfo func)
4403 get_cached_class_info = func;
4406 gboolean
4407 mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
4409 if (!get_cached_class_info)
4410 return FALSE;
4411 else
4412 return get_cached_class_info (klass, res);
4415 void
4416 mono_install_get_class_from_name (MonoGetClassFromName func)
4418 get_class_from_name = func;
4422 * mono_class_get_image:
4424 * Use this method to get the \c MonoImage* where this class came from.
4426 * \returns The image where this class is defined.
4428 MonoImage*
4429 mono_class_get_image (MonoClass *klass)
4431 return m_class_get_image (klass);
4435 * mono_class_get_element_class:
4436 * \param klass the \c MonoClass to act on
4438 * Use this function to get the element class of an array.
4440 * \returns The element class of an array.
4442 MonoClass*
4443 mono_class_get_element_class (MonoClass *klass)
4445 MonoClass *result;
4446 MONO_ENTER_GC_UNSAFE;
4447 result = m_class_get_element_class (klass);
4448 MONO_EXIT_GC_UNSAFE;
4449 return result;
4453 * mono_class_is_valuetype:
4454 * \param klass the \c MonoClass to act on
4456 * Use this method to determine if the provided \c MonoClass* represents a value type,
4457 * or a reference type.
4459 * \returns TRUE if the \c MonoClass represents a \c ValueType, FALSE if it represents a reference type.
4461 gboolean
4462 mono_class_is_valuetype (MonoClass *klass)
4464 gboolean result;
4465 MONO_ENTER_GC_UNSAFE;
4466 result = m_class_is_valuetype (klass);
4467 MONO_EXIT_GC_UNSAFE;
4468 return result;
4472 * mono_class_is_enum:
4473 * \param klass the \c MonoClass to act on
4475 * Use this function to determine if the provided \c MonoClass* represents an enumeration.
4477 * \returns TRUE if the \c MonoClass represents an enumeration.
4479 gboolean
4480 mono_class_is_enum (MonoClass *klass)
4482 gboolean result;
4483 MONO_ENTER_GC_UNSAFE;
4484 result = m_class_is_enumtype (klass);
4485 MONO_EXIT_GC_UNSAFE;
4486 return result;
4490 * mono_class_enum_basetype_internal:
4491 * \param klass the \c MonoClass to act on
4493 * Use this function to get the underlying type for an enumeration value.
4495 * \returns The underlying type representation for an enumeration.
4497 MonoType*
4498 mono_class_enum_basetype_internal (MonoClass *klass)
4500 if (m_class_get_element_class (klass) == klass)
4501 /* SRE or broken types */
4502 return NULL;
4503 return m_class_get_byval_arg (m_class_get_element_class (klass));
4507 * mono_class_enum_basetype:
4508 * \param klass the \c MonoClass to act on
4510 * Use this function to get the underlying type for an enumeration value.
4512 * \returns The underlying type representation for an enumeration.
4514 MonoType*
4515 mono_class_enum_basetype (MonoClass *klass)
4517 MonoType *res;
4518 MONO_ENTER_GC_UNSAFE;
4519 res = mono_class_enum_basetype_internal (klass);
4520 MONO_EXIT_GC_UNSAFE;
4521 return res;
4525 * mono_class_get_parent
4526 * \param klass the \c MonoClass to act on
4528 * \returns The parent class for this class.
4530 MonoClass*
4531 mono_class_get_parent (MonoClass *klass)
4533 MonoClass *result;
4534 MONO_ENTER_GC_UNSAFE;
4535 result = m_class_get_parent (klass);
4536 MONO_EXIT_GC_UNSAFE;
4537 return result;
4541 * mono_class_get_nesting_type:
4542 * \param klass the \c MonoClass to act on
4544 * Use this function to obtain the class that the provided \c MonoClass* is nested on.
4546 * If the return is NULL, this indicates that this class is not nested.
4548 * \returns The container type where this type is nested or NULL if this type is not a nested type.
4550 MonoClass*
4551 mono_class_get_nesting_type (MonoClass *klass)
4553 return m_class_get_nested_in (klass);
4557 * mono_class_get_rank:
4558 * \param klass the MonoClass to act on
4560 * \returns The rank for the array (the number of dimensions).
4563 mono_class_get_rank (MonoClass *klass)
4565 return m_class_get_rank (klass);
4569 * mono_class_get_name
4570 * \param klass the \c MonoClass to act on
4572 * \returns The name of the class.
4574 const char*
4575 mono_class_get_name (MonoClass *klass)
4577 const char *result;
4578 MONO_ENTER_GC_UNSAFE;
4579 result = m_class_get_name (klass);
4580 MONO_EXIT_GC_UNSAFE;
4581 return result;
4585 * mono_class_get_namespace:
4586 * \param klass the \c MonoClass to act on
4588 * \returns The namespace of the class.
4590 const char*
4591 mono_class_get_namespace (MonoClass *klass)
4593 const char *result;
4594 MONO_ENTER_GC_UNSAFE;
4595 result = m_class_get_name_space (klass);
4596 MONO_EXIT_GC_UNSAFE;
4597 return result;
4601 * mono_class_get_type:
4602 * \param klass the \c MonoClass to act on
4604 * This method returns the internal \c MonoType representation for the class.
4606 * \returns The \c MonoType from the class.
4608 MonoType*
4609 mono_class_get_type (MonoClass *klass)
4611 return m_class_get_byval_arg (klass);
4615 * mono_class_get_type_token:
4616 * \param klass the \c MonoClass to act on
4618 * This method returns type token for the class.
4620 * \returns The type token for the class.
4622 guint32
4623 mono_class_get_type_token (MonoClass *klass)
4625 return m_class_get_type_token (klass);
4629 * mono_class_get_byref_type:
4630 * \param klass the \c MonoClass to act on
4634 MonoType*
4635 mono_class_get_byref_type (MonoClass *klass)
4637 return m_class_get_this_arg (klass);
4641 * mono_class_num_fields:
4642 * \param klass the \c MonoClass to act on
4644 * \returns The number of static and instance fields in the class.
4647 mono_class_num_fields (MonoClass *klass)
4649 return mono_class_get_field_count (klass);
4653 * mono_class_num_methods:
4654 * \param klass the \c MonoClass to act on
4656 * \returns The number of methods in the class.
4659 mono_class_num_methods (MonoClass *klass)
4661 return mono_class_get_method_count (klass);
4665 * mono_class_num_properties
4666 * \param klass the \c MonoClass to act on
4668 * \returns The number of properties in the class.
4671 mono_class_num_properties (MonoClass *klass)
4673 mono_class_setup_properties (klass);
4675 return mono_class_get_property_info (klass)->count;
4679 * mono_class_num_events:
4680 * \param klass the \c MonoClass to act on
4682 * \returns The number of events in the class.
4685 mono_class_num_events (MonoClass *klass)
4687 mono_class_setup_events (klass);
4689 return mono_class_get_event_info (klass)->count;
4693 * mono_class_get_fields:
4694 * \param klass the \c MonoClass to act on
4696 * This routine is an iterator routine for retrieving the fields in a class.
4698 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4699 * iterate over all of the elements. When no more values are
4700 * available, the return value is NULL.
4702 * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
4704 MonoClassField*
4705 mono_class_get_fields (MonoClass* klass, gpointer *iter)
4707 MonoClassField *result;
4708 MONO_ENTER_GC_UNSAFE;
4709 result = mono_class_get_fields_internal (klass, iter);
4710 MONO_EXIT_GC_UNSAFE;
4711 return result;
4714 MonoClassField*
4715 mono_class_get_fields_internal (MonoClass *klass, gpointer *iter)
4717 MonoClassField* field;
4718 if (!iter)
4719 return NULL;
4720 if (!*iter) {
4721 mono_class_setup_fields (klass);
4722 if (mono_class_has_failure (klass))
4723 return NULL;
4724 /* start from the first */
4725 if (mono_class_get_field_count (klass)) {
4726 MonoClassField *klass_fields = m_class_get_fields (klass);
4727 *iter = &klass_fields [0];
4728 return &klass_fields [0];
4729 } else {
4730 /* no fields */
4731 return NULL;
4734 field = (MonoClassField *)*iter;
4735 field++;
4736 if (field < &m_class_get_fields (klass) [mono_class_get_field_count (klass)]) {
4737 *iter = field;
4738 return field;
4740 return NULL;
4744 * mono_class_get_methods:
4745 * \param klass the \c MonoClass to act on
4747 * This routine is an iterator routine for retrieving the fields in a class.
4749 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4750 * iterate over all of the elements. When no more values are
4751 * available, the return value is NULL.
4753 * \returns a \c MonoMethod on each iteration or NULL when no more methods are available.
4755 MonoMethod*
4756 mono_class_get_methods (MonoClass* klass, gpointer *iter)
4758 MonoMethod** method;
4759 if (!iter)
4760 return NULL;
4761 if (!*iter) {
4762 mono_class_setup_methods (klass);
4764 MonoMethod **klass_methods = m_class_get_methods (klass);
4766 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
4767 * FIXME we should better report this error to the caller
4769 if (!klass_methods)
4770 return NULL;
4771 /* start from the first */
4772 if (mono_class_get_method_count (klass)) {
4773 *iter = &klass_methods [0];
4774 return klass_methods [0];
4775 } else {
4776 /* no method */
4777 return NULL;
4780 method = (MonoMethod **)*iter;
4781 method++;
4782 if (method < &m_class_get_methods (klass) [mono_class_get_method_count (klass)]) {
4783 *iter = method;
4784 return *method;
4786 return NULL;
4790 * mono_class_get_properties:
4791 * \param klass the \c MonoClass to act on
4793 * This routine is an iterator routine for retrieving the properties in a class.
4795 * You must pass a gpointer that points to zero and is treated as an opaque handle to
4796 * iterate over all of the elements. When no more values are
4797 * available, the return value is NULL.
4799 * Returns: a \c MonoProperty* on each invocation, or NULL when no more are available.
4801 MonoProperty*
4802 mono_class_get_properties (MonoClass* klass, gpointer *iter)
4804 MonoProperty* property;
4805 if (!iter)
4806 return NULL;
4807 if (!*iter) {
4808 mono_class_setup_properties (klass);
4809 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
4810 /* start from the first */
4811 if (info->count) {
4812 *iter = &info->properties [0];
4813 return (MonoProperty *)*iter;
4814 } else {
4815 /* no fields */
4816 return NULL;
4819 property = (MonoProperty *)*iter;
4820 property++;
4821 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
4822 if (property < &info->properties [info->count]) {
4823 *iter = property;
4824 return (MonoProperty *)*iter;
4826 return NULL;
4830 * mono_class_get_events:
4831 * \param klass the \c MonoClass to act on
4833 * This routine is an iterator routine for retrieving the properties in a class.
4835 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4836 * iterate over all of the elements. When no more values are
4837 * available, the return value is NULL.
4839 * \returns a \c MonoEvent* on each invocation, or NULL when no more are available.
4841 MonoEvent*
4842 mono_class_get_events (MonoClass* klass, gpointer *iter)
4844 MonoEvent* event;
4845 if (!iter)
4846 return NULL;
4847 if (!*iter) {
4848 mono_class_setup_events (klass);
4849 MonoClassEventInfo *info = mono_class_get_event_info (klass);
4850 /* start from the first */
4851 if (info->count) {
4852 *iter = &info->events [0];
4853 return (MonoEvent *)*iter;
4854 } else {
4855 /* no fields */
4856 return NULL;
4859 event = (MonoEvent *)*iter;
4860 event++;
4861 MonoClassEventInfo *info = mono_class_get_event_info (klass);
4862 if (event < &info->events [info->count]) {
4863 *iter = event;
4864 return (MonoEvent *)*iter;
4866 return NULL;
4870 * mono_class_get_interfaces
4871 * \param klass the \c MonoClass to act on
4873 * This routine is an iterator routine for retrieving the interfaces implemented by this class.
4875 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4876 * iterate over all of the elements. When no more values are
4877 * available, the return value is NULL.
4879 * \returns a \c MonoClass* on each invocation, or NULL when no more are available.
4881 MonoClass*
4882 mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
4884 ERROR_DECL (error);
4885 MonoClass** iface;
4886 if (!iter)
4887 return NULL;
4888 if (!*iter) {
4889 if (!m_class_is_inited (klass))
4890 mono_class_init_internal (klass);
4891 if (!m_class_is_interfaces_inited (klass)) {
4892 mono_class_setup_interfaces (klass, error);
4893 if (!is_ok (error)) {
4894 mono_error_cleanup (error);
4895 return NULL;
4898 /* start from the first */
4899 if (m_class_get_interface_count (klass)) {
4900 *iter = &m_class_get_interfaces (klass) [0];
4901 return m_class_get_interfaces (klass) [0];
4902 } else {
4903 /* no interface */
4904 return NULL;
4907 iface = (MonoClass **)*iter;
4908 iface++;
4909 if (iface < &m_class_get_interfaces (klass) [m_class_get_interface_count (klass)]) {
4910 *iter = iface;
4911 return *iface;
4913 return NULL;
4917 * mono_class_get_nested_types
4918 * \param klass the \c MonoClass to act on
4920 * This routine is an iterator routine for retrieving the nested types of a class.
4921 * This works only if \p klass is non-generic, or a generic type definition.
4923 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
4924 * iterate over all of the elements. When no more values are
4925 * available, the return value is NULL.
4927 * \returns a \c Monoclass* on each invocation, or NULL when no more are available.
4929 MonoClass*
4930 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
4932 GList *item;
4934 if (!iter)
4935 return NULL;
4936 if (!m_class_is_nested_classes_inited (klass))
4937 mono_class_setup_nested_types (klass);
4939 if (!*iter) {
4940 GList *nested_classes = mono_class_get_nested_classes_property (klass);
4941 /* start from the first */
4942 if (nested_classes) {
4943 *iter = nested_classes;
4944 return (MonoClass *)nested_classes->data;
4945 } else {
4946 /* no nested types */
4947 return NULL;
4950 item = (GList *)*iter;
4951 item = item->next;
4952 if (item) {
4953 *iter = item;
4954 return (MonoClass *)item->data;
4956 return NULL;
4961 * mono_class_is_delegate
4962 * \param klass the \c MonoClass to act on
4964 * \returns TRUE if the \c MonoClass represents a \c System.Delegate.
4966 mono_bool
4967 mono_class_is_delegate (MonoClass *klass)
4969 mono_bool result;
4970 MONO_ENTER_GC_UNSAFE;
4971 result = m_class_is_delegate (klass);
4972 MONO_EXIT_GC_UNSAFE;
4973 return result;
4977 * mono_class_implements_interface
4978 * \param klass The MonoClass to act on
4979 * \param interface The interface to check if \p klass implements.
4981 * \returns TRUE if \p klass implements \p interface.
4983 mono_bool
4984 mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
4986 return mono_class_is_assignable_from_internal (iface, klass);
4989 static mono_bool
4990 class_implements_interface_ignore_generics (MonoClass* klass, MonoClass* iface)
4992 int i;
4993 ERROR_DECL (error);
4994 if (mono_class_is_ginst (iface))
4995 iface = mono_class_get_generic_type_definition (iface);
4996 while (klass != NULL) {
4997 if (mono_class_is_assignable_from_internal (iface, klass))
4998 return TRUE;
4999 mono_class_setup_interfaces (klass, error);
5000 if (!is_ok (error)) {
5001 mono_error_cleanup (error);
5002 return FALSE;
5004 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
5005 for (i = 0; i < m_class_get_interface_count (klass); i++) {
5006 MonoClass *ic = klass_interfaces [i];
5007 if (mono_class_is_ginst (ic))
5008 ic = mono_class_get_generic_type_definition (ic);
5009 if (ic == iface) {
5010 return TRUE;
5013 klass = m_class_get_parent (klass);
5015 return FALSE;
5020 * mono_field_get_name:
5021 * \param field the \c MonoClassField to act on
5023 * \returns The name of the field.
5025 const char*
5026 mono_field_get_name (MonoClassField *field)
5028 return field->name;
5032 * mono_field_get_type_internal:
5033 * \param field the \c MonoClassField to act on
5034 * \returns \c MonoType of the field.
5036 MonoType*
5037 mono_field_get_type_internal (MonoClassField *field)
5039 MonoType *type = field->type;
5040 if (type)
5041 return type;
5043 ERROR_DECL (error);
5044 type = mono_field_get_type_checked (field, error);
5045 if (!is_ok (error)) {
5046 mono_trace_warning (MONO_TRACE_TYPE, "Could not load field's type due to %s", mono_error_get_message (error));
5047 mono_error_cleanup (error);
5049 return type;
5053 * mono_field_get_type:
5054 * \param field the \c MonoClassField to act on
5055 * \returns \c MonoType of the field.
5057 MonoType*
5058 mono_field_get_type (MonoClassField *field)
5060 MonoType *type = field->type;
5061 if (type)
5062 return type;
5064 MONO_ENTER_GC_UNSAFE;
5065 type = mono_field_get_type_internal (field);
5066 MONO_EXIT_GC_UNSAFE;
5067 return type;
5071 * mono_field_get_type_checked:
5072 * \param field the \c MonoClassField to act on
5073 * \param error used to return any error found while retrieving \p field type
5075 * \returns \c MonoType of the field.
5077 MonoType*
5078 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
5080 error_init (error);
5081 MonoType *type = field->type;
5082 if (type)
5083 return type;
5084 mono_field_resolve_type (field, error);
5085 return field->type;
5089 * mono_field_get_parent:
5090 * \param field the \c MonoClassField to act on
5092 * \returns \c MonoClass where the field was defined.
5094 MonoClass*
5095 mono_field_get_parent (MonoClassField *field)
5097 return field->parent;
5101 * mono_field_get_flags;
5102 * \param field the \c MonoClassField to act on
5104 * The metadata flags for a field are encoded using the
5105 * \c FIELD_ATTRIBUTE_* constants. See the \c tabledefs.h file for details.
5107 * \returns The flags for the field.
5109 guint32
5110 mono_field_get_flags (MonoClassField *field)
5112 if (!field->type)
5113 return mono_field_resolve_flags (field);
5114 return field->type->attrs;
5118 * mono_field_get_offset:
5119 * \param field the \c MonoClassField to act on
5121 * \returns The field offset.
5123 guint32
5124 mono_field_get_offset (MonoClassField *field)
5126 mono_class_setup_fields(field->parent);
5127 return field->offset;
5130 static const char *
5131 mono_field_get_rva (MonoClassField *field)
5133 guint32 rva;
5134 int field_index;
5135 MonoClass *klass = field->parent;
5136 MonoFieldDefaultValue *def_values;
5138 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
5140 def_values = mono_class_get_field_def_values (klass);
5141 if (!def_values) {
5142 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
5144 mono_class_set_field_def_values (klass, def_values);
5147 field_index = mono_field_get_index (field);
5149 if (!def_values [field_index].data && !image_is_dynamic (m_class_get_image (klass))) {
5150 int first_field_idx = mono_class_get_first_field_idx (klass);
5151 mono_metadata_field_info (m_class_get_image (field->parent), first_field_idx + field_index, NULL, &rva, NULL);
5152 if (!rva)
5153 g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), m_class_get_name (field->parent));
5154 def_values [field_index].data = mono_image_rva_map (m_class_get_image (field->parent), rva);
5157 return def_values [field_index].data;
5161 * mono_field_get_data:
5162 * \param field the \c MonoClassField to act on
5164 * \returns A pointer to the metadata constant value or to the field
5165 * data if it has an RVA flag.
5167 const char *
5168 mono_field_get_data (MonoClassField *field)
5170 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
5171 MonoTypeEnum def_type;
5173 return mono_class_get_field_default_value (field, &def_type);
5174 } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
5175 return mono_field_get_rva (field);
5176 } else {
5177 return NULL;
5182 * mono_property_get_name:
5183 * \param prop the \c MonoProperty to act on
5184 * \returns The name of the property
5186 const char*
5187 mono_property_get_name (MonoProperty *prop)
5189 return prop->name;
5193 * mono_property_get_set_method
5194 * \param prop the \c MonoProperty to act on.
5195 * \returns The setter method of the property, a \c MonoMethod.
5197 MonoMethod*
5198 mono_property_get_set_method (MonoProperty *prop)
5200 return prop->set;
5204 * mono_property_get_get_method
5205 * \param prop the MonoProperty to act on.
5206 * \returns The getter method of the property (A \c MonoMethod)
5208 MonoMethod*
5209 mono_property_get_get_method (MonoProperty *prop)
5211 return prop->get;
5215 * mono_property_get_parent:
5216 * \param prop the \c MonoProperty to act on.
5217 * \returns The \c MonoClass where the property was defined.
5219 MonoClass*
5220 mono_property_get_parent (MonoProperty *prop)
5222 return prop->parent;
5226 * mono_property_get_flags:
5227 * \param prop the \c MonoProperty to act on.
5229 * The metadata flags for a property are encoded using the
5230 * \c PROPERTY_ATTRIBUTE_* constants. See the \c tabledefs.h file for details.
5232 * \returns The flags for the property.
5234 guint32
5235 mono_property_get_flags (MonoProperty *prop)
5237 return prop->attrs;
5241 * mono_event_get_name:
5242 * \param event the MonoEvent to act on
5243 * \returns The name of the event.
5245 const char*
5246 mono_event_get_name (MonoEvent *event)
5248 return event->name;
5252 * mono_event_get_add_method:
5253 * \param event The \c MonoEvent to act on.
5254 * \returns The \c add method for the event, a \c MonoMethod.
5256 MonoMethod*
5257 mono_event_get_add_method (MonoEvent *event)
5259 return event->add;
5263 * mono_event_get_remove_method:
5264 * \param event The \c MonoEvent to act on.
5265 * \returns The \c remove method for the event, a \c MonoMethod.
5267 MonoMethod*
5268 mono_event_get_remove_method (MonoEvent *event)
5270 return event->remove;
5274 * mono_event_get_raise_method:
5275 * \param event The \c MonoEvent to act on.
5276 * \returns The \c raise method for the event, a \c MonoMethod.
5278 MonoMethod*
5279 mono_event_get_raise_method (MonoEvent *event)
5281 return event->raise;
5285 * mono_event_get_parent:
5286 * \param event the MonoEvent to act on.
5287 * \returns The \c MonoClass where the event is defined.
5289 MonoClass*
5290 mono_event_get_parent (MonoEvent *event)
5292 return event->parent;
5296 * mono_event_get_flags
5297 * \param event the \c MonoEvent to act on.
5299 * The metadata flags for an event are encoded using the
5300 * \c EVENT_* constants. See the \c tabledefs.h file for details.
5302 * \returns The flags for the event.
5304 guint32
5305 mono_event_get_flags (MonoEvent *event)
5307 return event->attrs;
5311 * mono_class_get_method_from_name:
5312 * \param klass where to look for the method
5313 * \param name name of the method
5314 * \param param_count number of parameters. -1 for any number.
5316 * Obtains a \c MonoMethod with a given name and number of parameters.
5317 * It only works if there are no multiple signatures for any given method name.
5319 MonoMethod *
5320 mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_count)
5322 MonoMethod *result;
5323 MONO_ENTER_GC_UNSAFE;
5324 ERROR_DECL (error);
5325 result = mono_class_get_method_from_name_checked (klass, name, param_count, 0, error);
5326 mono_error_cleanup (error);
5327 MONO_EXIT_GC_UNSAFE;
5328 return result;
5331 MonoMethod*
5332 mono_find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
5334 MonoImage *klass_image = m_class_get_image (klass);
5335 MonoMethod *res = NULL;
5336 int i;
5338 /* Search directly in the metadata to avoid calling setup_methods () */
5339 int first_idx = mono_class_get_first_method_idx (klass);
5340 int mcount = mono_class_get_method_count (klass);
5341 for (i = 0; i < mcount; ++i) {
5342 ERROR_DECL (error);
5343 guint32 cols [MONO_METHOD_SIZE];
5344 MonoMethod *method;
5345 MonoMethodSignature *sig;
5347 /* first_idx points into the methodptr table */
5348 mono_metadata_decode_table_row (klass_image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE);
5350 if (!strcmp (mono_metadata_string_heap (klass_image, cols [MONO_METHOD_NAME]), name)) {
5351 method = mono_get_method_checked (klass_image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error);
5352 if (!method) {
5353 mono_error_cleanup (error); /* FIXME don't swallow the error */
5354 continue;
5356 if (param_count == -1) {
5357 res = method;
5358 break;
5360 sig = mono_method_signature_checked (method, error);
5361 if (!sig) {
5362 mono_error_cleanup (error); /* FIXME don't swallow the error */
5363 continue;
5365 if (sig->param_count == param_count) {
5366 res = method;
5367 break;
5372 return res;
5376 * mono_class_get_method_from_name_flags:
5377 * \param klass where to look for the method
5378 * \param name_space name of the method
5379 * \param param_count number of parameters. -1 for any number.
5380 * \param flags flags which must be set in the method
5382 * Obtains a \c MonoMethod with a given name and number of parameters.
5383 * It only works if there are no multiple signatures for any given method name.
5385 MonoMethod *
5386 mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int param_count, int flags)
5388 MonoMethod *method;
5389 MONO_ENTER_GC_UNSAFE;
5390 ERROR_DECL (error);
5391 method = mono_class_get_method_from_name_checked (klass, name, param_count, flags, error);
5392 mono_error_cleanup (error);
5393 MONO_EXIT_GC_UNSAFE;
5394 return method;
5398 * mono_class_get_method_from_name_checked:
5399 * \param klass where to look for the method
5400 * \param name_space name of the method
5401 * \param param_count number of parameters. -1 for any number.
5402 * \param flags flags which must be set in the method
5403 * \param error
5405 * Obtains a \c MonoMethod with a given name and number of parameters.
5406 * It only works if there are no multiple signatures for any given method name.
5408 MonoMethod *
5409 mono_class_get_method_from_name_checked (MonoClass *klass, const char *name,
5410 int param_count, int flags, MonoError *error)
5412 MonoMethod *res = NULL;
5413 int i;
5415 mono_class_init_internal (klass);
5417 if (mono_class_is_ginst (klass) && !m_class_get_methods (klass)) {
5418 res = mono_class_get_method_from_name_checked (mono_class_get_generic_class (klass)->container_class, name, param_count, flags, error);
5420 if (res)
5421 res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), error);
5423 return res;
5426 if (m_class_get_methods (klass) || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
5427 mono_class_setup_methods (klass);
5429 We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
5430 See mono/tests/array_load_exception.il
5431 FIXME we should better report this error to the caller
5433 MonoMethod **klass_methods = m_class_get_methods (klass);
5434 if (!klass_methods)
5435 return NULL;
5436 int mcount = mono_class_get_method_count (klass);
5437 for (i = 0; i < mcount; ++i) {
5438 MonoMethod *method = klass_methods [i];
5440 if (method->name[0] == name [0] &&
5441 !strcmp (name, method->name) &&
5442 (param_count == -1 || mono_method_signature_internal (method)->param_count == param_count) &&
5443 ((method->flags & flags) == flags)) {
5444 res = method;
5445 break;
5449 else {
5450 res = mono_find_method_in_metadata (klass, name, param_count, flags);
5453 return res;
5456 gboolean
5457 mono_class_has_failure (const MonoClass *klass)
5459 g_assert (klass != NULL);
5460 return m_class_has_failure ((MonoClass*)klass) != 0;
5465 * mono_class_set_type_load_failure:
5466 * \param klass class in which the failure was detected
5467 * \param fmt \c printf -style error message string.
5469 * Collect detected failure informaion in the class for later processing.
5470 * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class()
5471 * Note that only the first failure is kept.
5473 * LOCKING: Acquires the loader lock.
5475 * \returns FALSE if a failure was already set on the class, or TRUE otherwise.
5477 gboolean
5478 mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
5480 ERROR_DECL (prepare_error);
5481 va_list args;
5483 if (mono_class_has_failure (klass))
5484 return FALSE;
5486 va_start (args, fmt);
5487 mono_error_vset_type_load_class (prepare_error, klass, fmt, args);
5488 va_end (args);
5490 MonoErrorBoxed *box = mono_error_box (prepare_error, m_class_get_image (klass));
5491 mono_error_cleanup (prepare_error);
5492 return mono_class_set_failure (klass, box);
5496 * mono_class_get_exception_for_failure:
5497 * \param klass class in which the failure was detected
5499 * \returns a constructed MonoException than the caller can then throw
5500 * using mono_raise_exception - or NULL if no failure is present (or
5501 * doesn't result in an exception).
5503 MonoException*
5504 mono_class_get_exception_for_failure (MonoClass *klass)
5506 if (!mono_class_has_failure (klass))
5507 return NULL;
5508 ERROR_DECL (unboxed_error);
5509 mono_error_set_for_class_failure (unboxed_error, klass);
5510 return mono_error_convert_to_exception (unboxed_error);
5513 static gboolean
5514 is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
5516 outer_klass = mono_class_get_generic_type_definition (outer_klass);
5517 inner_klass = mono_class_get_generic_type_definition (inner_klass);
5518 do {
5519 if (outer_klass == inner_klass)
5520 return TRUE;
5521 inner_klass = m_class_get_nested_in (inner_klass);
5522 } while (inner_klass);
5523 return FALSE;
5526 MonoClass *
5527 mono_class_get_generic_type_definition (MonoClass *klass)
5529 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
5530 return gklass ? gklass->container_class : klass;
5534 * Check if @klass is a subtype of @parent ignoring generic instantiations.
5536 * Generic instantiations are ignored for all super types of @klass.
5538 * Visibility checks ignoring generic instantiations.
5540 * Class implementing interface visibility checks ignore generic instantiations
5542 gboolean
5543 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
5545 int i;
5546 klass = mono_class_get_generic_type_definition (klass);
5547 parent = mono_class_get_generic_type_definition (parent);
5548 mono_class_setup_supertypes (klass);
5550 for (i = 0; i < m_class_get_idepth (klass); ++i) {
5551 if (parent == mono_class_get_generic_type_definition (m_class_get_supertypes (klass) [i]))
5552 return TRUE;
5555 if (MONO_CLASS_IS_INTERFACE_INTERNAL (parent) && class_implements_interface_ignore_generics (klass, parent))
5556 return TRUE;
5558 return FALSE;
5561 * Subtype can only access parent members with family protection if the site object
5562 * is subclass of Subtype. For example:
5563 * class A { protected int x; }
5564 * class B : A {
5565 * void valid_access () {
5566 * B b;
5567 * b.x = 0;
5569 * void invalid_access () {
5570 * A a;
5571 * a.x = 0;
5574 * */
5575 static gboolean
5576 is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
5578 if (MONO_CLASS_IS_INTERFACE_INTERNAL (member_klass) && !MONO_CLASS_IS_INTERFACE_INTERNAL (access_klass)) {
5579 /* Can happen with default interface methods */
5580 if (!class_implements_interface_ignore_generics (access_klass, member_klass))
5581 return FALSE;
5582 } else if (member_klass != access_klass && MONO_CLASS_IS_INTERFACE_INTERNAL (member_klass) && MONO_CLASS_IS_INTERFACE_INTERNAL (access_klass)) {
5583 /* Can happen with default interface methods */
5584 if (!mono_interface_implements_interface (access_klass, member_klass))
5585 return FALSE;
5586 } else {
5587 if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
5588 return FALSE;
5591 if (context_klass == NULL)
5592 return TRUE;
5593 /*if access_klass is not member_klass context_klass must be type compat*/
5594 if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
5595 return FALSE;
5596 return TRUE;
5599 static gboolean
5600 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
5602 GSList *tmp;
5603 if (accessing == accessed)
5604 return TRUE;
5605 if (!accessed || !accessing)
5606 return FALSE;
5608 /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
5609 * anywhere so untrusted friends are not safe to access platform's code internals */
5610 if (mono_security_core_clr_enabled ()) {
5611 if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
5612 return FALSE;
5615 mono_assembly_load_friends (accessed);
5616 for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
5617 MonoAssemblyName *friend_ = (MonoAssemblyName *)tmp->data;
5618 /* Be conservative with checks */
5619 if (!friend_->name)
5620 continue;
5621 if (g_ascii_strcasecmp (accessing->aname.name, friend_->name))
5622 continue;
5623 if (friend_->public_key_token [0]) {
5624 if (!accessing->aname.public_key_token [0])
5625 continue;
5626 if (!mono_public_tokens_are_equal (friend_->public_key_token, accessing->aname.public_key_token))
5627 continue;
5629 return TRUE;
5631 return FALSE;
5635 * If klass is a generic type or if it is derived from a generic type, return the
5636 * MonoClass of the generic definition
5637 * Returns NULL if not found
5639 static MonoClass*
5640 get_generic_definition_class (MonoClass *klass)
5642 while (klass) {
5643 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
5644 if (gklass && gklass->container_class)
5645 return gklass->container_class;
5646 klass = m_class_get_parent (klass);
5648 return NULL;
5651 static gboolean
5652 can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
5654 int i;
5655 for (i = 0; i < ginst->type_argc; ++i) {
5656 MonoType *type = ginst->type_argv[i];
5657 switch (type->type) {
5658 case MONO_TYPE_SZARRAY:
5659 if (!can_access_type (access_klass, type->data.klass))
5660 return FALSE;
5661 break;
5662 case MONO_TYPE_ARRAY:
5663 if (!can_access_type (access_klass, type->data.array->eklass))
5664 return FALSE;
5665 break;
5666 case MONO_TYPE_PTR:
5667 if (!can_access_type (access_klass, mono_class_from_mono_type_internal (type->data.type)))
5668 return FALSE;
5669 break;
5670 case MONO_TYPE_CLASS:
5671 case MONO_TYPE_VALUETYPE:
5672 case MONO_TYPE_GENERICINST:
5673 if (!can_access_type (access_klass, mono_class_from_mono_type_internal (type)))
5674 return FALSE;
5675 default:
5676 break;
5679 return TRUE;
5682 static gboolean
5683 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
5685 int access_level;
5687 if (access_klass == member_klass)
5688 return TRUE;
5690 MonoAssembly *access_klass_assembly = m_class_get_image (access_klass)->assembly;
5691 MonoAssembly *member_klass_assembly = m_class_get_image (member_klass)->assembly;
5693 if (access_klass_assembly && m_class_get_image (access_klass)->assembly->corlib_internal)
5694 return TRUE;
5696 if (m_class_get_element_class (access_klass) && !m_class_is_enumtype (access_klass)) {
5697 access_klass = m_class_get_element_class (access_klass);
5698 access_klass_assembly = m_class_get_image (access_klass)->assembly;
5701 if (m_class_get_element_class (member_klass) && !m_class_is_enumtype (member_klass)) {
5702 member_klass = m_class_get_element_class (member_klass);
5703 member_klass_assembly = m_class_get_image (member_klass)->assembly;
5706 access_level = mono_class_get_flags (member_klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
5708 if (mono_type_is_generic_argument (m_class_get_byval_arg (member_klass)))
5709 return TRUE;
5711 if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst))
5712 return FALSE;
5714 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)))
5715 return TRUE;
5717 /*Non nested type with nested visibility. We just fail it.*/
5718 if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && m_class_get_nested_in (member_klass) == NULL)
5719 return FALSE;
5721 MonoClass *member_klass_nested_in = m_class_get_nested_in (member_klass);
5722 switch (access_level) {
5723 case TYPE_ATTRIBUTE_NOT_PUBLIC:
5724 return can_access_internals (access_klass_assembly, member_klass_assembly);
5726 case TYPE_ATTRIBUTE_PUBLIC:
5727 return TRUE;
5729 case TYPE_ATTRIBUTE_NESTED_PUBLIC:
5730 return member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
5732 case TYPE_ATTRIBUTE_NESTED_PRIVATE:
5733 return is_nesting_type (member_klass, access_klass) && member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
5735 case TYPE_ATTRIBUTE_NESTED_FAMILY:
5736 return mono_class_has_parent_and_ignore_generics (access_klass, m_class_get_nested_in (member_klass));
5738 case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
5739 return can_access_internals (access_klass_assembly, member_klass_assembly) && member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
5741 case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
5742 return can_access_internals (access_klass_assembly, m_class_get_image (member_klass_nested_in)->assembly) &&
5743 mono_class_has_parent_and_ignore_generics (access_klass, member_klass_nested_in);
5745 case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
5746 return can_access_internals (access_klass_assembly, m_class_get_image (member_klass_nested_in)->assembly) ||
5747 mono_class_has_parent_and_ignore_generics (access_klass, member_klass_nested_in);
5749 return FALSE;
5752 /* FIXME: check visibility of type, too */
5753 static gboolean
5754 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
5756 MonoClass *member_generic_def;
5757 MonoAssembly *access_klass_assembly = m_class_get_image (access_klass)->assembly;
5758 if (access_klass_assembly && access_klass_assembly->corlib_internal)
5759 return TRUE;
5761 MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass);
5762 if (((access_gklass && access_gklass->container_class) ||
5763 mono_class_is_gtd (access_klass)) &&
5764 (member_generic_def = get_generic_definition_class (member_klass))) {
5765 MonoClass *access_container;
5767 if (mono_class_is_gtd (access_klass))
5768 access_container = access_klass;
5769 else
5770 access_container = access_gklass->container_class;
5772 if (can_access_member (access_container, member_generic_def, context_klass, access_level))
5773 return TRUE;
5776 MonoImage *member_klass_image = m_class_get_image (member_klass);
5777 /* Partition I 8.5.3.2 */
5778 /* the access level values are the same for fields and methods */
5779 switch (access_level) {
5780 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
5781 /* same compilation unit */
5782 return m_class_get_image (access_klass) == member_klass_image;
5783 case FIELD_ATTRIBUTE_PRIVATE:
5784 return access_klass == member_klass;
5785 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
5786 if (is_valid_family_access (access_klass, member_klass, context_klass) &&
5787 can_access_internals (access_klass_assembly, member_klass_image->assembly))
5788 return TRUE;
5789 return FALSE;
5790 case FIELD_ATTRIBUTE_ASSEMBLY:
5791 return can_access_internals (access_klass_assembly, member_klass_image->assembly);
5792 case FIELD_ATTRIBUTE_FAMILY:
5793 if (is_valid_family_access (access_klass, member_klass, context_klass))
5794 return TRUE;
5795 return FALSE;
5796 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
5797 if (is_valid_family_access (access_klass, member_klass, context_klass))
5798 return TRUE;
5799 return can_access_internals (access_klass_assembly, member_klass_image->assembly);
5800 case FIELD_ATTRIBUTE_PUBLIC:
5801 return TRUE;
5803 return FALSE;
5807 * mono_method_can_access_field:
5808 * \param method Method that will attempt to access the field
5809 * \param field the field to access
5811 * Used to determine if a method is allowed to access the specified field.
5813 * \returns TRUE if the given \p method is allowed to access the \p field while following
5814 * the accessibility rules of the CLI.
5816 gboolean
5817 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
5819 /* FIXME: check all overlapping fields */
5820 int can = can_access_member (method->klass, field->parent, NULL, mono_field_get_type_internal (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5821 if (!can) {
5822 MonoClass *nested = m_class_get_nested_in (method->klass);
5823 while (nested) {
5824 can = can_access_member (nested, field->parent, NULL, mono_field_get_type_internal (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5825 if (can)
5826 return TRUE;
5827 nested = m_class_get_nested_in (nested);
5830 return can;
5833 static MonoMethod*
5834 mono_method_get_method_definition (MonoMethod *method)
5836 while (method->is_inflated)
5837 method = ((MonoMethodInflated*)method)->declaring;
5838 return method;
5842 * mono_method_can_access_method:
5843 * \param method Method that will attempt to access the other method
5844 * \param called the method that we want to probe for accessibility.
5846 * Used to determine if the \p method is allowed to access the specified \p called method.
5848 * \returns TRUE if the given \p method is allowed to invoke the \p called while following
5849 * the accessibility rules of the CLI.
5851 gboolean
5852 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
5854 method = mono_method_get_method_definition (method);
5855 called = mono_method_get_method_definition (called);
5856 return mono_method_can_access_method_full (method, called, NULL);
5860 * mono_method_can_access_method_full:
5861 * @method: The caller method
5862 * @called: The called method
5863 * @context_klass: The static type on stack of the owner @called object used
5865 * This function must be used with instance calls, as they have more strict family accessibility.
5866 * It can be used with static methods, but context_klass should be NULL.
5868 * Returns: TRUE if caller have proper visibility and acessibility to @called
5870 gboolean
5871 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
5873 /* Wrappers are except from access checks */
5874 if (method->wrapper_type != MONO_WRAPPER_NONE || called->wrapper_type != MONO_WRAPPER_NONE)
5875 return TRUE;
5877 MonoClass *access_class = method->klass;
5878 MonoClass *member_class = called->klass;
5879 int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
5880 if (!can) {
5881 MonoClass *nested = m_class_get_nested_in (access_class);
5882 while (nested) {
5883 can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
5884 if (can)
5885 break;
5886 nested = m_class_get_nested_in (nested);
5890 if (!can)
5891 return FALSE;
5893 can = can_access_type (access_class, member_class);
5894 if (!can) {
5895 MonoClass *nested = m_class_get_nested_in (access_class);
5896 while (nested) {
5897 can = can_access_type (nested, member_class);
5898 if (can)
5899 break;
5900 nested = m_class_get_nested_in (nested);
5904 if (!can)
5905 return FALSE;
5907 if (called->is_inflated) {
5908 MonoMethodInflated * infl = (MonoMethodInflated*)called;
5909 if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
5910 return FALSE;
5913 return TRUE;
5918 * mono_method_can_access_field_full:
5919 * @method: The caller method
5920 * @field: The accessed field
5921 * @context_klass: The static type on stack of the owner @field object used
5923 * This function must be used with instance fields, as they have more strict family accessibility.
5924 * It can be used with static fields, but context_klass should be NULL.
5926 * Returns: TRUE if caller have proper visibility and acessibility to @field
5928 gboolean
5929 mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
5931 MonoClass *access_class = method->klass;
5932 MonoClass *member_class = field->parent;
5933 /* FIXME: check all overlapping fields */
5934 int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5935 if (!can) {
5936 MonoClass *nested = m_class_get_nested_in (access_class);
5937 while (nested) {
5938 can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
5939 if (can)
5940 break;
5941 nested = m_class_get_nested_in (nested);
5945 if (!can)
5946 return FALSE;
5948 can = can_access_type (access_class, member_class);
5949 if (!can) {
5950 MonoClass *nested = m_class_get_nested_in (access_class);
5951 while (nested) {
5952 can = can_access_type (nested, member_class);
5953 if (can)
5954 break;
5955 nested = m_class_get_nested_in (nested);
5959 if (!can)
5960 return FALSE;
5961 return TRUE;
5965 * mono_class_can_access_class:
5966 * @source_class: The source class
5967 * @target_class: The accessed class
5969 * This function returns is @target_class is visible to @source_class
5971 * Returns: TRUE if source have proper visibility and acessibility to target
5973 gboolean
5974 mono_class_can_access_class (MonoClass *source_class, MonoClass *target_class)
5976 return can_access_type (source_class, target_class);
5980 * mono_type_is_valid_enum_basetype:
5981 * \param type The MonoType to check
5982 * \returns TRUE if the type can be used as the basetype of an enum
5984 gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
5985 switch (type->type) {
5986 case MONO_TYPE_I1:
5987 case MONO_TYPE_U1:
5988 case MONO_TYPE_BOOLEAN:
5989 case MONO_TYPE_I2:
5990 case MONO_TYPE_U2:
5991 case MONO_TYPE_CHAR:
5992 case MONO_TYPE_I4:
5993 case MONO_TYPE_U4:
5994 case MONO_TYPE_I8:
5995 case MONO_TYPE_U8:
5996 case MONO_TYPE_I:
5997 case MONO_TYPE_U:
5998 #if ENABLE_NETCORE
5999 case MONO_TYPE_R8:
6000 case MONO_TYPE_R4:
6001 #endif
6002 return TRUE;
6003 default:
6004 return FALSE;
6009 * mono_class_is_valid_enum:
6010 * \param klass An enum class to be validated
6012 * This method verify the required properties an enum should have.
6014 * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
6015 * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
6016 * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
6018 * \returns TRUE if the informed enum class is valid
6020 gboolean
6021 mono_class_is_valid_enum (MonoClass *klass)
6023 MonoClassField * field;
6024 gpointer iter = NULL;
6025 gboolean found_base_field = FALSE;
6027 g_assert (m_class_is_enumtype (klass));
6028 MonoClass *klass_parent = m_class_get_parent (klass);
6029 /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
6030 if (!klass_parent || strcmp (m_class_get_name (klass_parent), "Enum") || strcmp (m_class_get_name_space (klass_parent), "System") ) {
6031 return FALSE;
6034 if (!mono_class_is_auto_layout (klass))
6035 return FALSE;
6037 while ((field = mono_class_get_fields_internal (klass, &iter))) {
6038 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
6039 if (found_base_field)
6040 return FALSE;
6041 found_base_field = TRUE;
6042 if (!mono_type_is_valid_enum_basetype (field->type))
6043 return FALSE;
6047 if (!found_base_field)
6048 return FALSE;
6050 if (mono_class_get_method_count (klass) > 0)
6051 return FALSE;
6053 return TRUE;
6056 gboolean
6057 mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
6059 return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst;
6062 void
6063 mono_field_resolve_type (MonoClassField *field, MonoError *error)
6065 MonoClass *klass = field->parent;
6066 MonoImage *image = m_class_get_image (klass);
6067 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
6068 MonoType *ftype;
6069 int field_idx = field - m_class_get_fields (klass);
6071 error_init (error);
6073 if (gtd) {
6074 MonoClassField *gfield = &m_class_get_fields (gtd) [field_idx];
6075 MonoType *gtype = mono_field_get_type_checked (gfield, error);
6076 if (!is_ok (error)) {
6077 char *full_name = mono_type_get_full_name (gtd);
6078 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));
6079 g_free (full_name);
6082 ftype = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
6083 if (!is_ok (error)) {
6084 char *full_name = mono_type_get_full_name (klass);
6085 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));
6086 g_free (full_name);
6088 } else {
6089 const char *sig;
6090 guint32 cols [MONO_FIELD_SIZE];
6091 MonoGenericContainer *container = NULL;
6092 int idx = mono_class_get_first_field_idx (klass) + field_idx;
6094 /*FIXME, in theory we do not lazy load SRE fields*/
6095 g_assert (!image_is_dynamic (image));
6097 if (mono_class_is_gtd (klass)) {
6098 container = mono_class_get_generic_container (klass);
6099 } else if (gtd) {
6100 container = mono_class_get_generic_container (gtd);
6101 g_assert (container);
6104 /* first_field_idx and idx points into the fieldptr table */
6105 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
6107 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], error)) {
6108 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
6109 return;
6112 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
6114 mono_metadata_decode_value (sig, &sig);
6115 /* FIELD signature == 0x06 */
6116 g_assert (*sig == 0x06);
6118 ftype = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
6119 if (!ftype) {
6120 char *full_name = mono_type_get_full_name (klass);
6121 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));
6122 g_free (full_name);
6125 mono_memory_barrier ();
6126 field->type = ftype;
6129 static guint32
6130 mono_field_resolve_flags (MonoClassField *field)
6132 MonoClass *klass = field->parent;
6133 MonoImage *image = m_class_get_image (klass);
6134 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
6135 int field_idx = field - m_class_get_fields (klass);
6137 if (gtd) {
6138 MonoClassField *gfield = &m_class_get_fields (gtd) [field_idx];
6139 return mono_field_get_flags (gfield);
6140 } else {
6141 int idx = mono_class_get_first_field_idx (klass) + field_idx;
6143 /*FIXME, in theory we do not lazy load SRE fields*/
6144 g_assert (!image_is_dynamic (image));
6146 return mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_FLAGS);
6151 * mono_class_get_fields_lazy:
6152 * \param klass the MonoClass to act on
6154 * This routine is an iterator routine for retrieving the fields in a class.
6155 * Only minimal information about fields are loaded. Accessors must be used
6156 * for all MonoClassField returned.
6158 * You must pass a gpointer that points to zero and is treated as an opaque handle to
6159 * iterate over all of the elements. When no more values are
6160 * available, the return value is NULL.
6162 * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
6164 MonoClassField*
6165 mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
6167 MonoClassField* field;
6168 if (!iter)
6169 return NULL;
6170 if (!*iter) {
6171 mono_class_setup_basic_field_info (klass);
6172 MonoClassField *klass_fields = m_class_get_fields (klass);
6173 if (!klass_fields)
6174 return NULL;
6175 /* start from the first */
6176 if (mono_class_get_field_count (klass)) {
6177 *iter = &klass_fields [0];
6178 return (MonoClassField *)*iter;
6179 } else {
6180 /* no fields */
6181 return NULL;
6184 field = (MonoClassField *)*iter;
6185 field++;
6186 if (field < &m_class_get_fields (klass) [mono_class_get_field_count (klass)]) {
6187 *iter = field;
6188 return (MonoClassField *)*iter;
6190 return NULL;
6193 char*
6194 mono_class_full_name (MonoClass *klass)
6196 return mono_type_full_name (m_class_get_byval_arg (klass));
6199 /* Declare all shared lazy type lookup functions */
6200 GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, "System.Runtime.InteropServices", "SafeHandle")
6203 * mono_method_get_base_method:
6204 * \param method a method
6205 * \param definition if true, get the definition
6206 * \param error set on failure
6208 * Given a virtual method associated with a subclass, return the corresponding
6209 * method from an ancestor. If \p definition is FALSE, returns the method in the
6210 * superclass of the given method. If \p definition is TRUE, return the method
6211 * in the ancestor class where it was first declared. The type arguments will
6212 * be inflated in the ancestor classes. If the method is not associated with a
6213 * class, or isn't virtual, returns the method itself. On failure returns NULL
6214 * and sets \p error.
6216 MonoMethod*
6217 mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error)
6219 MonoClass *klass, *parent;
6220 MonoGenericContext *generic_inst = NULL;
6221 MonoMethod *result = NULL;
6222 int slot;
6224 if (method->klass == NULL)
6225 return method;
6227 if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
6228 MONO_CLASS_IS_INTERFACE_INTERNAL (method->klass) ||
6229 method->flags & METHOD_ATTRIBUTE_NEW_SLOT)
6230 return method;
6232 slot = mono_method_get_vtable_slot (method);
6233 if (slot == -1)
6234 return method;
6236 klass = method->klass;
6237 if (mono_class_is_ginst (klass)) {
6238 generic_inst = mono_class_get_context (klass);
6239 klass = mono_class_get_generic_class (klass)->container_class;
6242 retry:
6243 if (definition) {
6244 /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */
6245 for (parent = m_class_get_parent (klass); parent != NULL; parent = m_class_get_parent (parent)) {
6246 /* on entry, klass is either a plain old non-generic class and generic_inst == NULL
6247 or klass is the generic container class and generic_inst is the instantiation.
6249 when we go to the parent, if the parent is an open constructed type, we need to
6250 replace the type parameters by the definitions from the generic_inst, and then take it
6251 apart again into the klass and the generic_inst.
6253 For cases like this:
6254 class C<T> : B<T, int> {
6255 public override void Foo () { ... }
6257 class B<U,V> : A<HashMap<U,V>> {
6258 public override void Foo () { ... }
6260 class A<X> {
6261 public virtual void Foo () { ... }
6264 if at each iteration the parent isn't open, we can skip inflating it. if at some
6265 iteration the parent isn't generic (after possible inflation), we set generic_inst to
6266 NULL;
6268 MonoGenericContext *parent_inst = NULL;
6269 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (parent))) {
6270 parent = mono_class_inflate_generic_class_checked (parent, generic_inst, error);
6271 return_val_if_nok (error, NULL);
6273 if (mono_class_is_ginst (parent)) {
6274 parent_inst = mono_class_get_context (parent);
6275 parent = mono_class_get_generic_class (parent)->container_class;
6278 mono_class_setup_vtable (parent);
6279 if (m_class_get_vtable_size (parent) <= slot)
6280 break;
6281 klass = parent;
6282 generic_inst = parent_inst;
6284 } else {
6285 klass = m_class_get_parent (klass);
6286 if (!klass)
6287 return method;
6288 if (mono_class_is_open_constructed_type (m_class_get_byval_arg (klass))) {
6289 klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
6290 return_val_if_nok (error, NULL);
6292 generic_inst = NULL;
6294 if (mono_class_is_ginst (klass)) {
6295 generic_inst = mono_class_get_context (klass);
6296 klass = mono_class_get_generic_class (klass)->container_class;
6301 if (generic_inst) {
6302 klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
6303 return_val_if_nok (error, NULL);
6306 if (klass == method->klass)
6307 return method;
6309 /*This is possible if definition == FALSE.
6310 * Do it here to be really sure we don't read invalid memory.
6312 if (slot >= m_class_get_vtable_size (klass))
6313 return method;
6315 mono_class_setup_vtable (klass);
6317 result = m_class_get_vtable (klass) [slot];
6318 if (result == NULL) {
6319 /* It is an abstract method */
6320 gboolean found = FALSE;
6321 gpointer iter = NULL;
6322 while ((result = mono_class_get_methods (klass, &iter))) {
6323 if (result->slot == slot) {
6324 found = TRUE;
6325 break;
6328 /* found might be FALSE if we looked in an abstract class
6329 * that doesn't override an abstract method of its
6330 * parent:
6331 * abstract class Base {
6332 * public abstract void Foo ();
6334 * abstract class Derived : Base { }
6335 * class Child : Derived {
6336 * public override void Foo () { }
6339 * if m was Child.Foo and we ask for the base method,
6340 * then we get here with klass == Derived and found == FALSE
6342 /* but it shouldn't be the case that if we're looking
6343 * for the definition and didn't find a result; the
6344 * loop above should've taken us as far as we could
6345 * go! */
6346 g_assert (!(definition && !found));
6347 if (!found)
6348 goto retry;
6351 g_assert (result != NULL);
6352 return result;