[utils] Explicitly check if the system has mincore instead of relying on mmap been...
[mono-project.git] / mono / metadata / class.c
blob4fa47c798707605d8548e65337561c794d6f60c5
1 /*
2 * class.c: Class management for the Mono runtime
4 * Author:
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
11 #include <config.h>
12 #ifdef HAVE_ALLOCA_H
13 #include <alloca.h>
14 #endif
15 #include <glib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <mono/metadata/image.h>
20 #include <mono/metadata/assembly.h>
21 #include <mono/metadata/metadata.h>
22 #include <mono/metadata/metadata-internals.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/tokentype.h>
26 #include <mono/metadata/class-internals.h>
27 #include <mono/metadata/object.h>
28 #include <mono/metadata/appdomain.h>
29 #include <mono/metadata/mono-endian.h>
30 #include <mono/metadata/debug-helpers.h>
31 #include <mono/metadata/reflection.h>
32 #include <mono/metadata/exception.h>
33 #include <mono/metadata/security-manager.h>
34 #include <mono/metadata/security-core-clr.h>
35 #include <mono/metadata/attrdefs.h>
36 #include <mono/metadata/gc-internal.h>
37 #include <mono/metadata/verify-internals.h>
38 #include <mono/metadata/mono-debug.h>
39 #include <mono/utils/mono-counters.h>
40 #include <mono/utils/mono-string.h>
41 #include <mono/utils/mono-error-internals.h>
42 #include <mono/utils/mono-logger-internal.h>
43 #include <mono/utils/mono-memory-model.h>
44 #include <mono/utils/atomic.h>
45 #include <mono/utils/bsearch.h>
47 MonoStats mono_stats;
49 gboolean mono_print_vtable = FALSE;
51 /* Statistics */
52 guint32 inflated_classes, inflated_classes_size, inflated_methods_size;
53 guint32 classes_size, class_ext_size;
55 /* Low level lock which protects data structures in this module */
56 static mono_mutex_t classes_mutex;
58 /* Function supplied by the runtime to find classes by name using information from the AOT file */
59 static MonoGetClassFromName get_class_from_name = NULL;
61 static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error);
62 static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res);
63 static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
64 static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
65 static int generic_array_methods (MonoClass *class);
66 static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos);
68 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
69 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
70 static void mono_field_resolve_type (MonoClassField *field, MonoError *error);
71 static guint32 mono_field_resolve_flags (MonoClassField *field);
72 static void mono_class_setup_vtable_full (MonoClass *class, GList *in_setup);
73 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
76 We use gclass recording to allow recursive system f types to be referenced by a parent.
78 Given the following type hierarchy:
80 class TextBox : TextBoxBase<TextBox> {}
81 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
82 class TextInput<T> : Input<T> where T: TextInput<T> {}
83 class Input<T> {}
85 The runtime tries to load TextBoxBase<>.
86 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
87 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
88 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
90 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
91 at this point, iow, both are registered in the type map and both and a NULL parent. This means
92 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
94 To fix that what we do is to record all generic instantes created while resolving the parent of
95 any generic type definition and, after resolved, correct the parent field if needed.
98 static int record_gclass_instantiation;
99 static GSList *gclass_recorded_list;
100 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
102 static inline void
103 classes_lock (void)
105 mono_locks_acquire (&classes_mutex, ClassesLock);
108 static inline void
109 classes_unlock (void)
111 mono_locks_release (&classes_mutex, ClassesLock);
115 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
117 static void
118 enable_gclass_recording (void)
120 ++record_gclass_instantiation;
124 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
126 static void
127 disable_gclass_recording (gclass_record_func func, void *user_data)
129 GSList **head = &gclass_recorded_list;
131 g_assert (record_gclass_instantiation > 0);
132 --record_gclass_instantiation;
134 while (*head) {
135 GSList *node = *head;
136 if (func ((MonoClass*)node->data, user_data)) {
137 *head = node->next;
138 g_slist_free_1 (node);
139 } else {
140 head = &node->next;
144 /* We automatically discard all recorded gclasses when disabled. */
145 if (!record_gclass_instantiation && gclass_recorded_list) {
146 g_slist_free (gclass_recorded_list);
147 gclass_recorded_list = NULL;
152 * mono_class_from_typeref:
153 * @image: a MonoImage
154 * @type_token: a TypeRef token
156 * Creates the MonoClass* structure representing the type defined by
157 * the typeref token valid inside @image.
158 * Returns: the MonoClass* representing the typeref token, NULL ifcould
159 * not be loaded.
161 MonoClass *
162 mono_class_from_typeref (MonoImage *image, guint32 type_token)
164 MonoError error;
165 MonoClass *class = mono_class_from_typeref_checked (image, type_token, &error);
166 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
167 return class;
170 MonoClass *
171 mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
173 guint32 cols [MONO_TYPEREF_SIZE];
174 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
175 guint32 idx;
176 const char *name, *nspace;
177 MonoClass *res = NULL;
178 MonoImage *module;
180 mono_error_init (error);
182 if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
183 return NULL;
185 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
187 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
188 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
190 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
191 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
192 case MONO_RESOLUTION_SCOPE_MODULE:
194 LAMESPEC The spec says that a null module resolution scope should go through the exported type table.
195 This is not the observed behavior of existing implementations.
196 The defacto behavior is that it's just a typedef in disguise.
198 /* a typedef in disguise */
199 res = mono_class_from_name (image, nspace, name); /*FIXME proper error handling*/
200 goto done;
202 case MONO_RESOLUTION_SCOPE_MODULEREF:
203 module = mono_image_load_module (image, idx);
204 if (module)
205 res = mono_class_from_name (module, nspace, name); /*FIXME proper error handling*/
206 goto done;
208 case MONO_RESOLUTION_SCOPE_TYPEREF: {
209 MonoClass *enclosing;
210 GList *tmp;
212 if (idx == mono_metadata_token_index (type_token)) {
213 mono_error_set_bad_image (error, image, "Image with self-referencing typeref token %08x.", type_token);
214 return NULL;
217 enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
218 if (!mono_error_ok (error))
219 return NULL;
221 if (enclosing->nested_classes_inited && enclosing->ext) {
222 /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
223 for (tmp = enclosing->ext->nested_classes; tmp; tmp = tmp->next) {
224 res = tmp->data;
225 if (strcmp (res->name, name) == 0)
226 return res;
228 } else {
229 /* Don't call mono_class_init as we might've been called by it recursively */
230 int i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, 1);
231 while (i) {
232 guint32 class_nested = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, MONO_NESTED_CLASS_NESTED);
233 guint32 string_offset = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
234 const char *nname = mono_metadata_string_heap (enclosing->image, string_offset);
236 if (strcmp (nname, name) == 0)
237 return mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, error);
239 i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1);
242 g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
243 goto done;
245 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
246 break;
249 if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
250 mono_error_set_bad_image (error, image, "Image with invalid assemblyref token %08x.", idx);
251 return NULL;
254 if (!image->references || !image->references [idx - 1])
255 mono_assembly_load_reference (image, idx - 1);
256 g_assert (image->references [idx - 1]);
258 /* If the assembly did not load, register this as a type load exception */
259 if (image->references [idx - 1] == REFERENCE_MISSING){
260 MonoAssemblyName aname;
261 char *human_name;
263 mono_assembly_get_assemblyref (image, idx - 1, &aname);
264 human_name = mono_stringify_assembly_name (&aname);
265 mono_error_set_assembly_load_simple (error, human_name, image->assembly ? image->assembly->ref_only : FALSE);
266 return NULL;
269 res = mono_class_from_name (image->references [idx - 1]->image, nspace, name);
271 done:
272 /* Generic case, should be avoided for when a better error is possible. */
273 if (!res && mono_error_ok (error)) {
274 char *name = mono_class_name_from_token (image, type_token);
275 char *assembly = mono_assembly_name_from_token (image, type_token);
276 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
278 return res;
282 static void *
283 mono_image_memdup (MonoImage *image, void *data, guint size)
285 void *res = mono_image_alloc (image, size);
286 memcpy (res, data, size);
287 return res;
290 /* Copy everything mono_metadata_free_array free. */
291 MonoArrayType *
292 mono_dup_array_type (MonoImage *image, MonoArrayType *a)
294 if (image) {
295 a = mono_image_memdup (image, a, sizeof (MonoArrayType));
296 if (a->sizes)
297 a->sizes = mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
298 if (a->lobounds)
299 a->lobounds = mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
300 } else {
301 a = g_memdup (a, sizeof (MonoArrayType));
302 if (a->sizes)
303 a->sizes = g_memdup (a->sizes, a->numsizes * sizeof (int));
304 if (a->lobounds)
305 a->lobounds = g_memdup (a->lobounds, a->numlobounds * sizeof (int));
307 return a;
310 /* Copy everything mono_metadata_free_method_signature free. */
311 MonoMethodSignature*
312 mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
314 int i;
316 sig = mono_metadata_signature_dup_full (image, sig);
318 sig->ret = mono_metadata_type_dup (image, sig->ret);
319 for (i = 0; i < sig->param_count; ++i)
320 sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
322 return sig;
325 static void
326 _mono_type_get_assembly_name (MonoClass *klass, GString *str)
328 MonoAssembly *ta = klass->image->assembly;
329 char *name;
331 name = mono_stringify_assembly_name (&ta->aname);
332 g_string_append_printf (str, ", %s", name);
333 g_free (name);
336 static inline void
337 mono_type_name_check_byref (MonoType *type, GString *str)
339 if (type->byref)
340 g_string_append_c (str, '&');
343 static void
344 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
345 MonoTypeNameFormat format)
347 MonoClass *klass;
349 switch (type->type) {
350 case MONO_TYPE_ARRAY: {
351 int i, rank = type->data.array->rank;
352 MonoTypeNameFormat nested_format;
354 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
355 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
357 mono_type_get_name_recurse (
358 &type->data.array->eklass->byval_arg, str, FALSE, nested_format);
359 g_string_append_c (str, '[');
360 if (rank == 1)
361 g_string_append_c (str, '*');
362 for (i = 1; i < rank; i++)
363 g_string_append_c (str, ',');
364 g_string_append_c (str, ']');
366 mono_type_name_check_byref (type, str);
368 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
369 _mono_type_get_assembly_name (type->data.array->eklass, str);
370 break;
372 case MONO_TYPE_SZARRAY: {
373 MonoTypeNameFormat nested_format;
375 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
376 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
378 mono_type_get_name_recurse (
379 &type->data.klass->byval_arg, str, FALSE, nested_format);
380 g_string_append (str, "[]");
382 mono_type_name_check_byref (type, str);
384 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
385 _mono_type_get_assembly_name (type->data.klass, str);
386 break;
388 case MONO_TYPE_PTR: {
389 MonoTypeNameFormat nested_format;
391 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
392 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
394 mono_type_get_name_recurse (
395 type->data.type, str, FALSE, nested_format);
396 g_string_append_c (str, '*');
398 mono_type_name_check_byref (type, str);
400 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
401 _mono_type_get_assembly_name (mono_class_from_mono_type (type->data.type), str);
402 break;
404 case MONO_TYPE_VAR:
405 case MONO_TYPE_MVAR:
406 if (!mono_generic_param_info (type->data.generic_param))
407 g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
408 else
409 g_string_append (str, mono_generic_param_info (type->data.generic_param)->name);
411 mono_type_name_check_byref (type, str);
413 break;
414 default:
415 klass = mono_class_from_mono_type (type);
416 if (klass->nested_in) {
417 mono_type_get_name_recurse (
418 &klass->nested_in->byval_arg, str, TRUE, format);
419 if (format == MONO_TYPE_NAME_FORMAT_IL)
420 g_string_append_c (str, '.');
421 else
422 g_string_append_c (str, '+');
423 } else if (*klass->name_space) {
424 g_string_append (str, klass->name_space);
425 g_string_append_c (str, '.');
427 if (format == MONO_TYPE_NAME_FORMAT_IL) {
428 char *s = strchr (klass->name, '`');
429 int len = s ? s - klass->name : strlen (klass->name);
431 g_string_append_len (str, klass->name, len);
432 } else
433 g_string_append (str, klass->name);
434 if (is_recursed)
435 break;
436 if (klass->generic_class) {
437 MonoGenericClass *gclass = klass->generic_class;
438 MonoGenericInst *inst = gclass->context.class_inst;
439 MonoTypeNameFormat nested_format;
440 int i;
442 nested_format = format == MONO_TYPE_NAME_FORMAT_FULL_NAME ?
443 MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format;
445 if (format == MONO_TYPE_NAME_FORMAT_IL)
446 g_string_append_c (str, '<');
447 else
448 g_string_append_c (str, '[');
449 for (i = 0; i < inst->type_argc; i++) {
450 MonoType *t = inst->type_argv [i];
452 if (i)
453 g_string_append_c (str, ',');
454 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
455 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
456 g_string_append_c (str, '[');
457 mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
458 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
459 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
460 g_string_append_c (str, ']');
462 if (format == MONO_TYPE_NAME_FORMAT_IL)
463 g_string_append_c (str, '>');
464 else
465 g_string_append_c (str, ']');
466 } else if (klass->generic_container &&
467 (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
468 (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
469 int i;
471 if (format == MONO_TYPE_NAME_FORMAT_IL)
472 g_string_append_c (str, '<');
473 else
474 g_string_append_c (str, '[');
475 for (i = 0; i < klass->generic_container->type_argc; i++) {
476 if (i)
477 g_string_append_c (str, ',');
478 g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name);
480 if (format == MONO_TYPE_NAME_FORMAT_IL)
481 g_string_append_c (str, '>');
482 else
483 g_string_append_c (str, ']');
486 mono_type_name_check_byref (type, str);
488 if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
489 (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
490 _mono_type_get_assembly_name (klass, str);
491 break;
496 * mono_type_get_name_full:
497 * @type: a type
498 * @format: the format for the return string.
501 * Returns: the string representation in a number of formats:
503 * if format is MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
504 * returned in the formatrequired by System.Reflection, this is the
505 * inverse of mono_reflection_parse_type ().
507 * if format is MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
508 * be used by the IL assembler.
510 * if format is MONO_TYPE_NAME_FORMAT_FULL_NAME
512 * if format is MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
514 char*
515 mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
517 GString* result;
519 result = g_string_new ("");
521 mono_type_get_name_recurse (type, result, FALSE, format);
523 return g_string_free (result, FALSE);
527 * mono_type_get_full_name:
528 * @class: a class
530 * Returns: the string representation for type as required by System.Reflection.
531 * The inverse of mono_reflection_parse_type ().
533 char *
534 mono_type_get_full_name (MonoClass *class)
536 return mono_type_get_name_full (mono_class_get_type (class), MONO_TYPE_NAME_FORMAT_REFLECTION);
540 * mono_type_get_name:
541 * @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 * @type: a type
555 * Returns: the MonoType for the underlying integer type if @type
556 * is an enum and byref is false, otherwise the type itself.
558 MonoType*
559 mono_type_get_underlying_type (MonoType *type)
561 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype && !type->byref)
562 return mono_class_enum_basetype (type->data.klass);
563 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype && !type->byref)
564 return mono_class_enum_basetype (type->data.generic_class->container_class);
565 return type;
569 * mono_class_is_open_constructed_type:
570 * @type: a type
572 * Returns TRUE if type represents a generics open constructed type.
573 * IOW, not all type parameters required for the instantiation have
574 * been provided or it's a generic type definition.
576 * An open constructed type means it's a non realizable type. Not to
577 * be mixed up with an abstract type - we can't cast or dispatch to
578 * an open type, for example.
580 gboolean
581 mono_class_is_open_constructed_type (MonoType *t)
583 switch (t->type) {
584 case MONO_TYPE_VAR:
585 case MONO_TYPE_MVAR:
586 return TRUE;
587 case MONO_TYPE_SZARRAY:
588 return mono_class_is_open_constructed_type (&t->data.klass->byval_arg);
589 case MONO_TYPE_ARRAY:
590 return mono_class_is_open_constructed_type (&t->data.array->eklass->byval_arg);
591 case MONO_TYPE_PTR:
592 return mono_class_is_open_constructed_type (t->data.type);
593 case MONO_TYPE_GENERICINST:
594 return t->data.generic_class->context.class_inst->is_open;
595 case MONO_TYPE_CLASS:
596 case MONO_TYPE_VALUETYPE:
597 return t->data.klass->generic_container != NULL;
598 default:
599 return FALSE;
604 This is a simple function to catch the most common bad instances of generic types.
605 Specially those that might lead to further failures in the runtime.
607 static gboolean
608 is_valid_generic_argument (MonoType *type)
610 switch (type->type) {
611 case MONO_TYPE_VOID:
612 //case MONO_TYPE_TYPEDBYREF:
613 return FALSE;
615 return TRUE;
618 static MonoType*
619 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
621 mono_error_init (error);
623 switch (type->type) {
624 case MONO_TYPE_MVAR: {
625 MonoType *nt;
626 int num = mono_type_get_generic_param_num (type);
627 MonoGenericInst *inst = context->method_inst;
628 if (!inst || !inst->type_argv)
629 return NULL;
630 if (num >= inst->type_argc) {
631 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
632 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
633 num, info ? info->name : "", inst->type_argc);
634 return NULL;
637 if (!is_valid_generic_argument (inst->type_argv [num])) {
638 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
639 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
640 num, info ? info->name : "", inst->type_argv [num]->type);
641 return NULL;
644 * Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
645 * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
646 * ->byref and ->attrs from @type are propagated to the returned type.
648 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
649 nt->byref = type->byref;
650 nt->attrs = type->attrs;
651 return nt;
653 case MONO_TYPE_VAR: {
654 MonoType *nt;
655 int num = mono_type_get_generic_param_num (type);
656 MonoGenericInst *inst = context->class_inst;
657 if (!inst)
658 return NULL;
659 if (num >= inst->type_argc) {
660 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
661 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
662 num, info ? info->name : "", inst->type_argc);
663 return NULL;
665 if (!is_valid_generic_argument (inst->type_argv [num])) {
666 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
667 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
668 num, info ? info->name : "", inst->type_argv [num]->type);
669 return NULL;
671 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
672 nt->byref = type->byref;
673 nt->attrs = type->attrs;
674 return nt;
676 case MONO_TYPE_SZARRAY: {
677 MonoClass *eclass = type->data.klass;
678 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
679 if (!inflated || !mono_error_ok (error))
680 return NULL;
681 nt = mono_metadata_type_dup (image, type);
682 nt->data.klass = mono_class_from_mono_type (inflated);
683 mono_metadata_free_type (inflated);
684 return nt;
686 case MONO_TYPE_ARRAY: {
687 MonoClass *eclass = type->data.array->eklass;
688 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
689 if (!inflated || !mono_error_ok (error))
690 return NULL;
691 nt = mono_metadata_type_dup (image, type);
692 nt->data.array->eklass = mono_class_from_mono_type (inflated);
693 mono_metadata_free_type (inflated);
694 return nt;
696 case MONO_TYPE_GENERICINST: {
697 MonoGenericClass *gclass = type->data.generic_class;
698 MonoGenericInst *inst;
699 MonoType *nt;
700 if (!gclass->context.class_inst->is_open)
701 return NULL;
703 inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
704 if (!mono_error_ok (error))
705 return NULL;
706 if (inst != gclass->context.class_inst)
707 gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
709 if (gclass == type->data.generic_class)
710 return NULL;
712 nt = mono_metadata_type_dup (image, type);
713 nt->data.generic_class = gclass;
714 return nt;
716 case MONO_TYPE_CLASS:
717 case MONO_TYPE_VALUETYPE: {
718 MonoClass *klass = type->data.klass;
719 MonoGenericContainer *container = klass->generic_container;
720 MonoGenericInst *inst;
721 MonoGenericClass *gclass = NULL;
722 MonoType *nt;
724 if (!container)
725 return NULL;
727 /* We can't use context->class_inst directly, since it can have more elements */
728 inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
729 if (!mono_error_ok (error))
730 return NULL;
731 if (inst == container->context.class_inst)
732 return NULL;
734 gclass = mono_metadata_lookup_generic_class (klass, inst, image_is_dynamic (klass->image));
736 nt = mono_metadata_type_dup (image, type);
737 nt->type = MONO_TYPE_GENERICINST;
738 nt->data.generic_class = gclass;
739 return nt;
741 default:
742 return NULL;
744 return NULL;
747 MonoGenericContext *
748 mono_generic_class_get_context (MonoGenericClass *gclass)
750 return &gclass->context;
753 MonoGenericContext *
754 mono_class_get_context (MonoClass *class)
756 return class->generic_class ? mono_generic_class_get_context (class->generic_class) : NULL;
760 * mono_class_get_generic_container:
762 * Return the generic container of KLASS which should be a generic type definition.
764 MonoGenericContainer*
765 mono_class_get_generic_container (MonoClass *klass)
767 g_assert (klass->is_generic);
769 return klass->generic_container;
773 * mono_class_get_generic_class:
775 * Return the MonoGenericClass of KLASS, which should be a generic instance.
777 MonoGenericClass*
778 mono_class_get_generic_class (MonoClass *klass)
780 g_assert (klass->is_inflated);
782 return klass->generic_class;
786 * mono_class_inflate_generic_type_with_mempool:
787 * @mempool: a mempool
788 * @type: a type
789 * @context: a generics context
790 * @error: error context
792 * The same as mono_class_inflate_generic_type, but allocates the MonoType
793 * from mempool if it is non-NULL. If it is NULL, the MonoType is
794 * allocated on the heap and is owned by the caller.
795 * The returned type can potentially be the same as TYPE, so it should not be
796 * modified by the caller, and it should be freed using mono_metadata_free_type ().
798 MonoType*
799 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
801 MonoType *inflated = NULL;
802 mono_error_init (error);
804 if (context)
805 inflated = inflate_generic_type (image, type, context, error);
806 if (!mono_error_ok (error))
807 return NULL;
809 if (!inflated) {
810 MonoType *shared = mono_metadata_get_shared_type (type);
812 if (shared) {
813 return shared;
814 } else {
815 return mono_metadata_type_dup (image, type);
819 mono_stats.inflated_type_count++;
820 return inflated;
824 * mono_class_inflate_generic_type:
825 * @type: a type
826 * @context: a generics context
828 * If @type is a generic type and @context is not NULL, instantiate it using the
829 * generics context @context.
831 * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
832 * on the heap and is owned by the caller. Returns NULL on error.
834 * @deprecated Please use mono_class_inflate_generic_type_checked instead
836 MonoType*
837 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
839 MonoError error;
840 MonoType *result;
841 result = mono_class_inflate_generic_type_checked (type, context, &error);
843 if (!mono_error_ok (&error)) {
844 mono_error_cleanup (&error);
845 return NULL;
847 return result;
851 * mono_class_inflate_generic_type:
852 * @type: a type
853 * @context: a generics context
854 * @error: error context to use
856 * If @type is a generic type and @context is not NULL, instantiate it using the
857 * generics context @context.
859 * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
860 * on the heap and is owned by the caller.
862 MonoType*
863 mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
865 return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
869 * mono_class_inflate_generic_type_no_copy:
871 * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
872 * was done.
874 static MonoType*
875 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
877 MonoType *inflated = NULL;
879 mono_error_init (error);
880 if (context) {
881 inflated = inflate_generic_type (image, type, context, error);
882 if (!mono_error_ok (error))
883 return NULL;
886 if (!inflated)
887 return type;
889 mono_stats.inflated_type_count++;
890 return inflated;
893 MonoClass*
894 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
896 MonoClass *res;
897 MonoType *inflated;
899 inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, error);
900 if (!mono_error_ok (error))
901 return NULL;
903 res = mono_class_from_mono_type (inflated);
904 mono_metadata_free_type (inflated);
906 return res;
909 * mono_class_inflate_generic_class:
911 * Inflate the class GKLASS with CONTEXT.
913 MonoClass*
914 mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context)
916 MonoError error;
917 MonoClass *res;
919 res = mono_class_inflate_generic_class_checked (gklass, context, &error);
920 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
922 return res;
927 static MonoGenericContext
928 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
930 MonoGenericInst *class_inst = NULL;
931 MonoGenericInst *method_inst = NULL;
932 MonoGenericContext res = { NULL, NULL };
934 mono_error_init (error);
936 if (context->class_inst) {
937 class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
938 if (!mono_error_ok (error))
939 goto fail;
942 if (context->method_inst) {
943 method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with, error);
944 if (!mono_error_ok (error))
945 goto fail;
948 res.class_inst = class_inst;
949 res.method_inst = method_inst;
950 fail:
951 return res;
955 * mono_class_inflate_generic_method:
956 * @method: a generic method
957 * @context: a generics context
959 * Instantiate the generic method @method using the generics context @context.
961 * Returns: the new instantiated method
963 MonoMethod *
964 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
966 return mono_class_inflate_generic_method_full (method, NULL, context);
969 MonoMethod *
970 mono_class_inflate_generic_method_checked (MonoMethod *method, MonoGenericContext *context, MonoError *error)
972 return mono_class_inflate_generic_method_full_checked (method, NULL, context, error);
976 * mono_class_inflate_generic_method_full:
978 * Instantiate method @method with the generic context @context.
979 * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
980 * Use mono_method_signature () and mono_method_get_header () to get the correct values.
982 MonoMethod*
983 mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context)
985 MonoError error;
986 MonoMethod *res = mono_class_inflate_generic_method_full_checked (method, klass_hint, context, &error);
987 if (!mono_error_ok (&error))
988 /*FIXME do proper error handling - on this case, kill this function. */
989 g_error ("Could not inflate generic method due to %s", mono_error_get_message (&error));
991 return res;
995 * mono_class_inflate_generic_method_full_checked:
996 * Same as mono_class_inflate_generic_method_full but return failure using @error.
998 MonoMethod*
999 mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error)
1001 MonoMethod *result;
1002 MonoMethodInflated *iresult, *cached;
1003 MonoMethodSignature *sig;
1004 MonoGenericContext tmp_context;
1005 gboolean is_mb_open = FALSE;
1007 mono_error_init (error);
1009 /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
1010 while (method->is_inflated) {
1011 MonoGenericContext *method_context = mono_method_get_context (method);
1012 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1014 tmp_context = inflate_generic_context (method_context, context, error);
1015 if (!mono_error_ok (error))
1016 return NULL;
1017 context = &tmp_context;
1019 if (mono_metadata_generic_context_equal (method_context, context))
1020 return method;
1022 method = imethod->declaring;
1026 * A method only needs to be inflated if the context has argument for which it is
1027 * parametric. Eg:
1029 * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
1030 * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
1033 if (!((method->is_generic && context->method_inst) ||
1034 (method->klass->generic_container && context->class_inst)))
1035 return method;
1038 * The reason for this hack is to fix the behavior of inflating generic methods that come from a MethodBuilder.
1039 * What happens is that instantiating a generic MethodBuilder with its own arguments should create a diferent object.
1040 * This is opposite to the way non-SRE MethodInfos behave.
1042 * This happens, for example, when we want to emit a recursive generic method. Given the following C# code:
1044 * void Example<T> () {
1045 * Example<T> ();
1048 * In Example, the method token must be encoded as: "void Example<!!0>()"
1050 * The reference to the first generic argument, "!!0", must be explicit otherwise it won't be inflated
1051 * properly. To get that we need to inflate the MethodBuilder with its own arguments.
1053 * On the other hand, inflating a non-SRE generic method with its own arguments should
1054 * return itself. For example:
1056 * MethodInfo m = ... //m is a generic method definition
1057 * MethodInfo res = m.MakeGenericMethod (m.GetGenericArguments ());
1058 * res == m
1060 * To allow such scenarios we must allow inflation of MethodBuilder to happen in a diferent way than
1061 * what happens with regular methods.
1063 * There is one last touch to this madness, once a TypeBuilder is finished, IOW CreateType() is called,
1064 * everything should behave like a regular type or method.
1067 is_mb_open = method->is_generic &&
1068 image_is_dynamic (method->klass->image) && !method->klass->wastypebuilder && /* that is a MethodBuilder from an unfinished TypeBuilder */
1069 context->method_inst == mono_method_get_generic_container (method)->context.method_inst; /* and it's been instantiated with its own arguments. */
1071 iresult = g_new0 (MonoMethodInflated, 1);
1072 iresult->context = *context;
1073 iresult->declaring = method;
1074 iresult->method.method.is_mb_open = is_mb_open;
1076 if (!context->method_inst && method->is_generic)
1077 iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
1079 if (!context->class_inst) {
1080 g_assert (!iresult->declaring->klass->generic_class);
1081 if (iresult->declaring->klass->generic_container)
1082 iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst;
1083 else if (iresult->declaring->klass->generic_class)
1084 iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst;
1087 cached = mono_method_inflated_lookup (iresult, FALSE);
1088 if (cached) {
1089 g_free (iresult);
1090 return (MonoMethod*)cached;
1093 mono_stats.inflated_method_count++;
1095 inflated_methods_size += sizeof (MonoMethodInflated);
1097 sig = mono_method_signature (method);
1098 if (!sig) {
1099 char *name = mono_type_get_full_name (method->klass);
1100 mono_error_set_bad_image (error, method->klass->image, "Could not resolve signature of method %s:%s", name, method->name);
1101 g_free (name);
1102 goto fail;
1105 if (sig->pinvoke) {
1106 memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
1107 } else {
1108 memcpy (&iresult->method.method, method, sizeof (MonoMethod));
1111 result = (MonoMethod *) iresult;
1112 result->is_inflated = TRUE;
1113 result->is_generic = FALSE;
1114 result->sre_method = FALSE;
1115 result->signature = NULL;
1116 result->is_mb_open = is_mb_open;
1118 if (!context->method_inst) {
1119 /* Set the generic_container of the result to the generic_container of method */
1120 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
1122 if (generic_container) {
1123 result->is_generic = 1;
1124 mono_method_set_generic_container (result, generic_container);
1128 if (!klass_hint || !klass_hint->generic_class ||
1129 klass_hint->generic_class->container_class != method->klass ||
1130 klass_hint->generic_class->context.class_inst != context->class_inst)
1131 klass_hint = NULL;
1133 if (method->klass->generic_container)
1134 result->klass = klass_hint;
1136 if (!result->klass) {
1137 MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context, error);
1138 if (!mono_error_ok (error))
1139 goto fail;
1141 result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
1142 if (inflated)
1143 mono_metadata_free_type (inflated);
1147 * FIXME: This should hold, but it doesn't:
1149 * if (result->is_inflated && mono_method_get_context (result)->method_inst &&
1150 * mono_method_get_context (result)->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)result)->declaring)->context.method_inst) {
1151 * g_assert (result->is_generic);
1154 * Fixing this here causes other things to break, hence a very
1155 * ugly hack in mini-trampolines.c - see
1156 * is_generic_method_definition().
1159 return (MonoMethod*)mono_method_inflated_lookup (iresult, TRUE);
1161 fail:
1162 g_free (iresult);
1163 return NULL;
1167 * mono_get_inflated_method:
1169 * Obsolete. We keep it around since it's mentioned in the public API.
1171 MonoMethod*
1172 mono_get_inflated_method (MonoMethod *method)
1174 return method;
1178 * mono_method_get_context_general:
1179 * @method: a method
1180 * @uninflated: handle uninflated methods?
1182 * Returns the generic context of a method or NULL if it doesn't have
1183 * one. For an inflated method that's the context stored in the
1184 * method. Otherwise it's in the method's generic container or in the
1185 * generic container of the method's class.
1187 MonoGenericContext*
1188 mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
1190 if (method->is_inflated) {
1191 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1192 return &imethod->context;
1194 if (!uninflated)
1195 return NULL;
1196 if (method->is_generic)
1197 return &(mono_method_get_generic_container (method)->context);
1198 if (method->klass->generic_container)
1199 return &method->klass->generic_container->context;
1200 return NULL;
1204 * mono_method_get_context:
1205 * @method: a method
1207 * Returns the generic context for method if it's inflated, otherwise
1208 * NULL.
1210 MonoGenericContext*
1211 mono_method_get_context (MonoMethod *method)
1213 return mono_method_get_context_general (method, FALSE);
1217 * mono_method_get_generic_container:
1219 * Returns the generic container of METHOD, which should be a generic method definition.
1220 * Returns NULL if METHOD is not a generic method definition.
1221 * LOCKING: Acquires the loader lock.
1223 MonoGenericContainer*
1224 mono_method_get_generic_container (MonoMethod *method)
1226 MonoGenericContainer *container;
1228 if (!method->is_generic)
1229 return NULL;
1231 container = mono_image_property_lookup (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER);
1232 g_assert (container);
1234 return container;
1238 * mono_method_set_generic_container:
1240 * Sets the generic container of METHOD to CONTAINER.
1241 * LOCKING: Acquires the image lock.
1243 void
1244 mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
1246 g_assert (method->is_generic);
1248 mono_image_property_insert (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
1251 /**
1252 * mono_class_find_enum_basetype:
1253 * @class: The enum class
1255 * Determine the basetype of an enum by iterating through its fields. We do this
1256 * in a separate function since it is cheaper than calling mono_class_setup_fields.
1258 static MonoType*
1259 mono_class_find_enum_basetype (MonoClass *class, MonoError *error)
1261 MonoGenericContainer *container = NULL;
1262 MonoImage *m = class->image;
1263 const int top = class->field.count;
1264 int i;
1266 g_assert (class->enumtype);
1268 mono_error_init (error);
1270 if (class->generic_container)
1271 container = class->generic_container;
1272 else if (class->generic_class) {
1273 MonoClass *gklass = class->generic_class->container_class;
1275 container = gklass->generic_container;
1276 g_assert (container);
1280 * Fetch all the field information.
1282 for (i = 0; i < top; i++){
1283 const char *sig;
1284 guint32 cols [MONO_FIELD_SIZE];
1285 int idx = class->field.first + i;
1286 MonoType *ftype;
1288 /* class->field.first and idx points into the fieldptr table */
1289 mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
1291 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
1292 continue;
1294 if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL)) {
1295 mono_error_set_bad_image (error, class->image, "Invalid field signature %x", cols [MONO_FIELD_SIGNATURE]);
1296 goto fail;
1299 sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
1300 mono_metadata_decode_value (sig, &sig);
1301 /* FIELD signature == 0x06 */
1302 if (*sig != 0x06) {
1303 mono_error_set_bad_image (error, class->image, "Invalid field signature %x, expected 0x6 but got %x", cols [MONO_FIELD_SIGNATURE], *sig);
1304 goto fail;
1307 ftype = mono_metadata_parse_type_full (m, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
1308 if (!ftype) {
1309 if (mono_loader_get_last_error ()) /*FIXME plug the above to not leak errors*/
1310 mono_error_set_from_loader_error (error);
1311 else
1312 mono_error_set_bad_image (error, class->image, "Could not parse type for field signature %x", cols [MONO_FIELD_SIGNATURE]);
1313 goto fail;
1315 if (class->generic_class) {
1316 //FIXME do we leak here?
1317 ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (class), error);
1318 if (!mono_error_ok (error))
1319 goto fail;
1320 ftype->attrs = cols [MONO_FIELD_FLAGS];
1323 return ftype;
1325 mono_error_set_type_load_class (error, class, "Could not find base type");
1327 fail:
1328 g_assert (!mono_loader_get_last_error ());
1329 return NULL;
1333 * Checks for MonoClass::exception_type without resolving all MonoType's into MonoClass'es
1335 static gboolean
1336 mono_type_has_exceptions (MonoType *type)
1338 switch (type->type) {
1339 case MONO_TYPE_CLASS:
1340 case MONO_TYPE_VALUETYPE:
1341 case MONO_TYPE_SZARRAY:
1342 return type->data.klass->exception_type;
1343 case MONO_TYPE_ARRAY:
1344 return type->data.array->eklass->exception_type;
1345 case MONO_TYPE_GENERICINST:
1346 return mono_generic_class_get_class (type->data.generic_class)->exception_type;
1348 return FALSE;
1352 * mono_class_alloc:
1354 * Allocate memory for some data belonging to CLASS, either from its image's mempool,
1355 * or from the heap.
1357 static gpointer
1358 mono_class_alloc (MonoClass *class, int size)
1360 if (class->generic_class)
1361 return mono_image_set_alloc (class->generic_class->owner, size);
1362 else
1363 return mono_image_alloc (class->image, size);
1366 static gpointer
1367 mono_class_alloc0 (MonoClass *class, int size)
1369 gpointer res;
1371 res = mono_class_alloc (class, size);
1372 memset (res, 0, size);
1373 return res;
1376 #define mono_class_new0(class,struct_type, n_structs) \
1377 ((struct_type *) mono_class_alloc0 ((class), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
1380 * mono_class_setup_basic_field_info:
1381 * @class: The class to initialize
1383 * Initializes the class->fields.
1384 * LOCKING: Assumes the loader lock is held.
1386 static void
1387 mono_class_setup_basic_field_info (MonoClass *class)
1389 MonoClassField *field;
1390 MonoClass *gtd;
1391 MonoImage *image;
1392 int i, top;
1394 if (class->fields)
1395 return;
1397 gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
1398 image = class->image;
1399 top = class->field.count;
1401 if (class->generic_class && image_is_dynamic (class->generic_class->container_class->image) && !class->generic_class->container_class->wastypebuilder) {
1403 * This happens when a generic instance of an unfinished generic typebuilder
1404 * is used as an element type for creating an array type. We can't initialize
1405 * the fields of this class using the fields of gklass, since gklass is not
1406 * finished yet, fields could be added to it later.
1408 return;
1411 if (gtd) {
1412 mono_class_setup_basic_field_info (gtd);
1414 top = gtd->field.count;
1415 class->field.first = gtd->field.first;
1416 class->field.count = gtd->field.count;
1419 class->fields = mono_class_alloc0 (class, sizeof (MonoClassField) * top);
1422 * Fetch all the field information.
1424 for (i = 0; i < top; i++){
1425 field = &class->fields [i];
1426 field->parent = class;
1428 if (gtd) {
1429 field->name = mono_field_get_name (&gtd->fields [i]);
1430 } else {
1431 int idx = class->field.first + i;
1432 /* class->field.first and idx points into the fieldptr table */
1433 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
1434 /* The name is needed for fieldrefs */
1435 field->name = mono_metadata_string_heap (image, name_idx);
1440 /**
1441 * mono_class_setup_fields:
1442 * @class: The class to initialize
1444 * Initializes the class->fields.
1445 * LOCKING: Assumes the loader lock is held.
1447 static void
1448 mono_class_setup_fields (MonoClass *class)
1450 MonoError error;
1451 MonoImage *m = class->image;
1452 int top;
1453 guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
1454 int i, blittable = TRUE;
1455 guint32 real_size = 0;
1456 guint32 packing_size = 0;
1457 gboolean explicit_size;
1458 MonoClassField *field;
1459 MonoGenericContainer *container = NULL;
1460 MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
1463 * FIXME: We have a race condition here. It's possible that this function returns
1464 * to its caller with `instance_size` set to `0` instead of the actual size. This
1465 * is not a problem when the function is called recursively on the same class,
1466 * because the size will be initialized by the outer invocation. What follows is a
1467 * description of how it can occur in other cases, too. There it is a problem,
1468 * because it can lead to the GC being asked to allocate an object of size `0`,
1469 * which SGen chokes on. The race condition is triggered infrequently by
1470 * `tests/sgen-suspend.cs`.
1472 * This function is called for a class whenever one of its subclasses is inited.
1473 * For example, it's called for every subclass of Object. What it does is this:
1475 * if (class->setup_fields_called)
1476 * return;
1477 * ...
1478 * class->instance_size = 0;
1479 * ...
1480 * class->setup_fields_called = 1;
1481 * ... critical point
1482 * class->instance_size = actual_instance_size;
1484 * The last two steps are sometimes reversed, but that only changes the way in which
1485 * the race condition works.
1487 * Assume thread A goes through this function and makes it to the critical point.
1488 * Now thread B runs the function and, since `setup_fields_called` is set, returns
1489 * immediately, but `instance_size` is incorrect.
1491 * The other case looks like this:
1493 * if (class->setup_fields_called)
1494 * return;
1495 * ... critical point X
1496 * class->instance_size = 0;
1497 * ... critical point Y
1498 * class->instance_size = actual_instance_size;
1499 * ...
1500 * class->setup_fields_called = 1;
1502 * Assume thread A goes through the function and makes it to critical point X. Now
1503 * thread B runs through the whole of the function, returning, assuming
1504 * `instance_size` is set. At that point thread A gets to run and makes it to
1505 * critical point Y, at which time `instance_size` is `0` again, invalidating thread
1506 * B's assumption.
1508 if (class->setup_fields_called)
1509 return;
1511 if (class->generic_class && image_is_dynamic (class->generic_class->container_class->image) && !class->generic_class->container_class->wastypebuilder) {
1513 * This happens when a generic instance of an unfinished generic typebuilder
1514 * is used as an element type for creating an array type. We can't initialize
1515 * the fields of this class using the fields of gklass, since gklass is not
1516 * finished yet, fields could be added to it later.
1518 return;
1521 mono_class_setup_basic_field_info (class);
1522 top = class->field.count;
1524 if (gtd) {
1525 mono_class_setup_fields (gtd);
1526 if (gtd->exception_type) {
1527 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1528 return;
1532 class->instance_size = 0;
1533 if (!class->rank)
1534 class->sizes.class_size = 0;
1536 if (class->parent) {
1537 /* For generic instances, class->parent might not have been initialized */
1538 mono_class_init (class->parent);
1539 if (!class->parent->size_inited) {
1540 mono_class_setup_fields (class->parent);
1541 if (class->parent->exception_type) {
1542 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1543 return;
1546 class->instance_size += class->parent->instance_size;
1547 class->min_align = class->parent->min_align;
1548 /* we use |= since it may have been set already */
1549 class->has_references |= class->parent->has_references;
1550 blittable = class->parent->blittable;
1551 } else {
1552 class->instance_size = sizeof (MonoObject);
1553 class->min_align = 1;
1556 /* We can't really enable 16 bytes alignment until the GC supports it.
1557 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
1558 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
1559 Bug #506144 is an example of this issue.
1561 if (class->simd_type)
1562 class->min_align = 16;
1564 /* Get the real size */
1565 explicit_size = mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &real_size);
1567 if (explicit_size) {
1568 if ((packing_size & 0xffffff00) != 0) {
1569 char *err_msg = g_strdup_printf ("Could not load struct '%s' with packing size %d >= 256", class->name, packing_size);
1570 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
1571 return;
1573 class->packing_size = packing_size;
1574 real_size += class->instance_size;
1577 if (!top) {
1578 if (explicit_size && real_size) {
1579 class->instance_size = MAX (real_size, class->instance_size);
1581 class->blittable = blittable;
1582 mono_memory_barrier ();
1583 class->size_inited = 1;
1584 class->fields_inited = 1;
1585 class->setup_fields_called = 1;
1586 return;
1589 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT)
1590 blittable = FALSE;
1592 /* Prevent infinite loops if the class references itself */
1593 class->setup_fields_called = 1;
1595 if (class->generic_container) {
1596 container = class->generic_container;
1597 } else if (gtd) {
1598 container = gtd->generic_container;
1599 g_assert (container);
1603 * Fetch all the field information.
1605 for (i = 0; i < top; i++){
1606 int idx = class->field.first + i;
1607 field = &class->fields [i];
1609 field->parent = class;
1611 if (!field->type) {
1612 mono_field_resolve_type (field, &error);
1613 if (!mono_error_ok (&error)) {
1614 /*mono_field_resolve_type already failed class*/
1615 mono_error_cleanup (&error);
1616 return;
1618 if (!field->type)
1619 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(class), field->name);
1620 g_assert (field->type);
1623 if (mono_field_is_deleted (field))
1624 continue;
1625 if (gtd) {
1626 MonoClassField *gfield = &gtd->fields [i];
1627 field->offset = gfield->offset;
1628 } else {
1629 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
1630 guint32 offset;
1631 mono_metadata_field_info (m, idx, &offset, NULL, NULL);
1632 field->offset = offset;
1634 if (field->offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1635 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Missing field layout info for %s", field->name));
1636 break;
1638 if (field->offset < -1) { /*-1 is used to encode special static fields */
1639 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Invalid negative field offset %d for %s", field->offset, field->name));
1640 break;
1642 if (class->generic_container) {
1643 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic class cannot have explicit layout."));
1644 break;
1649 /* Only do these checks if we still think this type is blittable */
1650 if (blittable && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1651 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
1652 blittable = FALSE;
1653 } else {
1654 MonoClass *field_class = mono_class_from_mono_type (field->type);
1655 if (field_class) {
1656 mono_class_setup_fields (field_class);
1657 if (field_class->exception_type) {
1658 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1659 break;
1662 if (!field_class || !field_class->blittable)
1663 blittable = FALSE;
1667 if (class->enumtype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1668 class->cast_class = class->element_class = mono_class_from_mono_type (field->type);
1669 blittable = class->element_class->blittable;
1672 if (mono_type_has_exceptions (field->type)) {
1673 char *class_name = mono_type_get_full_name (class);
1674 char *type_name = mono_type_full_name (field->type);
1676 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1677 g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
1678 g_free (class_name);
1679 g_free (type_name);
1680 break;
1682 /* The def_value of fields is compute lazily during vtable creation */
1685 if (class == mono_defaults.string_class)
1686 blittable = FALSE;
1688 class->blittable = blittable;
1690 if (class->enumtype && !mono_class_enum_basetype (class)) {
1691 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1692 return;
1694 if (explicit_size && real_size) {
1695 class->instance_size = MAX (real_size, class->instance_size);
1698 if (class->exception_type)
1699 return;
1700 mono_class_layout_fields (class);
1702 /*valuetypes can't be neither bigger than 1Mb or empty. */
1703 if (class->valuetype && (class->instance_size <= 0 || class->instance_size > (0x100000 + sizeof (MonoObject))))
1704 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1706 mono_memory_barrier ();
1707 class->fields_inited = 1;
1710 /**
1711 * mono_class_setup_fields_locking:
1712 * @class: The class to initialize
1714 * Initializes the class->fields array of fields.
1715 * Aquires the loader lock.
1717 void
1718 mono_class_setup_fields_locking (MonoClass *class)
1720 /* This can be checked without locks */
1721 if (class->fields_inited)
1722 return;
1723 mono_loader_lock ();
1724 mono_class_setup_fields (class);
1725 mono_loader_unlock ();
1729 * mono_class_has_references:
1731 * Returns whenever @klass->has_references is set, initializing it if needed.
1732 * Aquires the loader lock.
1734 static gboolean
1735 mono_class_has_references (MonoClass *klass)
1737 if (klass->init_pending) {
1738 /* Be conservative */
1739 return TRUE;
1740 } else {
1741 mono_class_init (klass);
1743 return klass->has_references;
1748 * mono_type_get_basic_type_from_generic:
1749 * @type: a type
1751 * Returns a closed type corresponding to the possibly open type
1752 * passed to it.
1754 MonoType*
1755 mono_type_get_basic_type_from_generic (MonoType *type)
1757 /* When we do generic sharing we let type variables stand for reference types. */
1758 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1759 return &mono_defaults.object_class->byval_arg;
1760 return type;
1764 * mono_class_layout_fields:
1765 * @class: a class
1767 * Compute the placement of fields inside an object or struct, according to
1768 * the layout rules and set the following fields in @class:
1769 * - has_references (if the class contains instance references firled or structs that contain references)
1770 * - has_static_refs (same, but for static fields)
1771 * - instance_size (size of the object in memory)
1772 * - class_size (size needed for the static fields)
1773 * - size_inited (flag set when the instance_size is set)
1775 * LOCKING: this is supposed to be called with the loader lock held.
1777 void
1778 mono_class_layout_fields (MonoClass *class)
1780 int i;
1781 const int top = class->field.count;
1782 guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
1783 guint32 pass, passes, real_size;
1784 gboolean gc_aware_layout = FALSE;
1785 gboolean has_static_fields = FALSE;
1786 MonoClassField *field;
1789 * When we do generic sharing we need to have layout
1790 * information for open generic classes (either with a generic
1791 * context containing type variables or with a generic
1792 * container), so we don't return in that case anymore.
1796 * Enable GC aware auto layout: in this mode, reference
1797 * fields are grouped together inside objects, increasing collector
1798 * performance.
1799 * Requires that all classes whose layout is known to native code be annotated
1800 * with [StructLayout (LayoutKind.Sequential)]
1801 * Value types have gc_aware_layout disabled by default, as per
1802 * what the default is for other runtimes.
1804 /* corlib is missing [StructLayout] directives in many places */
1805 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
1806 if (!class->valuetype)
1807 gc_aware_layout = TRUE;
1810 /* Compute klass->has_references */
1812 * Process non-static fields first, since static fields might recursively
1813 * refer to the class itself.
1815 for (i = 0; i < top; i++) {
1816 MonoType *ftype;
1818 field = &class->fields [i];
1820 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1821 ftype = mono_type_get_underlying_type (field->type);
1822 ftype = mono_type_get_basic_type_from_generic (ftype);
1823 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
1824 class->has_references = TRUE;
1828 for (i = 0; i < top; i++) {
1829 MonoType *ftype;
1831 field = &class->fields [i];
1833 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1834 ftype = mono_type_get_underlying_type (field->type);
1835 ftype = mono_type_get_basic_type_from_generic (ftype);
1836 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
1837 class->has_static_refs = TRUE;
1841 for (i = 0; i < top; i++) {
1842 MonoType *ftype;
1844 field = &class->fields [i];
1846 ftype = mono_type_get_underlying_type (field->type);
1847 ftype = mono_type_get_basic_type_from_generic (ftype);
1848 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
1849 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1850 class->has_static_refs = TRUE;
1851 else
1852 class->has_references = TRUE;
1857 * Compute field layout and total size (not considering static fields)
1860 switch (layout) {
1861 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
1862 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
1864 if (gc_aware_layout)
1865 passes = 2;
1866 else
1867 passes = 1;
1869 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
1870 passes = 1;
1872 if (class->parent) {
1873 mono_class_setup_fields (class->parent);
1874 if (class->parent->exception_type) {
1875 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1876 return;
1878 real_size = class->parent->instance_size;
1879 } else {
1880 real_size = sizeof (MonoObject);
1883 for (pass = 0; pass < passes; ++pass) {
1884 for (i = 0; i < top; i++){
1885 gint32 align;
1886 guint32 size;
1887 MonoType *ftype;
1889 field = &class->fields [i];
1891 if (mono_field_is_deleted (field))
1892 continue;
1893 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1894 continue;
1896 ftype = mono_type_get_underlying_type (field->type);
1897 ftype = mono_type_get_basic_type_from_generic (ftype);
1898 if (gc_aware_layout) {
1899 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
1900 if (pass == 1)
1901 continue;
1902 } else {
1903 if (pass == 0)
1904 continue;
1908 if ((top == 1) && (class->instance_size == sizeof (MonoObject)) &&
1909 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
1910 /* This field is a hack inserted by MCS to empty structures */
1911 continue;
1914 size = mono_type_size (field->type, &align);
1916 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
1917 align = class->packing_size ? MIN (class->packing_size, align): align;
1918 /* if the field has managed references, we need to force-align it
1919 * see bug #77788
1921 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
1922 align = MAX (align, sizeof (gpointer));
1924 class->min_align = MAX (align, class->min_align);
1925 field->offset = real_size;
1926 if (align) {
1927 field->offset += align - 1;
1928 field->offset &= ~(align - 1);
1930 /*TypeBuilders produce all sort of weird things*/
1931 g_assert (image_is_dynamic (class->image) || field->offset > 0);
1932 real_size = field->offset + size;
1935 class->instance_size = MAX (real_size, class->instance_size);
1937 if (class->instance_size & (class->min_align - 1)) {
1938 class->instance_size += class->min_align - 1;
1939 class->instance_size &= ~(class->min_align - 1);
1942 break;
1943 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
1944 guint8 *ref_bitmap;
1946 real_size = 0;
1947 for (i = 0; i < top; i++) {
1948 gint32 align;
1949 guint32 size;
1950 MonoType *ftype;
1952 field = &class->fields [i];
1955 * There must be info about all the fields in a type if it
1956 * uses explicit layout.
1958 if (mono_field_is_deleted (field))
1959 continue;
1960 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1961 continue;
1963 size = mono_type_size (field->type, &align);
1964 align = class->packing_size ? MIN (class->packing_size, align): align;
1965 class->min_align = MAX (align, class->min_align);
1968 * When we get here, field->offset is already set by the
1969 * loader (for either runtime fields or fields loaded from metadata).
1970 * The offset is from the start of the object: this works for both
1971 * classes and valuetypes.
1973 field->offset += sizeof (MonoObject);
1974 ftype = mono_type_get_underlying_type (field->type);
1975 ftype = mono_type_get_basic_type_from_generic (ftype);
1976 if (MONO_TYPE_IS_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
1977 if (field->offset % sizeof (gpointer)) {
1978 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1983 * Calc max size.
1985 real_size = MAX (real_size, size + field->offset);
1988 if (class->has_references) {
1989 ref_bitmap = g_new0 (guint8, real_size / sizeof (gpointer));
1991 /* Check for overlapping reference and non-reference fields */
1992 for (i = 0; i < top; i++) {
1993 MonoType *ftype;
1995 field = &class->fields [i];
1997 if (mono_field_is_deleted (field))
1998 continue;
1999 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2000 continue;
2001 ftype = mono_type_get_underlying_type (field->type);
2002 if (MONO_TYPE_IS_REFERENCE (ftype))
2003 ref_bitmap [field->offset / sizeof (gpointer)] = 1;
2005 for (i = 0; i < top; i++) {
2006 field = &class->fields [i];
2008 if (mono_field_is_deleted (field))
2009 continue;
2010 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2011 continue;
2013 // FIXME: Too much code does this
2014 #if 0
2015 if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field->offset / sizeof (gpointer)]) {
2016 char *err_msg = g_strdup_printf ("Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", class->name, field->offset);
2017 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
2019 #endif
2021 g_free (ref_bitmap);
2024 class->instance_size = MAX (real_size, class->instance_size);
2025 if (class->instance_size & (class->min_align - 1)) {
2026 class->instance_size += class->min_align - 1;
2027 class->instance_size &= ~(class->min_align - 1);
2029 break;
2033 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
2035 * For small structs, set min_align to at least the struct size to improve
2036 * performance, and since the JIT memset/memcpy code assumes this and generates
2037 * unaligned accesses otherwise. See #78990 for a testcase.
2039 if (class->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
2040 class->min_align = MAX (class->min_align, class->instance_size - sizeof (MonoObject));
2043 mono_memory_barrier ();
2044 class->size_inited = 1;
2047 * Compute static field layout and size
2049 for (i = 0; i < top; i++){
2050 gint32 align;
2051 guint32 size;
2053 field = &class->fields [i];
2055 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
2056 continue;
2057 if (mono_field_is_deleted (field))
2058 continue;
2060 if (mono_type_has_exceptions (field->type)) {
2061 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
2062 break;
2065 has_static_fields = TRUE;
2067 size = mono_type_size (field->type, &align);
2068 field->offset = class->sizes.class_size;
2069 /*align is always non-zero here*/
2070 field->offset += align - 1;
2071 field->offset &= ~(align - 1);
2072 class->sizes.class_size = field->offset + size;
2075 if (has_static_fields && class->sizes.class_size == 0)
2076 /* Simplify code which depends on class_size != 0 if the class has static fields */
2077 class->sizes.class_size = 8;
2080 static MonoMethod*
2081 create_array_method (MonoClass *class, const char *name, MonoMethodSignature *sig)
2083 MonoMethod *method;
2085 method = (MonoMethod *) mono_image_alloc0 (class->image, sizeof (MonoMethodPInvoke));
2086 method->klass = class;
2087 method->flags = METHOD_ATTRIBUTE_PUBLIC;
2088 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
2089 method->signature = sig;
2090 method->name = name;
2091 method->slot = -1;
2092 /* .ctor */
2093 if (name [0] == '.') {
2094 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
2095 } else {
2096 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
2098 return method;
2102 * mono_class_setup_methods:
2103 * @class: a class
2105 * Initializes the 'methods' array in CLASS.
2106 * Calling this method should be avoided if possible since it allocates a lot
2107 * of long-living MonoMethod structures.
2108 * Methods belonging to an interface are assigned a sequential slot starting
2109 * from 0.
2111 * On failure this function sets class->exception_type
2113 void
2114 mono_class_setup_methods (MonoClass *class)
2116 int i, count;
2117 MonoMethod **methods;
2119 if (class->methods)
2120 return;
2122 if (class->generic_class) {
2123 MonoError error;
2124 MonoClass *gklass = class->generic_class->container_class;
2126 mono_class_init (gklass);
2127 if (!gklass->exception_type)
2128 mono_class_setup_methods (gklass);
2129 if (gklass->exception_type) {
2130 /* FIXME make exception_data less opaque so it's possible to dup it here */
2131 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2132 return;
2135 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
2136 count = gklass->method.count;
2137 methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * (count + 1));
2139 for (i = 0; i < count; i++) {
2140 methods [i] = mono_class_inflate_generic_method_full_checked (
2141 gklass->methods [i], class, mono_class_get_context (class), &error);
2142 if (!mono_error_ok (&error)) {
2143 char *method = mono_method_full_name (gklass->methods [i], TRUE);
2144 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not inflate method %s due to %s", method, mono_error_get_message (&error)));
2146 g_free (method);
2147 mono_error_cleanup (&error);
2148 return;
2151 } else if (class->rank) {
2152 MonoError error;
2153 MonoMethod *amethod;
2154 MonoMethodSignature *sig;
2155 int count_generic = 0, first_generic = 0;
2156 int method_num = 0;
2157 gboolean jagged_ctor = FALSE;
2159 count = 3 + (class->rank > 1? 2: 1);
2161 mono_class_setup_interfaces (class, &error);
2162 g_assert (mono_error_ok (&error)); /*FIXME can this fail for array types?*/
2164 if (class->rank == 1 && class->element_class->rank) {
2165 jagged_ctor = TRUE;
2166 class->method.count ++;
2169 if (class->interface_count) {
2170 count_generic = generic_array_methods (class);
2171 first_generic = count;
2172 count += class->interface_count * count_generic;
2175 methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * count);
2177 sig = mono_metadata_signature_alloc (class->image, class->rank);
2178 sig->ret = &mono_defaults.void_class->byval_arg;
2179 sig->pinvoke = TRUE;
2180 sig->hasthis = TRUE;
2181 for (i = 0; i < class->rank; ++i)
2182 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2184 amethod = create_array_method (class, ".ctor", sig);
2185 methods [method_num++] = amethod;
2186 if (class->rank > 1) {
2187 sig = mono_metadata_signature_alloc (class->image, class->rank * 2);
2188 sig->ret = &mono_defaults.void_class->byval_arg;
2189 sig->pinvoke = TRUE;
2190 sig->hasthis = TRUE;
2191 for (i = 0; i < class->rank * 2; ++i)
2192 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2194 amethod = create_array_method (class, ".ctor", sig);
2195 methods [method_num++] = amethod;
2198 if (jagged_ctor) {
2199 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
2200 sig = mono_metadata_signature_alloc (class->image, class->rank + 1);
2201 sig->ret = &mono_defaults.void_class->byval_arg;
2202 sig->pinvoke = TRUE;
2203 sig->hasthis = TRUE;
2204 for (i = 0; i < class->rank + 1; ++i)
2205 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2206 amethod = create_array_method (class, ".ctor", sig);
2207 methods [method_num++] = amethod;
2210 /* element Get (idx11, [idx2, ...]) */
2211 sig = mono_metadata_signature_alloc (class->image, class->rank);
2212 sig->ret = &class->element_class->byval_arg;
2213 sig->pinvoke = TRUE;
2214 sig->hasthis = TRUE;
2215 for (i = 0; i < class->rank; ++i)
2216 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2217 amethod = create_array_method (class, "Get", sig);
2218 methods [method_num++] = amethod;
2219 /* element& Address (idx11, [idx2, ...]) */
2220 sig = mono_metadata_signature_alloc (class->image, class->rank);
2221 sig->ret = &class->element_class->this_arg;
2222 sig->pinvoke = TRUE;
2223 sig->hasthis = TRUE;
2224 for (i = 0; i < class->rank; ++i)
2225 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2226 amethod = create_array_method (class, "Address", sig);
2227 methods [method_num++] = amethod;
2228 /* void Set (idx11, [idx2, ...], element) */
2229 sig = mono_metadata_signature_alloc (class->image, class->rank + 1);
2230 sig->ret = &mono_defaults.void_class->byval_arg;
2231 sig->pinvoke = TRUE;
2232 sig->hasthis = TRUE;
2233 for (i = 0; i < class->rank; ++i)
2234 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2235 sig->params [i] = &class->element_class->byval_arg;
2236 amethod = create_array_method (class, "Set", sig);
2237 methods [method_num++] = amethod;
2239 for (i = 0; i < class->interface_count; i++)
2240 setup_generic_array_ifaces (class, class->interfaces [i], methods, first_generic + i * count_generic);
2241 } else {
2242 MonoError error;
2244 count = class->method.count;
2245 methods = mono_class_alloc (class, sizeof (MonoMethod*) * count);
2246 for (i = 0; i < count; ++i) {
2247 int idx = mono_metadata_translate_token_index (class->image, MONO_TABLE_METHOD, class->method.first + i + 1);
2248 methods [i] = mono_get_method_checked (class->image, MONO_TOKEN_METHOD_DEF | idx, class, NULL, &error);
2249 if (!methods [i]) {
2250 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load method %d due to %s", i, mono_error_get_message (&error)));
2251 mono_error_cleanup (&error);
2256 if (MONO_CLASS_IS_INTERFACE (class)) {
2257 int slot = 0;
2258 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
2259 for (i = 0; i < count; ++i) {
2260 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
2261 methods [i]->slot = slot++;
2265 mono_image_lock (class->image);
2267 if (!class->methods) {
2268 class->method.count = count;
2270 /* Needed because of the double-checking locking pattern */
2271 mono_memory_barrier ();
2273 class->methods = methods;
2276 mono_image_unlock (class->image);
2280 * mono_class_get_method_by_index:
2282 * Returns class->methods [index], initializing class->methods if neccesary.
2284 * LOCKING: Acquires the loader lock.
2286 MonoMethod*
2287 mono_class_get_method_by_index (MonoClass *class, int index)
2289 MonoError error;
2290 /* Avoid calling setup_methods () if possible */
2291 if (class->generic_class && !class->methods) {
2292 MonoClass *gklass = class->generic_class->container_class;
2293 MonoMethod *m;
2295 m = mono_class_inflate_generic_method_full_checked (
2296 gklass->methods [index], class, mono_class_get_context (class), &error);
2297 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2299 * If setup_methods () is called later for this class, no duplicates are created,
2300 * since inflate_generic_method guarantees that only one instance of a method
2301 * is created for each context.
2304 mono_class_setup_methods (class);
2305 g_assert (m == class->methods [index]);
2307 return m;
2308 } else {
2309 mono_class_setup_methods (class);
2310 if (class->exception_type) /*FIXME do proper error handling*/
2311 return NULL;
2312 g_assert (index >= 0 && index < class->method.count);
2313 return class->methods [index];
2318 * mono_class_get_inflated_method:
2320 * Given an inflated class CLASS and a method METHOD which should be a method of
2321 * CLASS's generic definition, return the inflated method corresponding to METHOD.
2323 MonoMethod*
2324 mono_class_get_inflated_method (MonoClass *class, MonoMethod *method)
2326 MonoClass *gklass = class->generic_class->container_class;
2327 int i;
2329 g_assert (method->klass == gklass);
2331 mono_class_setup_methods (gklass);
2332 g_assert (!gklass->exception_type); /*FIXME do proper error handling*/
2334 for (i = 0; i < gklass->method.count; ++i) {
2335 if (gklass->methods [i] == method) {
2336 if (class->methods) {
2337 return class->methods [i];
2338 } else {
2339 MonoError error;
2340 MonoMethod *result = mono_class_inflate_generic_method_full_checked (gklass->methods [i], class, mono_class_get_context (class), &error);
2341 g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
2342 return result;
2347 return NULL;
2351 * mono_class_get_vtable_entry:
2353 * Returns class->vtable [offset], computing it if neccesary. Returns NULL on failure.
2354 * LOCKING: Acquires the loader lock.
2356 MonoMethod*
2357 mono_class_get_vtable_entry (MonoClass *class, int offset)
2359 MonoMethod *m;
2361 if (class->rank == 1) {
2363 * szarrays do not overwrite any methods of Array, so we can avoid
2364 * initializing their vtables in some cases.
2366 mono_class_setup_vtable (class->parent);
2367 if (offset < class->parent->vtable_size)
2368 return class->parent->vtable [offset];
2371 if (class->generic_class) {
2372 MonoError error;
2373 MonoClass *gklass = class->generic_class->container_class;
2374 mono_class_setup_vtable (gklass);
2375 m = gklass->vtable [offset];
2377 m = mono_class_inflate_generic_method_full_checked (m, class, mono_class_get_context (class), &error);
2378 g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
2379 } else {
2380 mono_class_setup_vtable (class);
2381 if (class->exception_type)
2382 return NULL;
2383 m = class->vtable [offset];
2386 return m;
2390 * mono_class_get_vtable_size:
2392 * Return the vtable size for KLASS.
2395 mono_class_get_vtable_size (MonoClass *klass)
2397 mono_class_setup_vtable (klass);
2399 return klass->vtable_size;
2403 * mono_class_setup_properties:
2405 * Initialize class->ext.property and class->ext.properties.
2407 * This method can fail the class.
2409 static void
2410 mono_class_setup_properties (MonoClass *class)
2412 guint startm, endm, i, j;
2413 guint32 cols [MONO_PROPERTY_SIZE];
2414 MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS];
2415 MonoProperty *properties;
2416 guint32 last;
2417 int first, count;
2419 if (class->ext && class->ext->properties)
2420 return;
2422 if (class->generic_class) {
2423 MonoClass *gklass = class->generic_class->container_class;
2425 mono_class_init (gklass);
2426 mono_class_setup_properties (gklass);
2427 if (gklass->exception_type) {
2428 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2429 return;
2432 properties = mono_class_new0 (class, MonoProperty, gklass->ext->property.count + 1);
2434 for (i = 0; i < gklass->ext->property.count; i++) {
2435 MonoError error;
2436 MonoProperty *prop = &properties [i];
2438 *prop = gklass->ext->properties [i];
2440 if (prop->get)
2441 prop->get = mono_class_inflate_generic_method_full_checked (
2442 prop->get, class, mono_class_get_context (class), &error);
2443 if (prop->set)
2444 prop->set = mono_class_inflate_generic_method_full_checked (
2445 prop->set, class, mono_class_get_context (class), &error);
2447 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2448 prop->parent = class;
2451 first = gklass->ext->property.first;
2452 count = gklass->ext->property.count;
2453 } else {
2454 first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
2455 count = last - first;
2457 if (count) {
2458 mono_class_setup_methods (class);
2459 if (class->exception_type)
2460 return;
2463 properties = mono_class_alloc0 (class, sizeof (MonoProperty) * count);
2464 for (i = first; i < last; ++i) {
2465 mono_metadata_decode_table_row (class->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
2466 properties [i - first].parent = class;
2467 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
2468 properties [i - first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]);
2470 startm = mono_metadata_methods_from_property (class->image, i, &endm);
2471 for (j = startm; j < endm; ++j) {
2472 MonoMethod *method;
2474 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2476 if (class->image->uncompressed_metadata) {
2477 MonoError error;
2478 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2479 method = mono_get_method_checked (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class, NULL, &error);
2480 mono_error_cleanup (&error); /* FIXME don't swallow this error */
2481 } else {
2482 method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
2485 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2486 case METHOD_SEMANTIC_SETTER:
2487 properties [i - first].set = method;
2488 break;
2489 case METHOD_SEMANTIC_GETTER:
2490 properties [i - first].get = method;
2491 break;
2492 default:
2493 break;
2499 mono_class_alloc_ext (class);
2501 mono_image_lock (class->image);
2503 if (class->ext->properties) {
2504 /* We leak 'properties' which was allocated from the image mempool */
2505 mono_image_unlock (class->image);
2506 return;
2509 class->ext->property.first = first;
2510 class->ext->property.count = count;
2512 /* Flush any pending writes as we do double checked locking on class->ext->properties */
2513 mono_memory_barrier ();
2515 /* Leave this assignment as the last op in the function */
2516 class->ext->properties = properties;
2518 mono_image_unlock (class->image);
2521 static MonoMethod**
2522 inflate_method_listz (MonoMethod **methods, MonoClass *class, MonoGenericContext *context)
2524 MonoMethod **om, **retval;
2525 int count;
2527 for (om = methods, count = 0; *om; ++om, ++count)
2530 retval = g_new0 (MonoMethod*, count + 1);
2531 count = 0;
2532 for (om = methods, count = 0; *om; ++om, ++count) {
2533 MonoError error;
2534 retval [count] = mono_class_inflate_generic_method_full_checked (*om, class, context, &error);
2535 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2538 return retval;
2541 /*This method can fail the class.*/
2542 static void
2543 mono_class_setup_events (MonoClass *class)
2545 int first, count;
2546 guint startm, endm, i, j;
2547 guint32 cols [MONO_EVENT_SIZE];
2548 MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS];
2549 guint32 last;
2550 MonoEvent *events;
2552 if (class->ext && class->ext->events)
2553 return;
2555 if (class->generic_class) {
2556 MonoClass *gklass = class->generic_class->container_class;
2557 MonoGenericContext *context = NULL;
2559 mono_class_setup_events (gklass);
2560 if (gklass->exception_type) {
2561 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2562 return;
2565 first = gklass->ext->event.first;
2566 count = gklass->ext->event.count;
2568 events = mono_class_new0 (class, MonoEvent, count);
2570 if (count)
2571 context = mono_class_get_context (class);
2573 for (i = 0; i < count; i++) {
2574 MonoError error;
2575 MonoEvent *event = &events [i];
2576 MonoEvent *gevent = &gklass->ext->events [i];
2578 mono_error_init (&error); //since we do conditional calls, we must ensure the default value is ok
2580 event->parent = class;
2581 event->name = gevent->name;
2582 event->add = gevent->add ? mono_class_inflate_generic_method_full_checked (gevent->add, class, context, &error) : NULL;
2583 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2584 event->remove = gevent->remove ? mono_class_inflate_generic_method_full_checked (gevent->remove, class, context, &error) : NULL;
2585 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2586 event->raise = gevent->raise ? mono_class_inflate_generic_method_full_checked (gevent->raise, class, context, &error) : NULL;
2587 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2589 #ifndef MONO_SMALL_CONFIG
2590 event->other = gevent->other ? inflate_method_listz (gevent->other, class, context) : NULL;
2591 #endif
2592 event->attrs = gevent->attrs;
2594 } else {
2595 first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
2596 count = last - first;
2598 if (count) {
2599 mono_class_setup_methods (class);
2600 if (class->exception_type) {
2601 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2602 return;
2606 events = mono_class_alloc0 (class, sizeof (MonoEvent) * count);
2607 for (i = first; i < last; ++i) {
2608 MonoEvent *event = &events [i - first];
2610 mono_metadata_decode_table_row (class->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
2611 event->parent = class;
2612 event->attrs = cols [MONO_EVENT_FLAGS];
2613 event->name = mono_metadata_string_heap (class->image, cols [MONO_EVENT_NAME]);
2615 startm = mono_metadata_methods_from_event (class->image, i, &endm);
2616 for (j = startm; j < endm; ++j) {
2617 MonoMethod *method;
2619 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2621 if (class->image->uncompressed_metadata) {
2622 MonoError error;
2623 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2624 method = mono_get_method_checked (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class, NULL, &error);
2625 mono_error_cleanup (&error); /* FIXME don't swallow this error */
2626 } else {
2627 method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
2630 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2631 case METHOD_SEMANTIC_ADD_ON:
2632 event->add = method;
2633 break;
2634 case METHOD_SEMANTIC_REMOVE_ON:
2635 event->remove = method;
2636 break;
2637 case METHOD_SEMANTIC_FIRE:
2638 event->raise = method;
2639 break;
2640 case METHOD_SEMANTIC_OTHER: {
2641 #ifndef MONO_SMALL_CONFIG
2642 int n = 0;
2644 if (event->other == NULL) {
2645 event->other = g_new0 (MonoMethod*, 2);
2646 } else {
2647 while (event->other [n])
2648 n++;
2649 event->other = g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
2651 event->other [n] = method;
2652 /* NULL terminated */
2653 event->other [n + 1] = NULL;
2654 #endif
2655 break;
2657 default:
2658 break;
2664 mono_class_alloc_ext (class);
2666 mono_image_lock (class->image);
2668 if (class->ext->events) {
2669 mono_image_unlock (class->image);
2670 return;
2673 class->ext->event.first = first;
2674 class->ext->event.count = count;
2676 /* Flush any pending writes as we do double checked locking on class->ext.events */
2677 mono_memory_barrier ();
2679 /* Leave this assignment as the last op in the function */
2680 class->ext->events = events;
2682 mono_image_unlock (class->image);
2686 * Global pool of interface IDs, represented as a bitset.
2687 * LOCKING: Protected by the classes lock.
2689 static MonoBitSet *global_interface_bitset = NULL;
2692 * mono_unload_interface_ids:
2693 * @bitset: bit set of interface IDs
2695 * When an image is unloaded, the interface IDs associated with
2696 * the image are put back in the global pool of IDs so the numbers
2697 * can be reused.
2699 void
2700 mono_unload_interface_ids (MonoBitSet *bitset)
2702 classes_lock ();
2703 mono_bitset_sub (global_interface_bitset, bitset);
2704 classes_unlock ();
2707 void
2708 mono_unload_interface_id (MonoClass *class)
2710 if (global_interface_bitset && class->interface_id) {
2711 classes_lock ();
2712 mono_bitset_clear (global_interface_bitset, class->interface_id);
2713 classes_unlock ();
2718 * mono_get_unique_iid:
2719 * @class: interface
2721 * Assign a unique integer ID to the interface represented by @class.
2722 * The ID will positive and as small as possible.
2723 * LOCKING: Acquires the classes lock.
2724 * Returns: the new ID.
2726 static guint
2727 mono_get_unique_iid (MonoClass *class)
2729 int iid;
2731 g_assert (MONO_CLASS_IS_INTERFACE (class));
2733 classes_lock ();
2735 if (!global_interface_bitset) {
2736 global_interface_bitset = mono_bitset_new (128, 0);
2739 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
2740 if (iid < 0) {
2741 int old_size = mono_bitset_size (global_interface_bitset);
2742 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
2743 mono_bitset_free (global_interface_bitset);
2744 global_interface_bitset = new_set;
2745 iid = old_size;
2747 mono_bitset_set (global_interface_bitset, iid);
2748 /* set the bit also in the per-image set */
2749 if (!class->generic_class) {
2750 if (class->image->interface_bitset) {
2751 if (iid >= mono_bitset_size (class->image->interface_bitset)) {
2752 MonoBitSet *new_set = mono_bitset_clone (class->image->interface_bitset, iid + 1);
2753 mono_bitset_free (class->image->interface_bitset);
2754 class->image->interface_bitset = new_set;
2756 } else {
2757 class->image->interface_bitset = mono_bitset_new (iid + 1, 0);
2759 mono_bitset_set (class->image->interface_bitset, iid);
2762 classes_unlock ();
2764 #ifndef MONO_SMALL_CONFIG
2765 if (mono_print_vtable) {
2766 int generic_id;
2767 char *type_name = mono_type_full_name (&class->byval_arg);
2768 if (class->generic_class && !class->generic_class->context.class_inst->is_open) {
2769 generic_id = class->generic_class->context.class_inst->id;
2770 g_assert (generic_id != 0);
2771 } else {
2772 generic_id = 0;
2774 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, class->image->name, type_name, generic_id);
2775 g_free (type_name);
2777 #endif
2779 g_assert (iid <= 65535);
2780 return iid;
2783 static void
2784 collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, MonoError *error)
2786 int i;
2787 MonoClass *ic;
2789 mono_class_setup_interfaces (klass, error);
2790 if (!mono_error_ok (error))
2791 return;
2793 for (i = 0; i < klass->interface_count; i++) {
2794 ic = klass->interfaces [i];
2796 if (*res == NULL)
2797 *res = g_ptr_array_new ();
2798 g_ptr_array_add (*res, ic);
2799 mono_class_init (ic);
2800 if (ic->exception_type) {
2801 mono_error_set_type_load_class (error, ic, "Error Loading class");
2802 return;
2805 collect_implemented_interfaces_aux (ic, res, error);
2806 if (!mono_error_ok (error))
2807 return;
2811 GPtrArray*
2812 mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error)
2814 GPtrArray *res = NULL;
2816 collect_implemented_interfaces_aux (klass, &res, error);
2817 if (!mono_error_ok (error)) {
2818 if (res)
2819 g_ptr_array_free (res, TRUE);
2820 return NULL;
2822 return res;
2825 static int
2826 compare_interface_ids (const void *p_key, const void *p_element) {
2827 const MonoClass *key = p_key;
2828 const MonoClass *element = *(MonoClass**) p_element;
2830 return (key->interface_id - element->interface_id);
2833 /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/
2835 mono_class_interface_offset (MonoClass *klass, MonoClass *itf) {
2836 MonoClass **result = mono_binary_search (
2837 itf,
2838 klass->interfaces_packed,
2839 klass->interface_offsets_count,
2840 sizeof (MonoClass *),
2841 compare_interface_ids);
2842 if (result) {
2843 return klass->interface_offsets_packed [result - (klass->interfaces_packed)];
2844 } else {
2845 return -1;
2850 * mono_class_interface_offset_with_variance:
2852 * Return the interface offset of @itf in @klass. Sets @non_exact_match to TRUE if the match required variance check
2853 * If @itf is an interface with generic variant arguments, try to find the compatible one.
2855 * Note that this function is responsible for resolving ambiguities. Right now we use whatever ordering interfaces_packed gives us.
2857 * FIXME figure out MS disambiguation rules and fix this function.
2860 mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match) {
2861 int i = mono_class_interface_offset (klass, itf);
2862 *non_exact_match = FALSE;
2863 if (i >= 0)
2864 return i;
2866 if (!mono_class_has_variant_generic_params (itf))
2867 return -1;
2869 for (i = 0; i < klass->interface_offsets_count; i++) {
2870 if (mono_class_is_variant_compatible (itf, klass->interfaces_packed [i], FALSE)) {
2871 *non_exact_match = TRUE;
2872 return klass->interface_offsets_packed [i];
2876 return -1;
2879 static void
2880 print_implemented_interfaces (MonoClass *klass) {
2881 char *name;
2882 MonoError error;
2883 GPtrArray *ifaces = NULL;
2884 int i;
2885 int ancestor_level = 0;
2887 name = mono_type_get_full_name (klass);
2888 printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
2889 g_free (name);
2891 for (i = 0; i < klass->interface_offsets_count; i++)
2892 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
2893 klass->interfaces_packed [i]->interface_id,
2894 klass->interface_offsets_packed [i],
2895 klass->interfaces_packed [i]->method.count,
2896 klass->interfaces_packed [i]->name_space,
2897 klass->interfaces_packed [i]->name );
2898 printf ("Interface flags: ");
2899 for (i = 0; i <= klass->max_interface_id; i++)
2900 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
2901 printf ("(%d,T)", i);
2902 else
2903 printf ("(%d,F)", i);
2904 printf ("\n");
2905 printf ("Dump interface flags:");
2906 #ifdef COMPRESSED_INTERFACE_BITMAP
2908 const uint8_t* p = klass->interface_bitmap;
2909 i = klass->max_interface_id;
2910 while (i > 0) {
2911 printf (" %d x 00 %02X", p [0], p [1]);
2912 i -= p [0] * 8;
2913 i -= 8;
2916 #else
2917 for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
2918 printf (" %02X", klass->interface_bitmap [i]);
2919 #endif
2920 printf ("\n");
2921 while (klass != NULL) {
2922 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
2923 ifaces = mono_class_get_implemented_interfaces (klass, &error);
2924 if (!mono_error_ok (&error)) {
2925 printf (" Type failed due to %s\n", mono_error_get_message (&error));
2926 mono_error_cleanup (&error);
2927 } else if (ifaces) {
2928 for (i = 0; i < ifaces->len; i++) {
2929 MonoClass *ic = g_ptr_array_index (ifaces, i);
2930 printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
2931 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
2932 ic->interface_id,
2933 mono_class_interface_offset (klass, ic),
2934 ic->method.count,
2935 ic->name_space,
2936 ic->name );
2938 g_ptr_array_free (ifaces, TRUE);
2940 ancestor_level ++;
2941 klass = klass->parent;
2945 static MonoClass*
2946 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
2948 MonoType *args [1];
2949 args [0] = &arg0->byval_arg;
2951 return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
2954 static MonoClass*
2955 array_class_get_if_rank (MonoClass *class, guint rank)
2957 return rank ? mono_array_class_get (class, rank) : class;
2960 static void
2961 fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *eclass, int rank)
2963 valuetype_types [0] = eclass;
2964 if (eclass == mono_defaults.int16_class)
2965 valuetype_types [1] = mono_defaults.uint16_class;
2966 else if (eclass == mono_defaults.uint16_class)
2967 valuetype_types [1] = mono_defaults.int16_class;
2968 else if (eclass == mono_defaults.int32_class)
2969 valuetype_types [1] = mono_defaults.uint32_class;
2970 else if (eclass == mono_defaults.uint32_class)
2971 valuetype_types [1] = mono_defaults.int32_class;
2972 else if (eclass == mono_defaults.int64_class)
2973 valuetype_types [1] = mono_defaults.uint64_class;
2974 else if (eclass == mono_defaults.uint64_class)
2975 valuetype_types [1] = mono_defaults.int64_class;
2976 else if (eclass == mono_defaults.byte_class)
2977 valuetype_types [1] = mono_defaults.sbyte_class;
2978 else if (eclass == mono_defaults.sbyte_class)
2979 valuetype_types [1] = mono_defaults.byte_class;
2980 else if (eclass->enumtype && mono_class_enum_basetype (eclass))
2981 valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass));
2984 /* this won't be needed once bug #325495 is completely fixed
2985 * though we'll need something similar to know which interfaces to allow
2986 * in arrays when they'll be lazyly created
2988 * FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
2989 * MS returns diferrent types based on which instance is called. For example:
2990 * object obj = new byte[10][];
2991 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
2992 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
2993 * a != b ==> true
2995 * Fixing this should kill quite some code, save some bits and improve compatibility.
2997 static MonoClass**
2998 get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enumerator)
3000 MonoClass *eclass = class->element_class;
3001 static MonoClass* generic_icollection_class = NULL;
3002 static MonoClass* generic_ienumerable_class = NULL;
3003 static MonoClass* generic_ienumerator_class = NULL;
3004 static MonoClass* generic_ireadonlylist_class = NULL;
3005 static MonoClass* generic_ireadonlycollection_class = NULL;
3006 MonoClass *valuetype_types[2] = { NULL, NULL };
3007 MonoClass **interfaces = NULL;
3008 int i, nifaces, interface_count, real_count, original_rank;
3009 int all_interfaces;
3010 gboolean internal_enumerator;
3011 gboolean eclass_is_valuetype;
3013 if (!mono_defaults.generic_ilist_class) {
3014 *num = 0;
3015 return NULL;
3017 internal_enumerator = FALSE;
3018 eclass_is_valuetype = FALSE;
3019 original_rank = eclass->rank;
3020 if (class->byval_arg.type != MONO_TYPE_SZARRAY) {
3021 if (class->generic_class && class->nested_in == mono_defaults.array_class && strcmp (class->name, "InternalEnumerator`1") == 0) {
3023 * For a Enumerator<T[]> we need to get the list of interfaces for T.
3025 eclass = mono_class_from_mono_type (class->generic_class->context.class_inst->type_argv [0]);
3026 original_rank = eclass->rank;
3027 if (!eclass->rank)
3028 eclass = eclass->element_class;
3029 internal_enumerator = TRUE;
3030 *is_enumerator = TRUE;
3031 } else {
3032 *num = 0;
3033 return NULL;
3038 * with this non-lazy impl we can't implement all the interfaces so we do just the minimal stuff
3039 * for deep levels of arrays of arrays (string[][] has all the interfaces, string[][][] doesn't)
3041 all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
3043 if (!generic_icollection_class) {
3044 generic_icollection_class = mono_class_from_name (mono_defaults.corlib,
3045 "System.Collections.Generic", "ICollection`1");
3046 generic_ienumerable_class = mono_class_from_name (mono_defaults.corlib,
3047 "System.Collections.Generic", "IEnumerable`1");
3048 generic_ienumerator_class = mono_class_from_name (mono_defaults.corlib,
3049 "System.Collections.Generic", "IEnumerator`1");
3050 generic_ireadonlylist_class = mono_class_from_name (mono_defaults.corlib,
3051 "System.Collections.Generic", "IReadOnlyList`1");
3052 generic_ireadonlycollection_class = mono_class_from_name (mono_defaults.corlib,
3053 "System.Collections.Generic", "IReadOnlyCollection`1");
3056 mono_class_init (eclass);
3059 * Arrays in 2.0 need to implement a number of generic interfaces
3060 * (IList`1, ICollection`1, IEnumerable`1 for a number of types depending
3061 * on the element class). For net 4.5, we also need to implement IReadOnlyList`1/IReadOnlyCollection`1.
3062 * We collect the types needed to build the
3063 * instantiations in interfaces at intervals of 3/5, because 3/5 are
3064 * the generic interfaces needed to implement.
3066 * On 4.5, as an optimization, we don't expand ref classes for the variant generic interfaces
3067 * (IEnumerator, IReadOnlyList and IReadOnlyColleciton). The regular dispatch code can handle those cases.
3069 if (eclass->valuetype) {
3070 nifaces = generic_ireadonlylist_class ? 5 : 3;
3071 fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank);
3073 /* IList, ICollection, IEnumerable, IReadOnlyList`1 */
3074 real_count = interface_count = valuetype_types [1] ? (nifaces * 2) : nifaces;
3075 if (internal_enumerator) {
3076 ++real_count;
3077 if (valuetype_types [1])
3078 ++real_count;
3081 interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
3082 interfaces [0] = valuetype_types [0];
3083 if (valuetype_types [1])
3084 interfaces [nifaces] = valuetype_types [1];
3086 eclass_is_valuetype = TRUE;
3087 } else {
3088 int j;
3089 int idepth = eclass->idepth;
3090 if (!internal_enumerator)
3091 idepth--;
3092 nifaces = generic_ireadonlylist_class ? 2 : 3;
3094 // FIXME: This doesn't seem to work/required for generic params
3095 if (!(eclass->this_arg.type == MONO_TYPE_VAR || eclass->this_arg.type == MONO_TYPE_MVAR || (image_is_dynamic (eclass->image) && !eclass->wastypebuilder)))
3096 mono_class_setup_interface_offsets (eclass);
3098 interface_count = all_interfaces? eclass->interface_offsets_count: eclass->interface_count;
3099 /* we add object for interfaces and the supertypes for the other
3100 * types. The last of the supertypes is the element class itself which we
3101 * already created the explicit interfaces for (so we include it for IEnumerator
3102 * and exclude it for arrays).
3104 if (MONO_CLASS_IS_INTERFACE (eclass))
3105 interface_count++;
3106 else
3107 interface_count += idepth;
3108 if (eclass->rank && eclass->element_class->valuetype) {
3109 fill_valuetype_array_derived_types (valuetype_types, eclass->element_class, original_rank);
3110 if (valuetype_types [1])
3111 ++interface_count;
3113 /* IList, ICollection, IEnumerable, IReadOnlyList */
3114 interface_count *= nifaces;
3115 real_count = interface_count;
3116 if (internal_enumerator) {
3117 real_count += (MONO_CLASS_IS_INTERFACE (eclass) ? 1 : idepth) + eclass->interface_offsets_count;
3118 if (valuetype_types [1])
3119 ++real_count;
3121 interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
3122 if (MONO_CLASS_IS_INTERFACE (eclass)) {
3123 interfaces [0] = mono_defaults.object_class;
3124 j = nifaces;
3125 } else {
3126 j = 0;
3127 for (i = 0; i < idepth; i++) {
3128 mono_class_init (eclass->supertypes [i]);
3129 interfaces [j] = eclass->supertypes [i];
3130 j += nifaces;
3133 if (all_interfaces) {
3134 for (i = 0; i < eclass->interface_offsets_count; i++) {
3135 interfaces [j] = eclass->interfaces_packed [i];
3136 j += nifaces;
3138 } else {
3139 for (i = 0; i < eclass->interface_count; i++) {
3140 interfaces [j] = eclass->interfaces [i];
3141 j += nifaces;
3144 if (valuetype_types [1]) {
3145 interfaces [j] = array_class_get_if_rank (valuetype_types [1], original_rank);
3146 j += nifaces;
3150 /* instantiate the generic interfaces */
3151 for (i = 0; i < interface_count; i += nifaces) {
3152 MonoClass *iface = interfaces [i];
3154 interfaces [i + 0] = inflate_class_one_arg (mono_defaults.generic_ilist_class, iface);
3155 interfaces [i + 1] = inflate_class_one_arg (generic_icollection_class, iface);
3157 if (eclass->valuetype) {
3158 interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
3159 if (generic_ireadonlylist_class) {
3160 interfaces [i + 3] = inflate_class_one_arg (generic_ireadonlylist_class, iface);
3161 interfaces [i + 4] = inflate_class_one_arg (generic_ireadonlycollection_class, iface);
3163 } else {
3164 if (!generic_ireadonlylist_class)
3165 interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
3168 if (internal_enumerator) {
3169 int j;
3170 /* instantiate IEnumerator<iface> */
3171 for (i = 0; i < interface_count; i++) {
3172 interfaces [i] = inflate_class_one_arg (generic_ienumerator_class, interfaces [i]);
3174 j = interface_count;
3175 if (!eclass_is_valuetype) {
3176 if (MONO_CLASS_IS_INTERFACE (eclass)) {
3177 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, mono_defaults.object_class);
3178 j ++;
3179 } else {
3180 for (i = 0; i < eclass->idepth; i++) {
3181 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->supertypes [i]);
3182 j ++;
3185 for (i = 0; i < eclass->interface_offsets_count; i++) {
3186 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->interfaces_packed [i]);
3187 j ++;
3189 } else {
3190 interfaces [j++] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [0], original_rank));
3192 if (valuetype_types [1])
3193 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [1], original_rank));
3195 #if 0
3197 char *type_name = mono_type_get_name_full (&class->byval_arg, 0);
3198 for (i = 0; i < real_count; ++i) {
3199 char *name = mono_type_get_name_full (&interfaces [i]->byval_arg, 0);
3200 g_print ("%s implements %s\n", type_name, name);
3201 g_free (name);
3203 g_free (type_name);
3205 #endif
3206 *num = real_count;
3207 return interfaces;
3210 static int
3211 find_array_interface (MonoClass *klass, const char *name)
3213 int i;
3214 for (i = 0; i < klass->interface_count; ++i) {
3215 if (strcmp (klass->interfaces [i]->name, name) == 0)
3216 return i;
3218 return -1;
3222 * Return the number of virtual methods.
3223 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
3224 * Return -1 on failure.
3225 * FIXME It would be nice if this information could be cached somewhere.
3227 static int
3228 count_virtual_methods (MonoClass *class)
3230 int i, count = 0;
3231 guint32 flags;
3232 class = mono_class_get_generic_type_definition (class); /*We can find this information by looking at the GTD*/
3234 if (class->methods || !MONO_CLASS_HAS_STATIC_METADATA (class)) {
3235 mono_class_setup_methods (class);
3236 if (class->exception_type)
3237 return -1;
3239 for (i = 0; i < class->method.count; ++i) {
3240 flags = class->methods [i]->flags;
3241 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3242 ++count;
3244 } else {
3245 for (i = 0; i < class->method.count; ++i) {
3246 flags = mono_metadata_decode_table_row_col (class->image, MONO_TABLE_METHOD, class->method.first + i, MONO_METHOD_FLAGS);
3248 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3249 ++count;
3252 return count;
3255 static int
3256 find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic)
3258 int m, l = 0;
3259 if (!num_ifaces)
3260 return -1;
3261 while (1) {
3262 if (l > num_ifaces)
3263 return -1;
3264 m = (l + num_ifaces) / 2;
3265 if (interfaces_full [m] == ic)
3266 return m;
3267 if (l == num_ifaces)
3268 return -1;
3269 if (!interfaces_full [m] || interfaces_full [m]->interface_id > ic->interface_id) {
3270 num_ifaces = m - 1;
3271 } else {
3272 l = m + 1;
3277 static int
3278 find_interface_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic)
3280 int i = find_interface (num_ifaces, interfaces_full, ic);
3281 if (ic >= 0)
3282 return interface_offsets_full [i];
3283 return -1;
3286 static mono_bool
3287 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
3289 int i = find_interface (num_ifaces, interfaces_full, ic);
3290 if (i >= 0) {
3291 if (!force_set)
3292 return TRUE;
3293 interface_offsets_full [i] = offset;
3294 return FALSE;
3296 for (i = 0; i < num_ifaces; ++i) {
3297 if (interfaces_full [i]) {
3298 int end;
3299 if (interfaces_full [i]->interface_id < ic->interface_id)
3300 continue;
3301 end = i + 1;
3302 while (end < num_ifaces && interfaces_full [end]) end++;
3303 memmove (interfaces_full + i + 1, interfaces_full + i, sizeof (MonoClass*) * (end - i));
3304 memmove (interface_offsets_full + i + 1, interface_offsets_full + i, sizeof (int) * (end - i));
3306 interfaces_full [i] = ic;
3307 interface_offsets_full [i] = offset;
3308 break;
3310 return FALSE;
3313 #ifdef COMPRESSED_INTERFACE_BITMAP
3316 * Compressed interface bitmap design.
3318 * Interface bitmaps take a large amount of memory, because their size is
3319 * linear with the maximum interface id assigned in the process (each interface
3320 * is assigned a unique id as it is loaded). The number of interface classes
3321 * is high because of the many implicit interfaces implemented by arrays (we'll
3322 * need to lazy-load them in the future).
3323 * Most classes implement a very small number of interfaces, so the bitmap is
3324 * sparse. This bitmap needs to be checked by interface casts, so access to the
3325 * needed bit must be fast and doable with few jit instructions.
3327 * The current compression format is as follows:
3328 * *) it is a sequence of one or more two-byte elements
3329 * *) the first byte in the element is the count of empty bitmap bytes
3330 * at the current bitmap position
3331 * *) the second byte in the element is an actual bitmap byte at the current
3332 * bitmap position
3334 * As an example, the following compressed bitmap bytes:
3335 * 0x07 0x01 0x00 0x7
3336 * correspond to the following bitmap:
3337 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
3339 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
3340 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
3341 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
3345 * mono_compress_bitmap:
3346 * @dest: destination buffer
3347 * @bitmap: bitmap buffer
3348 * @size: size of @bitmap in bytes
3350 * This is a mono internal function.
3351 * The @bitmap data is compressed into a format that is small but
3352 * still searchable in few instructions by the JIT and runtime.
3353 * The compressed data is stored in the buffer pointed to by the
3354 * @dest array. Passing a #NULL value for @dest allows to just compute
3355 * the size of the buffer.
3356 * This compression algorithm assumes the bits set in the bitmap are
3357 * few and far between, like in interface bitmaps.
3358 * Returns: the size of the compressed bitmap in bytes.
3361 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
3363 int numz = 0;
3364 int res = 0;
3365 const uint8_t *end = bitmap + size;
3366 while (bitmap < end) {
3367 if (*bitmap || numz == 255) {
3368 if (dest) {
3369 *dest++ = numz;
3370 *dest++ = *bitmap;
3372 res += 2;
3373 numz = 0;
3374 bitmap++;
3375 continue;
3377 bitmap++;
3378 numz++;
3380 if (numz) {
3381 res += 2;
3382 if (dest) {
3383 *dest++ = numz;
3384 *dest++ = 0;
3387 return res;
3391 * mono_class_interface_match:
3392 * @bitmap: a compressed bitmap buffer
3393 * @id: the index to check in the bitmap
3395 * This is a mono internal function.
3396 * Checks if a bit is set in a compressed interface bitmap. @id must
3397 * be already checked for being smaller than the maximum id encoded in the
3398 * bitmap.
3400 * Returns: a non-zero value if bit @id is set in the bitmap @bitmap,
3401 * #FALSE otherwise.
3404 mono_class_interface_match (const uint8_t *bitmap, int id)
3406 while (TRUE) {
3407 id -= bitmap [0] * 8;
3408 if (id < 8) {
3409 if (id < 0)
3410 return 0;
3411 return bitmap [1] & (1 << id);
3413 bitmap += 2;
3414 id -= 8;
3417 #endif
3420 * LOCKING: this is supposed to be called with the loader lock held.
3421 * Return -1 on failure and set exception_type
3423 static int
3424 setup_interface_offsets (MonoClass *class, int cur_slot, gboolean overwrite)
3426 MonoError error;
3427 MonoClass *k, *ic;
3428 int i, j, max_iid, num_ifaces;
3429 MonoClass **interfaces_full = NULL;
3430 int *interface_offsets_full = NULL;
3431 GPtrArray *ifaces;
3432 GPtrArray **ifaces_array = NULL;
3433 int interface_offsets_count;
3434 MonoClass **array_interfaces = NULL;
3435 int num_array_interfaces;
3436 int is_enumerator = FALSE;
3438 mono_class_setup_supertypes (class);
3440 * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator<T>
3441 * implicit interfaces have the property that they are assigned the same slot in the
3442 * vtables for compatible interfaces
3444 array_interfaces = get_implicit_generic_array_interfaces (class, &num_array_interfaces, &is_enumerator);
3446 /* compute maximum number of slots and maximum interface id */
3447 max_iid = 0;
3448 num_ifaces = num_array_interfaces; /* this can include duplicated ones */
3449 ifaces_array = g_new0 (GPtrArray *, class->idepth);
3450 for (j = 0; j < class->idepth; j++) {
3451 k = class->supertypes [j];
3452 num_ifaces += k->interface_count;
3453 for (i = 0; i < k->interface_count; i++) {
3454 ic = k->interfaces [i];
3456 if (!ic->inited)
3457 mono_class_init (ic);
3459 if (max_iid < ic->interface_id)
3460 max_iid = ic->interface_id;
3462 ifaces = mono_class_get_implemented_interfaces (k, &error);
3463 if (!mono_error_ok (&error)) {
3464 char *name = mono_type_get_full_name (k);
3465 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error)));
3466 g_free (name);
3467 mono_error_cleanup (&error);
3468 cur_slot = -1;
3469 goto end;
3471 if (ifaces) {
3472 num_ifaces += ifaces->len;
3473 for (i = 0; i < ifaces->len; ++i) {
3474 ic = g_ptr_array_index (ifaces, i);
3475 if (max_iid < ic->interface_id)
3476 max_iid = ic->interface_id;
3478 ifaces_array [j] = ifaces;
3482 for (i = 0; i < num_array_interfaces; ++i) {
3483 ic = array_interfaces [i];
3484 mono_class_init (ic);
3485 if (max_iid < ic->interface_id)
3486 max_iid = ic->interface_id;
3489 if (MONO_CLASS_IS_INTERFACE (class)) {
3490 num_ifaces++;
3491 if (max_iid < class->interface_id)
3492 max_iid = class->interface_id;
3494 class->max_interface_id = max_iid;
3495 /* compute vtable offset for interfaces */
3496 interfaces_full = g_malloc0 (sizeof (MonoClass*) * num_ifaces);
3497 interface_offsets_full = g_malloc (sizeof (int) * num_ifaces);
3499 for (i = 0; i < num_ifaces; i++) {
3500 interface_offsets_full [i] = -1;
3503 /* skip the current class */
3504 for (j = 0; j < class->idepth - 1; j++) {
3505 k = class->supertypes [j];
3506 ifaces = ifaces_array [j];
3508 if (ifaces) {
3509 for (i = 0; i < ifaces->len; ++i) {
3510 int io;
3511 ic = g_ptr_array_index (ifaces, i);
3513 /*Force the sharing of interface offsets between parent and subtypes.*/
3514 io = mono_class_interface_offset (k, ic);
3515 g_assert (io >= 0);
3516 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
3521 g_assert (class == class->supertypes [class->idepth - 1]);
3522 ifaces = ifaces_array [class->idepth - 1];
3523 if (ifaces) {
3524 for (i = 0; i < ifaces->len; ++i) {
3525 int count;
3526 ic = g_ptr_array_index (ifaces, i);
3527 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
3528 continue;
3529 count = count_virtual_methods (ic);
3530 if (count == -1) {
3531 char *name = mono_type_get_full_name (ic);
3532 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error calculating interface offset of %s", name));
3533 g_free (name);
3534 cur_slot = -1;
3535 goto end;
3537 cur_slot += count;
3541 if (MONO_CLASS_IS_INTERFACE (class))
3542 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, class, cur_slot, TRUE);
3544 if (num_array_interfaces) {
3545 if (is_enumerator) {
3546 int ienumerator_idx = find_array_interface (class, "IEnumerator`1");
3547 int ienumerator_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, class->interfaces [ienumerator_idx]);
3548 g_assert (ienumerator_offset >= 0);
3549 for (i = 0; i < num_array_interfaces; ++i) {
3550 ic = array_interfaces [i];
3551 if (strcmp (ic->name, "IEnumerator`1") == 0)
3552 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, ienumerator_offset, TRUE);
3553 else
3554 g_assert_not_reached ();
3555 /*g_print ("type %s has %s offset at %d (%s)\n", class->name, ic->name, interface_offsets_full [ic->interface_id], class->interfaces [0]->name);*/
3557 } else {
3558 int ilist_offset, icollection_offset, ienumerable_offset, ireadonlylist_offset, ireadonlycollection_offset;
3559 int ilist_iface_idx = find_array_interface (class, "IList`1");
3560 MonoClass* ilist_class = class->interfaces [ilist_iface_idx];
3561 int ireadonlylist_iface_idx = find_array_interface (class, "IReadOnlyList`1");
3562 MonoClass* ireadonlylist_class = ireadonlylist_iface_idx != -1 ? class->interfaces [ireadonlylist_iface_idx] : NULL;
3563 int icollection_iface_idx = find_array_interface (ilist_class, "ICollection`1");
3564 int ienumerable_iface_idx = find_array_interface (ilist_class, "IEnumerable`1");
3565 int ireadonlycollection_iface_idx = ireadonlylist_iface_idx != -1 ? find_array_interface (ireadonlylist_class, "IReadOnlyCollection`1") : -1;
3566 ilist_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, class->interfaces [ilist_iface_idx]);
3567 icollection_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [icollection_iface_idx]);
3568 ienumerable_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [ienumerable_iface_idx]);
3569 ireadonlylist_offset = ireadonlylist_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, class->interfaces [ireadonlylist_iface_idx]) : -1;
3570 ireadonlycollection_offset = ireadonlycollection_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ireadonlylist_class->interfaces [ireadonlycollection_iface_idx]) : -1;
3571 g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0);
3572 for (i = 0; i < num_array_interfaces; ++i) {
3573 int offset;
3574 ic = array_interfaces [i];
3575 if (ic->generic_class->container_class == mono_defaults.generic_ilist_class)
3576 offset = ilist_offset;
3577 else if (strcmp (ic->name, "ICollection`1") == 0)
3578 offset = icollection_offset;
3579 else if (strcmp (ic->name, "IEnumerable`1") == 0)
3580 offset = ienumerable_offset;
3581 else if (strcmp (ic->name, "IReadOnlyList`1") == 0)
3582 offset = ireadonlylist_offset;
3583 else if (strcmp (ic->name, "IReadOnlyCollection`1") == 0)
3584 offset = ireadonlycollection_offset;
3585 else
3586 g_assert_not_reached ();
3587 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, offset, TRUE);
3588 /*g_print ("type %s has %s offset at %d (%s)\n", class->name, ic->name, offset, class->interfaces [0]->name);*/
3593 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
3594 if (interface_offsets_full [i] != -1) {
3595 interface_offsets_count ++;
3600 * We might get called multiple times:
3601 * - mono_class_init ()
3602 * - mono_class_setup_vtable ().
3603 * - mono_class_setup_interface_offsets ().
3604 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
3605 * means we have to overwrite those when called from other places (#4440).
3607 if (class->interfaces_packed && !overwrite) {
3608 g_assert (class->interface_offsets_count == interface_offsets_count);
3609 } else {
3610 uint8_t *bitmap;
3611 int bsize;
3612 class->interface_offsets_count = interface_offsets_count;
3613 class->interfaces_packed = mono_class_alloc (class, sizeof (MonoClass*) * interface_offsets_count);
3614 class->interface_offsets_packed = mono_class_alloc (class, sizeof (guint16) * interface_offsets_count);
3615 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
3616 #ifdef COMPRESSED_INTERFACE_BITMAP
3617 bitmap = g_malloc0 (bsize);
3618 #else
3619 bitmap = mono_class_alloc0 (class, bsize);
3620 #endif
3621 for (i = 0; i < interface_offsets_count; i++) {
3622 int id = interfaces_full [i]->interface_id;
3623 bitmap [id >> 3] |= (1 << (id & 7));
3624 class->interfaces_packed [i] = interfaces_full [i];
3625 class->interface_offsets_packed [i] = interface_offsets_full [i];
3626 /*if (num_array_interfaces)
3627 g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&class->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/
3629 #ifdef COMPRESSED_INTERFACE_BITMAP
3630 i = mono_compress_bitmap (NULL, bitmap, bsize);
3631 class->interface_bitmap = mono_class_alloc0 (class, i);
3632 mono_compress_bitmap (class->interface_bitmap, bitmap, bsize);
3633 g_free (bitmap);
3634 #else
3635 class->interface_bitmap = bitmap;
3636 #endif
3639 end:
3640 g_free (interfaces_full);
3641 g_free (interface_offsets_full);
3642 g_free (array_interfaces);
3643 for (i = 0; i < class->idepth; i++) {
3644 ifaces = ifaces_array [i];
3645 if (ifaces)
3646 g_ptr_array_free (ifaces, TRUE);
3648 g_free (ifaces_array);
3650 //printf ("JUST DONE: ");
3651 //print_implemented_interfaces (class);
3653 return cur_slot;
3657 * Setup interface offsets for interfaces.
3658 * Initializes:
3659 * - class->max_interface_id
3660 * - class->interface_offsets_count
3661 * - class->interfaces_packed
3662 * - class->interface_offsets_packed
3663 * - class->interface_bitmap
3665 * This function can fail @class.
3667 void
3668 mono_class_setup_interface_offsets (MonoClass *class)
3670 mono_loader_lock ();
3672 setup_interface_offsets (class, 0, FALSE);
3674 mono_loader_unlock ();
3677 /*Checks if @klass has @parent as one of it's parents type gtd
3679 * For example:
3680 * Foo<T>
3681 * Bar<T> : Foo<Bar<Bar<T>>>
3684 static gboolean
3685 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
3687 klass = mono_class_get_generic_type_definition (klass);
3688 parent = mono_class_get_generic_type_definition (parent);
3689 mono_class_setup_supertypes (klass);
3690 mono_class_setup_supertypes (parent);
3692 return klass->idepth >= parent->idepth &&
3693 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
3696 gboolean
3697 mono_class_check_vtable_constraints (MonoClass *class, GList *in_setup)
3699 MonoGenericInst *ginst;
3700 int i;
3701 if (!class->generic_class) {
3702 mono_class_setup_vtable_full (class, in_setup);
3703 return class->exception_type == 0;
3706 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (class), in_setup);
3707 if (class->generic_class->container_class->exception_type) {
3708 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to load generic definition vtable"));
3709 return FALSE;
3712 ginst = class->generic_class->context.class_inst;
3713 for (i = 0; i < ginst->type_argc; ++i) {
3714 MonoClass *arg;
3715 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
3716 continue;
3717 arg = mono_class_from_mono_type (ginst->type_argv [i]);
3718 /*Those 2 will be checked by mono_class_setup_vtable itself*/
3719 if (mono_class_has_gtd_parent (class, arg) || mono_class_has_gtd_parent (arg, class))
3720 continue;
3721 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
3722 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Failed to load generic parameter %d", i));
3723 return FALSE;
3726 return TRUE;
3730 * mono_class_setup_vtable:
3732 * Creates the generic vtable of CLASS.
3733 * Initializes the following fields in MonoClass:
3734 * - vtable
3735 * - vtable_size
3736 * Plus all the fields initialized by setup_interface_offsets ().
3737 * If there is an error during vtable construction, class->exception_type is set.
3739 * LOCKING: Acquires the loader lock.
3741 void
3742 mono_class_setup_vtable (MonoClass *class)
3744 mono_class_setup_vtable_full (class, NULL);
3747 static void
3748 mono_class_setup_vtable_full (MonoClass *class, GList *in_setup)
3750 MonoMethod **overrides;
3751 MonoGenericContext *context;
3752 guint32 type_token;
3753 int onum = 0;
3754 gboolean ok = TRUE;
3756 if (class->vtable)
3757 return;
3759 if (MONO_CLASS_IS_INTERFACE (class)) {
3760 /* This sets method->slot for all methods if this is an interface */
3761 mono_class_setup_methods (class);
3762 return;
3765 if (class->exception_type)
3766 return;
3768 if (g_list_find (in_setup, class))
3769 return;
3771 mono_loader_lock ();
3773 if (class->vtable) {
3774 mono_loader_unlock ();
3775 return;
3778 mono_stats.generic_vtable_count ++;
3779 in_setup = g_list_prepend (in_setup, class);
3781 if (class->generic_class) {
3782 if (!mono_class_check_vtable_constraints (class, in_setup)) {
3783 mono_loader_unlock ();
3784 g_list_remove (in_setup, class);
3785 return;
3788 context = mono_class_get_context (class);
3789 type_token = class->generic_class->container_class->type_token;
3790 } else {
3791 context = (MonoGenericContext *) class->generic_container;
3792 type_token = class->type_token;
3795 if (image_is_dynamic (class->image)) {
3796 /* Generic instances can have zero method overrides without causing any harm.
3797 * This is true since we don't do layout all over again for them, we simply inflate
3798 * the layout of the parent.
3800 mono_reflection_get_dynamic_overrides (class, &overrides, &onum);
3801 } else {
3802 /* The following call fails if there are missing methods in the type */
3803 /* FIXME it's probably a good idea to avoid this for generic instances. */
3804 ok = mono_class_get_overrides_full (class->image, type_token, &overrides, &onum, context);
3807 if (ok)
3808 mono_class_setup_vtable_general (class, overrides, onum, in_setup);
3809 else
3810 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not load list of method overrides"));
3812 g_free (overrides);
3814 mono_loader_unlock ();
3815 g_list_remove (in_setup, class);
3817 return;
3820 #define DEBUG_INTERFACE_VTABLE_CODE 0
3821 #define TRACE_INTERFACE_VTABLE_CODE 0
3822 #define VERIFY_INTERFACE_VTABLE_CODE 0
3823 #define VTABLE_SELECTOR (1)
3825 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3826 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
3827 if (!(VTABLE_SELECTOR)) break; \
3828 stmt;\
3829 } while (0)
3830 #else
3831 #define DEBUG_INTERFACE_VTABLE(stmt)
3832 #endif
3834 #if TRACE_INTERFACE_VTABLE_CODE
3835 #define TRACE_INTERFACE_VTABLE(stmt) do {\
3836 if (!(VTABLE_SELECTOR)) break; \
3837 stmt;\
3838 } while (0)
3839 #else
3840 #define TRACE_INTERFACE_VTABLE(stmt)
3841 #endif
3843 #if VERIFY_INTERFACE_VTABLE_CODE
3844 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
3845 if (!(VTABLE_SELECTOR)) break; \
3846 stmt;\
3847 } while (0)
3848 #else
3849 #define VERIFY_INTERFACE_VTABLE(stmt)
3850 #endif
3853 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3854 static char*
3855 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
3857 int i;
3858 char *result;
3859 GString *res = g_string_new ("");
3861 g_string_append_c (res, '(');
3862 for (i = 0; i < sig->param_count; ++i) {
3863 if (i > 0)
3864 g_string_append_c (res, ',');
3865 mono_type_get_desc (res, sig->params [i], include_namespace);
3867 g_string_append (res, ")=>");
3868 if (sig->ret != NULL) {
3869 mono_type_get_desc (res, sig->ret, include_namespace);
3870 } else {
3871 g_string_append (res, "NULL");
3873 result = res->str;
3874 g_string_free (res, FALSE);
3875 return result;
3877 static void
3878 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
3879 char *im_sig = mono_signature_get_full_desc (mono_method_signature (im), TRUE);
3880 char *cm_sig = mono_signature_get_full_desc (mono_method_signature (cm), TRUE);
3881 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
3882 g_free (im_sig);
3883 g_free (cm_sig);
3887 #endif
3888 static gboolean
3889 is_wcf_hack_disabled (void)
3891 static gboolean disabled;
3892 static gboolean inited = FALSE;
3893 if (!inited) {
3894 disabled = g_getenv ("MONO_DISABLE_WCF_HACK") != NULL;
3895 inited = TRUE;
3897 return disabled;
3900 static gboolean
3901 check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty, gboolean security_enabled) {
3902 MonoMethodSignature *cmsig, *imsig;
3903 if (strcmp (im->name, cm->name) == 0) {
3904 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
3905 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
3906 return FALSE;
3908 if (! slot_is_empty) {
3909 if (require_newslot) {
3910 if (! interface_is_explicitly_implemented_by_class) {
3911 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
3912 return FALSE;
3914 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
3915 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
3916 return FALSE;
3918 } else {
3919 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
3922 cmsig = mono_method_signature (cm);
3923 imsig = mono_method_signature (im);
3924 if (!cmsig || !imsig) {
3925 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
3926 return FALSE;
3929 if (! mono_metadata_signature_equal (cmsig, imsig)) {
3930 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
3931 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
3932 TRACE_INTERFACE_VTABLE (printf ("]"));
3933 return FALSE;
3935 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
3936 /* CAS - SecurityAction.InheritanceDemand on interface */
3937 if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
3938 mono_secman_inheritancedemand_method (cm, im);
3941 if (mono_security_core_clr_enabled ())
3942 mono_security_core_clr_check_override (class, cm, im);
3944 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
3945 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
3946 char *body_name = mono_method_full_name (cm, TRUE);
3947 char *decl_name = mono_method_full_name (im, TRUE);
3948 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
3949 g_free (body_name);
3950 g_free (decl_name);
3951 return FALSE;
3954 return TRUE;
3955 } else {
3956 MonoClass *ic = im->klass;
3957 const char *ic_name_space = ic->name_space;
3958 const char *ic_name = ic->name;
3959 char *subname;
3961 if (! require_newslot) {
3962 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
3963 return FALSE;
3965 if (cm->klass->rank == 0) {
3966 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
3967 return FALSE;
3969 cmsig = mono_method_signature (cm);
3970 imsig = mono_method_signature (im);
3971 if (!cmsig || !imsig) {
3972 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
3973 return FALSE;
3976 if (! mono_metadata_signature_equal (cmsig, imsig)) {
3977 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
3978 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
3979 TRACE_INTERFACE_VTABLE (printf ("]"));
3980 return FALSE;
3982 if (mono_class_get_image (ic) != mono_defaults.corlib) {
3983 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
3984 return FALSE;
3986 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
3987 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
3988 return FALSE;
3990 if ((ic_name == NULL) || ((strcmp (ic_name, "IEnumerable`1") != 0) && (strcmp (ic_name, "ICollection`1") != 0) && (strcmp (ic_name, "IList`1") != 0) && (strcmp (ic_name, "IReadOnlyList`1") != 0) && (strcmp (ic_name, "IReadOnlyCollection`1") != 0))) {
3991 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
3992 return FALSE;
3995 subname = strstr (cm->name, ic_name_space);
3996 if (subname != cm->name) {
3997 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
3998 return FALSE;
4000 subname += strlen (ic_name_space);
4001 if (subname [0] != '.') {
4002 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
4003 return FALSE;
4005 subname ++;
4006 if (strstr (subname, ic_name) != subname) {
4007 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
4008 return FALSE;
4010 subname += strlen (ic_name);
4011 if (subname [0] != '.') {
4012 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
4013 return FALSE;
4015 subname ++;
4016 if (strcmp (subname, im->name) != 0) {
4017 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
4018 return FALSE;
4021 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
4022 /* CAS - SecurityAction.InheritanceDemand on interface */
4023 if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
4024 mono_secman_inheritancedemand_method (cm, im);
4027 if (mono_security_core_clr_enabled ())
4028 mono_security_core_clr_check_override (class, cm, im);
4030 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
4031 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
4032 char *body_name = mono_method_full_name (cm, TRUE);
4033 char *decl_name = mono_method_full_name (im, TRUE);
4034 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
4035 g_free (body_name);
4036 g_free (decl_name);
4037 return FALSE;
4040 return TRUE;
4044 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
4045 static void
4046 foreach_override (gpointer key, gpointer value, gpointer user_data) {
4047 MonoMethod *method = key;
4048 MonoMethod *override = value;
4049 MonoClass *method_class = mono_method_get_class (method);
4050 MonoClass *override_class = mono_method_get_class (override);
4052 printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
4053 mono_class_get_namespace (method_class), mono_class_get_name (method_class), mono_method_get_name (method),
4054 mono_class_get_namespace (override_class), mono_class_get_name (override_class), mono_method_get_name (override));
4056 static void
4057 print_overrides (GHashTable *override_map, const char *message) {
4058 if (override_map) {
4059 printf ("Override map \"%s\" START:\n", message);
4060 g_hash_table_foreach (override_map, foreach_override, NULL);
4061 printf ("Override map \"%s\" END.\n", message);
4062 } else {
4063 printf ("Override map \"%s\" EMPTY.\n", message);
4066 static void
4067 print_vtable_full (MonoClass *class, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
4068 char *full_name = mono_type_full_name (&class->byval_arg);
4069 int i;
4070 int parent_size;
4072 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
4074 if (print_interfaces) {
4075 print_implemented_interfaces (class);
4076 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
4079 if (class->parent) {
4080 parent_size = class->parent->vtable_size;
4081 } else {
4082 parent_size = 0;
4084 for (i = 0; i < size; ++i) {
4085 MonoMethod *cm = vtable [i];
4086 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
4087 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
4089 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
4090 g_free (cm_name);
4093 g_free (full_name);
4095 #endif
4097 #if VERIFY_INTERFACE_VTABLE_CODE
4098 static int
4099 mono_method_try_get_vtable_index (MonoMethod *method)
4101 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
4102 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
4103 if (imethod->declaring->is_generic)
4104 return imethod->declaring->slot;
4106 return method->slot;
4109 static void
4110 mono_class_verify_vtable (MonoClass *class)
4112 int i;
4113 char *full_name = mono_type_full_name (&class->byval_arg);
4115 printf ("*** Verifying VTable of class '%s' \n", full_name);
4116 g_free (full_name);
4117 full_name = NULL;
4119 if (!class->methods)
4120 return;
4122 for (i = 0; i < class->method.count; ++i) {
4123 MonoMethod *cm = class->methods [i];
4124 int slot;
4126 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
4127 continue;
4129 g_free (full_name);
4130 full_name = mono_method_full_name (cm, TRUE);
4132 slot = mono_method_try_get_vtable_index (cm);
4133 if (slot >= 0) {
4134 if (slot >= class->vtable_size) {
4135 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, class->vtable_size);
4136 continue;
4139 if (slot >= 0 && class->vtable [slot] != cm && (class->vtable [slot])) {
4140 char *other_name = class->vtable [slot] ? mono_method_full_name (class->vtable [slot], TRUE) : g_strdup ("[null value]");
4141 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
4142 g_free (other_name);
4144 } else
4145 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
4147 g_free (full_name);
4149 #endif
4151 static void
4152 print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) {
4153 int index;
4154 char *method_signature;
4155 char *type_name;
4157 for (index = 0; index < onum; ++index) {
4158 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name,
4159 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
4161 method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
4162 type_name = mono_type_full_name (&class->byval_arg);
4163 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s\n",
4164 mono_type_get_name (&ic->byval_arg), im->name, method_signature, type_name);
4165 g_free (method_signature);
4166 g_free (type_name);
4167 mono_class_setup_methods (class);
4168 if (class->exception_type) {
4169 char *name = mono_type_get_full_name (class);
4170 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods\n", name);
4171 g_free (name);
4172 return;
4174 for (index = 0; index < class->method.count; ++index) {
4175 MonoMethod *cm = class->methods [index];
4176 method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
4178 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)\n", cm->name, method_signature);
4179 g_free (method_signature);
4183 static MonoMethod*
4184 mono_method_get_method_definition (MonoMethod *method)
4186 while (method->is_inflated)
4187 method = ((MonoMethodInflated*)method)->declaring;
4188 return method;
4191 static gboolean
4192 verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum)
4194 int i;
4196 for (i = 0; i < onum; ++i) {
4197 MonoMethod *decl = overrides [i * 2];
4198 MonoMethod *body = overrides [i * 2 + 1];
4200 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (class)) {
4201 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method belongs to a different class than the declared one"));
4202 return FALSE;
4205 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
4206 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4207 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must not be static to override a base type"));
4208 else
4209 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must be virtual to override a base type"));
4210 return FALSE;
4213 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
4214 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4215 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type"));
4216 else
4217 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type"));
4218 return FALSE;
4221 if (!mono_class_is_assignable_from_slow (decl->klass, class)) {
4222 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that extended or implemented by this type"));
4223 return FALSE;
4226 body = mono_method_get_method_definition (body);
4227 decl = mono_method_get_method_definition (decl);
4229 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
4230 char *body_name = mono_method_full_name (body, TRUE);
4231 char *decl_name = mono_method_full_name (decl, TRUE);
4232 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
4233 g_free (body_name);
4234 g_free (decl_name);
4235 return FALSE;
4238 return TRUE;
4241 static gboolean
4242 mono_class_need_stelemref_method (MonoClass *class)
4244 return class->rank == 1 && MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg);
4248 * LOCKING: this is supposed to be called with the loader lock held.
4250 void
4251 mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int onum, GList *in_setup)
4253 MonoError error;
4254 MonoClass *k, *ic;
4255 MonoMethod **vtable;
4256 int i, max_vtsize = 0, max_iid, cur_slot = 0;
4257 GPtrArray *ifaces = NULL;
4258 GHashTable *override_map = NULL;
4259 gboolean security_enabled = mono_security_enabled ();
4260 MonoMethod *cm;
4261 gpointer class_iter;
4262 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
4263 int first_non_interface_slot;
4264 #endif
4265 GSList *virt_methods = NULL, *l;
4266 int stelemref_slot = 0;
4268 if (class->vtable)
4269 return;
4271 if (overrides && !verify_class_overrides (class, overrides, onum))
4272 return;
4274 ifaces = mono_class_get_implemented_interfaces (class, &error);
4275 if (!mono_error_ok (&error)) {
4276 char *name = mono_type_get_full_name (class);
4277 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error)));
4278 g_free (name);
4279 mono_error_cleanup (&error);
4280 return;
4281 } else if (ifaces) {
4282 for (i = 0; i < ifaces->len; i++) {
4283 MonoClass *ic = g_ptr_array_index (ifaces, i);
4284 max_vtsize += ic->method.count;
4286 g_ptr_array_free (ifaces, TRUE);
4287 ifaces = NULL;
4290 if (class->parent) {
4291 mono_class_init (class->parent);
4292 mono_class_setup_vtable_full (class->parent, in_setup);
4294 if (class->parent->exception_type) {
4295 char *name = mono_type_get_full_name (class->parent);
4296 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Parent %s failed to load", name));
4297 g_free (name);
4298 return;
4301 max_vtsize += class->parent->vtable_size;
4302 cur_slot = class->parent->vtable_size;
4305 max_vtsize += class->method.count;
4307 /*Array have a slot for stelemref*/
4308 if (mono_class_need_stelemref_method (class)) {
4309 stelemref_slot = cur_slot;
4310 ++max_vtsize;
4311 ++cur_slot;
4314 vtable = alloca (sizeof (gpointer) * max_vtsize);
4315 memset (vtable, 0, sizeof (gpointer) * max_vtsize);
4317 /* printf ("METAINIT %s.%s\n", class->name_space, class->name); */
4319 cur_slot = setup_interface_offsets (class, cur_slot, TRUE);
4320 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
4321 return;
4323 max_iid = class->max_interface_id;
4324 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
4326 /* Optimized version for generic instances */
4327 if (class->generic_class) {
4328 MonoError error;
4329 MonoClass *gklass = class->generic_class->container_class;
4330 MonoMethod **tmp;
4332 mono_class_setup_vtable_full (gklass, in_setup);
4333 if (gklass->exception_type != MONO_EXCEPTION_NONE) {
4334 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
4335 return;
4338 tmp = mono_class_alloc0 (class, sizeof (gpointer) * gklass->vtable_size);
4339 class->vtable_size = gklass->vtable_size;
4340 for (i = 0; i < gklass->vtable_size; ++i)
4341 if (gklass->vtable [i]) {
4342 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], class, mono_class_get_context (class), &error);
4343 if (!mono_error_ok (&error)) {
4344 char *err_msg = g_strdup_printf ("Could not inflate method due to %s", mono_error_get_message (&error));
4345 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
4346 g_free (err_msg);
4347 mono_error_cleanup (&error);
4348 return;
4350 tmp [i] = inflated;
4351 tmp [i]->slot = gklass->vtable [i]->slot;
4353 mono_memory_barrier ();
4354 class->vtable = tmp;
4356 /* Have to set method->slot for abstract virtual methods */
4357 if (class->methods && gklass->methods) {
4358 for (i = 0; i < class->method.count; ++i)
4359 if (class->methods [i]->slot == -1)
4360 class->methods [i]->slot = gklass->methods [i]->slot;
4363 return;
4366 if (class->parent && class->parent->vtable_size) {
4367 MonoClass *parent = class->parent;
4368 int i;
4370 memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
4372 // Also inherit parent interface vtables, just as a starting point.
4373 // This is needed otherwise bug-77127.exe fails when the property methods
4374 // have different names in the iterface and the class, because for child
4375 // classes the ".override" information is not used anymore.
4376 for (i = 0; i < parent->interface_offsets_count; i++) {
4377 MonoClass *parent_interface = parent->interfaces_packed [i];
4378 int interface_offset = mono_class_interface_offset (class, parent_interface);
4379 /*FIXME this is now dead code as this condition will never hold true.
4380 Since interface offsets are inherited then the offset of an interface implemented
4381 by a parent will never be the out of it's vtable boundary.
4383 if (interface_offset >= parent->vtable_size) {
4384 int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
4385 int j;
4387 mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
4388 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
4389 for (j = 0; j < parent_interface->method.count && !class->exception_type; j++) {
4390 vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
4391 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
4392 parent_interface_offset + j, parent_interface_offset, j,
4393 interface_offset + j, interface_offset, j));
4400 /*Array have a slot for stelemref*/
4401 if (mono_class_need_stelemref_method (class)) {
4402 MonoMethod *method = mono_marshal_get_virtual_stelemref (class);
4403 if (!method->slot)
4404 method->slot = stelemref_slot;
4405 else
4406 g_assert (method->slot == stelemref_slot);
4408 vtable [stelemref_slot] = method;
4411 TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
4412 /* override interface methods */
4413 for (i = 0; i < onum; i++) {
4414 MonoMethod *decl = overrides [i*2];
4415 if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
4416 int dslot;
4417 dslot = mono_method_get_vtable_slot (decl);
4418 if (dslot == -1) {
4419 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
4420 return;
4423 dslot += mono_class_interface_offset (class, decl->klass);
4424 vtable [dslot] = overrides [i*2 + 1];
4425 vtable [dslot]->slot = dslot;
4426 if (!override_map)
4427 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4429 g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
4431 if (mono_security_core_clr_enabled ())
4432 mono_security_core_clr_check_override (class, vtable [dslot], decl);
4435 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
4436 TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
4439 * Create a list of virtual methods to avoid calling
4440 * mono_class_get_virtual_methods () which is slow because of the metadata
4441 * optimization.
4444 gpointer iter = NULL;
4445 MonoMethod *cm;
4447 virt_methods = NULL;
4448 while ((cm = mono_class_get_virtual_methods (class, &iter))) {
4449 virt_methods = g_slist_prepend (virt_methods, cm);
4451 if (class->exception_type)
4452 goto fail;
4455 // Loop on all implemented interfaces...
4456 for (i = 0; i < class->interface_offsets_count; i++) {
4457 MonoClass *parent = class->parent;
4458 int ic_offset;
4459 gboolean interface_is_explicitly_implemented_by_class;
4460 int im_index;
4462 ic = class->interfaces_packed [i];
4463 ic_offset = mono_class_interface_offset (class, ic);
4465 mono_class_setup_methods (ic);
4466 if (ic->exception_type)
4467 goto fail;
4469 // Check if this interface is explicitly implemented (instead of just inherited)
4470 if (parent != NULL) {
4471 int implemented_interfaces_index;
4472 interface_is_explicitly_implemented_by_class = FALSE;
4473 for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) {
4474 if (ic == class->interfaces [implemented_interfaces_index]) {
4475 interface_is_explicitly_implemented_by_class = TRUE;
4476 break;
4479 } else {
4480 interface_is_explicitly_implemented_by_class = TRUE;
4483 // Loop on all interface methods...
4484 for (im_index = 0; im_index < ic->method.count; im_index++) {
4485 MonoMethod *im = ic->methods [im_index];
4486 int im_slot = ic_offset + im->slot;
4487 MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL;
4489 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4490 continue;
4492 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
4494 // If there is an explicit implementation, just use it right away,
4495 // otherwise look for a matching method
4496 if (override_im == NULL) {
4497 int cm_index;
4498 gpointer iter;
4499 MonoMethod *cm;
4501 // First look for a suitable method among the class methods
4502 iter = NULL;
4503 for (l = virt_methods; l; l = l->next) {
4504 cm = l->data;
4505 TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
4506 if (check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) {
4507 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
4508 vtable [im_slot] = cm;
4509 /* Why do we need this? */
4510 if (cm->slot < 0) {
4511 cm->slot = im_slot;
4514 TRACE_INTERFACE_VTABLE (printf ("\n"));
4515 if (class->exception_type) /*Might be set by check_interface_method_override*/
4516 goto fail;
4519 // If the slot is still empty, look in all the inherited virtual methods...
4520 if ((vtable [im_slot] == NULL) && class->parent != NULL) {
4521 MonoClass *parent = class->parent;
4522 // Reverse order, so that last added methods are preferred
4523 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
4524 MonoMethod *cm = parent->vtable [cm_index];
4526 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
4527 if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) {
4528 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
4529 vtable [im_slot] = cm;
4530 /* Why do we need this? */
4531 if (cm->slot < 0) {
4532 cm->slot = im_slot;
4534 break;
4536 if (class->exception_type) /*Might be set by check_interface_method_override*/
4537 goto fail;
4538 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
4541 } else {
4542 g_assert (vtable [im_slot] == override_im);
4547 // If the class is not abstract, check that all its interface slots are full.
4548 // The check is done here and not directly at the end of the loop above because
4549 // it can happen (for injected generic array interfaces) that the same slot is
4550 // processed multiple times (those interfaces have overlapping slots), and it
4551 // will not always be the first pass the one that fills the slot.
4552 if (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
4553 for (i = 0; i < class->interface_offsets_count; i++) {
4554 int ic_offset;
4555 int im_index;
4557 ic = class->interfaces_packed [i];
4558 ic_offset = mono_class_interface_offset (class, ic);
4560 for (im_index = 0; im_index < ic->method.count; im_index++) {
4561 MonoMethod *im = ic->methods [im_index];
4562 int im_slot = ic_offset + im->slot;
4564 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4565 continue;
4567 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
4568 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
4569 if (vtable [im_slot] == NULL) {
4570 print_unimplemented_interface_method_info (class, ic, im, im_slot, overrides, onum);
4571 goto fail;
4577 TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
4578 class_iter = NULL;
4579 for (l = virt_methods; l; l = l->next) {
4580 cm = l->data;
4582 * If the method is REUSE_SLOT, we must check in the
4583 * base class for a method to override.
4585 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
4586 int slot = -1;
4587 for (k = class->parent; k ; k = k->parent) {
4588 gpointer k_iter;
4589 MonoMethod *m1;
4591 k_iter = NULL;
4592 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
4593 MonoMethodSignature *cmsig, *m1sig;
4595 cmsig = mono_method_signature (cm);
4596 m1sig = mono_method_signature (m1);
4598 if (!cmsig || !m1sig) {
4599 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
4600 return;
4603 if (!strcmp(cm->name, m1->name) &&
4604 mono_metadata_signature_equal (cmsig, m1sig)) {
4606 /* CAS - SecurityAction.InheritanceDemand */
4607 if (security_enabled && (m1->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
4608 mono_secman_inheritancedemand_method (cm, m1);
4611 if (mono_security_core_clr_enabled ())
4612 mono_security_core_clr_check_override (class, cm, m1);
4614 slot = mono_method_get_vtable_slot (m1);
4615 if (slot == -1)
4616 goto fail;
4618 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
4619 char *body_name = mono_method_full_name (cm, TRUE);
4620 char *decl_name = mono_method_full_name (m1, TRUE);
4621 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
4622 g_free (body_name);
4623 g_free (decl_name);
4624 goto fail;
4627 g_assert (cm->slot < max_vtsize);
4628 if (!override_map)
4629 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4630 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
4631 mono_method_full_name (m1, 1), m1,
4632 mono_method_full_name (cm, 1), cm));
4633 g_hash_table_insert (override_map, m1, cm);
4634 break;
4637 if (k->exception_type)
4638 goto fail;
4640 if (slot >= 0)
4641 break;
4643 if (slot >= 0)
4644 cm->slot = slot;
4647 /*Non final newslot methods must be given a non-interface vtable slot*/
4648 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
4649 cm->slot = -1;
4651 if (cm->slot < 0)
4652 cm->slot = cur_slot++;
4654 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
4655 vtable [cm->slot] = cm;
4658 /* override non interface methods */
4659 for (i = 0; i < onum; i++) {
4660 MonoMethod *decl = overrides [i*2];
4661 if (!MONO_CLASS_IS_INTERFACE (decl->klass)) {
4662 g_assert (decl->slot != -1);
4663 vtable [decl->slot] = overrides [i*2 + 1];
4664 overrides [i * 2 + 1]->slot = decl->slot;
4665 if (!override_map)
4666 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4667 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
4668 mono_method_full_name (decl, 1), decl,
4669 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
4670 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
4672 if (mono_security_core_clr_enabled ())
4673 mono_security_core_clr_check_override (class, vtable [decl->slot], decl);
4678 * If a method occupies more than one place in the vtable, and it is
4679 * overriden, then change the other occurances too.
4681 if (override_map) {
4682 MonoMethod *cm;
4684 for (i = 0; i < max_vtsize; ++i)
4685 if (vtable [i]) {
4686 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
4688 cm = g_hash_table_lookup (override_map, vtable [i]);
4689 if (cm)
4690 vtable [i] = cm;
4693 g_hash_table_destroy (override_map);
4694 override_map = NULL;
4697 g_slist_free (virt_methods);
4698 virt_methods = NULL;
4700 /* Ensure that all vtable slots are filled with concrete instance methods */
4701 if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
4702 for (i = 0; i < cur_slot; ++i) {
4703 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
4704 char *type_name = mono_type_get_full_name (class);
4705 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
4706 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name));
4707 g_free (type_name);
4708 g_free (method_name);
4709 return;
4714 if (class->generic_class) {
4715 MonoClass *gklass = class->generic_class->container_class;
4717 mono_class_init (gklass);
4719 class->vtable_size = MAX (gklass->vtable_size, cur_slot);
4720 } else {
4721 /* Check that the vtable_size value computed in mono_class_init () is correct */
4722 if (class->vtable_size)
4723 g_assert (cur_slot == class->vtable_size);
4724 class->vtable_size = cur_slot;
4727 /* Try to share the vtable with our parent. */
4728 if (class->parent && (class->parent->vtable_size == class->vtable_size) && (memcmp (class->parent->vtable, vtable, sizeof (gpointer) * class->vtable_size) == 0)) {
4729 mono_memory_barrier ();
4730 class->vtable = class->parent->vtable;
4731 } else {
4732 MonoMethod **tmp = mono_class_alloc0 (class, sizeof (gpointer) * class->vtable_size);
4733 memcpy (tmp, vtable, sizeof (gpointer) * class->vtable_size);
4734 mono_memory_barrier ();
4735 class->vtable = tmp;
4738 DEBUG_INTERFACE_VTABLE (print_vtable_full (class, class->vtable, class->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
4739 if (mono_print_vtable) {
4740 int icount = 0;
4742 print_implemented_interfaces (class);
4744 for (i = 0; i <= max_iid; i++)
4745 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, i))
4746 icount++;
4748 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&class->byval_arg),
4749 class->vtable_size, icount);
4751 for (i = 0; i < cur_slot; ++i) {
4752 MonoMethod *cm;
4754 cm = vtable [i];
4755 if (cm) {
4756 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
4757 mono_method_full_name (cm, TRUE));
4762 if (icount) {
4763 printf ("Interfaces %s.%s (max_iid = %d)\n", class->name_space,
4764 class->name, max_iid);
4766 for (i = 0; i < class->interface_count; i++) {
4767 ic = class->interfaces [i];
4768 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
4769 mono_class_interface_offset (class, ic),
4770 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4773 for (k = class->parent; k ; k = k->parent) {
4774 for (i = 0; i < k->interface_count; i++) {
4775 ic = k->interfaces [i];
4776 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
4777 mono_class_interface_offset (class, ic),
4778 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4784 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (class));
4785 return;
4787 fail:
4789 char *name = mono_type_get_full_name (class);
4790 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("VTable setup of type %s failed", name));
4791 g_free (name);
4792 if (override_map)
4793 g_hash_table_destroy (override_map);
4794 if (virt_methods)
4795 g_slist_free (virt_methods);
4800 * mono_method_get_vtable_slot:
4802 * Returns method->slot, computing it if neccesary. Return -1 on failure.
4803 * LOCKING: Acquires the loader lock.
4805 * FIXME Use proper MonoError machinery here.
4808 mono_method_get_vtable_slot (MonoMethod *method)
4810 if (method->slot == -1) {
4811 mono_class_setup_vtable (method->klass);
4812 if (method->klass->exception_type)
4813 return -1;
4814 if (method->slot == -1) {
4815 MonoClass *gklass;
4816 int i;
4818 /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
4819 g_assert (method->klass->generic_class);
4820 gklass = method->klass->generic_class->container_class;
4821 mono_class_setup_methods (method->klass);
4822 g_assert (method->klass->methods);
4823 for (i = 0; i < method->klass->method.count; ++i) {
4824 if (method->klass->methods [i] == method)
4825 break;
4827 g_assert (i < method->klass->method.count);
4828 g_assert (gklass->methods);
4829 method->slot = gklass->methods [i]->slot;
4831 g_assert (method->slot != -1);
4833 return method->slot;
4837 * mono_method_get_vtable_index:
4838 * @method: a method
4840 * Returns the index into the runtime vtable to access the method or,
4841 * in the case of a virtual generic method, the virtual generic method
4842 * thunk. Returns -1 on failure.
4844 * FIXME Use proper MonoError machinery here.
4847 mono_method_get_vtable_index (MonoMethod *method)
4849 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
4850 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
4851 if (imethod->declaring->is_generic)
4852 return mono_method_get_vtable_slot (imethod->declaring);
4854 return mono_method_get_vtable_slot (method);
4857 static MonoMethod *default_ghc = NULL;
4858 static MonoMethod *default_finalize = NULL;
4859 static int finalize_slot = -1;
4860 static int ghc_slot = -1;
4862 static void
4863 initialize_object_slots (MonoClass *class)
4865 int i;
4866 if (default_ghc)
4867 return;
4868 if (class == mono_defaults.object_class) {
4869 mono_class_setup_vtable (class);
4870 for (i = 0; i < class->vtable_size; ++i) {
4871 MonoMethod *cm = class->vtable [i];
4873 if (!strcmp (cm->name, "GetHashCode"))
4874 ghc_slot = i;
4875 else if (!strcmp (cm->name, "Finalize"))
4876 finalize_slot = i;
4879 g_assert (ghc_slot > 0);
4880 default_ghc = class->vtable [ghc_slot];
4882 g_assert (finalize_slot > 0);
4883 default_finalize = class->vtable [finalize_slot];
4887 typedef struct {
4888 MonoMethod *array_method;
4889 char *name;
4890 } GenericArrayMethodInfo;
4892 static int generic_array_method_num = 0;
4893 static GenericArrayMethodInfo *generic_array_method_info = NULL;
4895 static int
4896 generic_array_methods (MonoClass *class)
4898 int i, count_generic = 0;
4899 GList *list = NULL, *tmp;
4900 if (generic_array_method_num)
4901 return generic_array_method_num;
4902 mono_class_setup_methods (class->parent); /*This is setting up System.Array*/
4903 g_assert (!class->parent->exception_type); /*So hitting this assert is a huge problem*/
4904 for (i = 0; i < class->parent->method.count; i++) {
4905 MonoMethod *m = class->parent->methods [i];
4906 if (!strncmp (m->name, "InternalArray__", 15)) {
4907 count_generic++;
4908 list = g_list_prepend (list, m);
4911 list = g_list_reverse (list);
4912 generic_array_method_info = mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
4913 i = 0;
4914 for (tmp = list; tmp; tmp = tmp->next) {
4915 const char *mname, *iname;
4916 gchar *name;
4917 MonoMethod *m = tmp->data;
4918 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
4919 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
4921 generic_array_method_info [i].array_method = m;
4922 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
4923 iname = "System.Collections.Generic.ICollection`1.";
4924 mname = m->name + 27;
4925 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
4926 iname = "System.Collections.Generic.IEnumerable`1.";
4927 mname = m->name + 27;
4928 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
4929 iname = "System.Collections.Generic.IReadOnlyList`1.";
4930 mname = m->name + strlen (ireadonlylist_prefix);
4931 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
4932 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
4933 mname = m->name + strlen (ireadonlycollection_prefix);
4934 } else if (!strncmp (m->name, "InternalArray__", 15)) {
4935 iname = "System.Collections.Generic.IList`1.";
4936 mname = m->name + 15;
4937 } else {
4938 g_assert_not_reached ();
4941 name = mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
4942 strcpy (name, iname);
4943 strcpy (name + strlen (iname), mname);
4944 generic_array_method_info [i].name = name;
4945 i++;
4947 /*g_print ("array generic methods: %d\n", count_generic);*/
4949 generic_array_method_num = count_generic;
4950 g_list_free (list);
4951 return generic_array_method_num;
4954 static void
4955 setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos)
4957 MonoGenericContext tmp_context;
4958 int i;
4960 tmp_context.class_inst = NULL;
4961 tmp_context.method_inst = iface->generic_class->context.class_inst;
4962 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
4964 for (i = 0; i < generic_array_method_num; i++) {
4965 MonoError error;
4966 MonoMethod *m = generic_array_method_info [i].array_method;
4967 MonoMethod *inflated;
4969 inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, &error);
4970 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
4971 methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, generic_array_method_info [i].name, inflated);
4975 static char*
4976 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
4978 int null_length = strlen ("(null)");
4979 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
4980 char *s = mono_image_alloc (image, len);
4981 int result;
4983 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
4984 g_assert (result == len - 1);
4986 return s;
4989 static void
4990 set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error)
4992 gpointer exception_data = NULL;
4994 switch (error->exception_type) {
4995 case MONO_EXCEPTION_TYPE_LOAD:
4996 exception_data = concat_two_strings_with_zero (class->image, error->class_name, error->assembly_name);
4997 break;
4999 case MONO_EXCEPTION_MISSING_METHOD:
5000 exception_data = concat_two_strings_with_zero (class->image, error->class_name, error->member_name);
5001 break;
5003 case MONO_EXCEPTION_MISSING_FIELD: {
5004 const char *name_space = error->klass->name_space ? error->klass->name_space : NULL;
5005 const char *class_name;
5007 if (name_space)
5008 class_name = g_strdup_printf ("%s.%s", name_space, error->klass->name);
5009 else
5010 class_name = error->klass->name;
5012 exception_data = concat_two_strings_with_zero (class->image, class_name, error->member_name);
5014 if (name_space)
5015 g_free ((void*)class_name);
5016 break;
5019 case MONO_EXCEPTION_FILE_NOT_FOUND: {
5020 const char *msg;
5022 if (error->ref_only)
5023 msg = "Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.";
5024 else
5025 msg = "Could not load file or assembly '%s' or one of its dependencies.";
5027 exception_data = concat_two_strings_with_zero (class->image, msg, error->assembly_name);
5028 break;
5031 case MONO_EXCEPTION_BAD_IMAGE:
5032 exception_data = error->msg;
5033 break;
5035 default :
5036 g_assert_not_reached ();
5039 mono_class_set_failure (class, error->exception_type, exception_data);
5043 * mono_class_init:
5044 * @class: the class to initialize
5046 * Compute the instance_size, class_size and other infos that cannot be
5047 * computed at mono_class_get() time. Also compute vtable_size if possible.
5048 * Returns TRUE on success or FALSE if there was a problem in loading
5049 * the type (incorrect assemblies, missing assemblies, methods, etc).
5051 * LOCKING: Acquires the loader lock.
5053 gboolean
5054 mono_class_init (MonoClass *class)
5056 int i;
5057 MonoCachedClassInfo cached_info;
5058 gboolean has_cached_info;
5060 g_assert (class);
5062 /* Double-checking locking pattern */
5063 if (class->inited || class->exception_type)
5064 return class->exception_type == MONO_EXCEPTION_NONE;
5066 /*g_print ("Init class %s\n", mono_type_get_full_name (class));*/
5068 /* We do everything inside the lock to prevent races */
5069 mono_loader_lock ();
5071 if (class->inited || class->exception_type) {
5072 mono_loader_unlock ();
5073 /* Somebody might have gotten in before us */
5074 return class->exception_type == MONO_EXCEPTION_NONE;
5077 if (class->init_pending) {
5078 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Recursive type definition detected"));
5079 goto leave;
5082 class->init_pending = 1;
5084 if (mono_verifier_is_enabled_for_class (class) && !mono_verifier_verify_class (class)) {
5085 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, concat_two_strings_with_zero (class->image, class->name, class->image->assembly_name));
5086 goto leave;
5090 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
5091 MonoClass *element_class = class->element_class;
5092 if (!element_class->inited)
5093 mono_class_init (element_class);
5094 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
5095 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5096 goto leave;
5100 /* CAS - SecurityAction.InheritanceDemand */
5101 if (mono_security_enabled () && class->parent && (class->parent->flags & TYPE_ATTRIBUTE_HAS_SECURITY)) {
5102 mono_secman_inheritancedemand_class (class, class->parent);
5105 mono_stats.initialized_class_count++;
5107 if (class->generic_class && !class->generic_class->is_dynamic) {
5108 MonoClass *gklass = class->generic_class->container_class;
5110 mono_stats.generic_class_count++;
5112 class->method = gklass->method;
5113 class->field = gklass->field;
5115 mono_class_init (gklass);
5116 // FIXME: Why is this needed ?
5117 if (!gklass->exception_type)
5118 mono_class_setup_methods (gklass);
5119 if (gklass->exception_type) {
5120 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic Type Defintion failed to init"));
5121 goto leave;
5124 if (MONO_CLASS_IS_INTERFACE (class))
5125 class->interface_id = mono_get_unique_iid (class);
5128 if (class->parent && !class->parent->inited)
5129 mono_class_init (class->parent);
5131 has_cached_info = mono_class_get_cached_class_info (class, &cached_info);
5133 if (class->generic_class || image_is_dynamic (class->image) || !class->type_token || (has_cached_info && !cached_info.has_nested_classes))
5134 class->nested_classes_inited = TRUE;
5137 * Computes the size used by the fields, and their locations
5139 if (has_cached_info) {
5140 class->instance_size = cached_info.instance_size;
5141 class->sizes.class_size = cached_info.class_size;
5142 class->packing_size = cached_info.packing_size;
5143 class->min_align = cached_info.min_align;
5144 class->blittable = cached_info.blittable;
5145 class->has_references = cached_info.has_references;
5146 class->has_static_refs = cached_info.has_static_refs;
5147 class->no_special_static_fields = cached_info.no_special_static_fields;
5149 else
5150 if (!class->size_inited){
5151 mono_class_setup_fields (class);
5152 if (class->exception_type || mono_loader_get_last_error ())
5153 goto leave;
5156 /* Initialize arrays */
5157 if (class->rank) {
5158 class->method.count = 3 + (class->rank > 1? 2: 1);
5160 if (class->interface_count) {
5161 int count_generic = generic_array_methods (class);
5162 class->method.count += class->interface_count * count_generic;
5166 mono_class_setup_supertypes (class);
5168 if (!default_ghc)
5169 initialize_object_slots (class);
5172 * Initialize the rest of the data without creating a generic vtable if possible.
5173 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
5174 * also avoid computing a generic vtable.
5176 if (has_cached_info) {
5177 /* AOT case */
5178 class->vtable_size = cached_info.vtable_size;
5179 class->has_finalize = cached_info.has_finalize;
5180 class->has_finalize_inited = TRUE;
5181 class->ghcimpl = cached_info.ghcimpl;
5182 class->has_cctor = cached_info.has_cctor;
5183 } else if (class->rank == 1 && class->byval_arg.type == MONO_TYPE_SZARRAY) {
5184 /* SZARRAY can have 2 vtable layouts, with and without the stelemref method.
5185 * The first slot if for array with.
5187 static int szarray_vtable_size[2] = { 0 };
5189 int slot = MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg) ? 0 : 1;
5191 /* SZARRAY case */
5192 if (!szarray_vtable_size [slot]) {
5193 mono_class_setup_vtable (class);
5194 szarray_vtable_size [slot] = class->vtable_size;
5195 } else {
5196 class->vtable_size = szarray_vtable_size[slot];
5198 } else if (class->generic_class && !MONO_CLASS_IS_INTERFACE (class)) {
5199 MonoClass *gklass = class->generic_class->container_class;
5201 /* Generic instance case */
5202 class->ghcimpl = gklass->ghcimpl;
5203 class->has_cctor = gklass->has_cctor;
5205 mono_class_setup_vtable (gklass);
5206 if (gklass->exception_type) {
5207 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5208 goto leave;
5211 class->vtable_size = gklass->vtable_size;
5212 } else {
5213 /* General case */
5215 /* ghcimpl is not currently used
5216 class->ghcimpl = 1;
5217 if (class->parent) {
5218 MonoMethod *cmethod = class->vtable [ghc_slot];
5219 if (cmethod->is_inflated)
5220 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5221 if (cmethod == default_ghc) {
5222 class->ghcimpl = 0;
5227 /* C# doesn't allow interfaces to have cctors */
5228 if (!MONO_CLASS_IS_INTERFACE (class) || class->image != mono_defaults.corlib) {
5229 MonoMethod *cmethod = NULL;
5231 if (class->type_token) {
5232 cmethod = find_method_in_metadata (class, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
5233 /* The find_method function ignores the 'flags' argument */
5234 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
5235 class->has_cctor = 1;
5236 } else {
5237 mono_class_setup_methods (class);
5238 if (class->exception_type)
5239 goto leave;
5241 for (i = 0; i < class->method.count; ++i) {
5242 MonoMethod *method = class->methods [i];
5243 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
5244 (strcmp (".cctor", method->name) == 0)) {
5245 class->has_cctor = 1;
5246 break;
5253 if (class->parent) {
5254 int first_iface_slot;
5255 /* This will compute class->parent->vtable_size for some classes */
5256 mono_class_init (class->parent);
5257 if (class->parent->exception_type) {
5258 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5259 goto leave;
5261 if (mono_loader_get_last_error ())
5262 goto leave;
5263 if (!class->parent->vtable_size) {
5264 /* FIXME: Get rid of this somehow */
5265 mono_class_setup_vtable (class->parent);
5266 if (class->parent->exception_type) {
5267 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5268 goto leave;
5270 if (mono_loader_get_last_error ())
5271 goto leave;
5273 first_iface_slot = class->parent->vtable_size;
5274 if (mono_class_need_stelemref_method (class))
5275 ++first_iface_slot;
5276 setup_interface_offsets (class, first_iface_slot, TRUE);
5277 } else {
5278 setup_interface_offsets (class, 0, TRUE);
5281 if (mono_security_core_clr_enabled ())
5282 mono_security_core_clr_check_inheritance (class);
5284 if (mono_loader_get_last_error ()) {
5285 if (class->exception_type == MONO_EXCEPTION_NONE) {
5286 set_failure_from_loader_error (class, mono_loader_get_last_error ());
5288 mono_loader_clear_error ();
5291 if (class->generic_class && !mono_verifier_class_is_valid_generic_instantiation (class))
5292 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Invalid generic instantiation"));
5294 goto leave;
5296 leave:
5297 /* Because of the double-checking locking pattern */
5298 mono_memory_barrier ();
5299 class->inited = 1;
5300 class->init_pending = 0;
5302 mono_loader_unlock ();
5304 return class->exception_type == MONO_EXCEPTION_NONE;
5308 * mono_class_has_finalizer:
5310 * Return whenever KLASS has a finalizer, initializing klass->has_finalizer in the
5311 * process.
5313 gboolean
5314 mono_class_has_finalizer (MonoClass *klass)
5316 MonoClass *class = klass;
5317 gboolean has_finalize = FALSE;
5319 if (klass->has_finalize_inited)
5320 return klass->has_finalize;
5322 /* Interfaces and valuetypes are not supposed to have finalizers */
5323 if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) {
5324 MonoMethod *cmethod = NULL;
5326 if (class->rank == 1 && class->byval_arg.type == MONO_TYPE_SZARRAY) {
5327 } else if (class->generic_class) {
5328 MonoClass *gklass = class->generic_class->container_class;
5330 has_finalize = mono_class_has_finalizer (gklass);
5331 } else if (class->parent && class->parent->has_finalize) {
5332 has_finalize = TRUE;
5333 } else {
5334 if (class->parent) {
5336 * Can't search in metadata for a method named Finalize, because that
5337 * ignores overrides.
5339 mono_class_setup_vtable (class);
5340 if (class->exception_type || mono_loader_get_last_error ())
5341 cmethod = NULL;
5342 else
5343 cmethod = class->vtable [finalize_slot];
5346 if (cmethod) {
5347 g_assert (class->vtable_size > finalize_slot);
5349 if (class->parent) {
5350 if (cmethod->is_inflated)
5351 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5352 if (cmethod != default_finalize)
5353 has_finalize = TRUE;
5359 mono_image_lock (klass->image);
5361 if (!klass->has_finalize_inited) {
5362 klass->has_finalize = has_finalize ? 1 : 0;
5364 mono_memory_barrier ();
5365 klass->has_finalize_inited = TRUE;
5368 mono_image_unlock (klass->image);
5370 return klass->has_finalize;
5373 gboolean
5374 mono_is_corlib_image (MonoImage *image)
5376 /* FIXME: allow the dynamic case for our compilers and with full trust */
5377 if (image_is_dynamic (image))
5378 return image->assembly && !strcmp (image->assembly->aname.name, "mscorlib");
5379 else
5380 return image == mono_defaults.corlib;
5384 * LOCKING: this assumes the loader lock is held
5386 void
5387 mono_class_setup_mono_type (MonoClass *class)
5389 const char *name = class->name;
5390 const char *nspace = class->name_space;
5391 gboolean is_corlib = mono_is_corlib_image (class->image);
5393 class->this_arg.byref = 1;
5394 class->this_arg.data.klass = class;
5395 class->this_arg.type = MONO_TYPE_CLASS;
5396 class->byval_arg.data.klass = class;
5397 class->byval_arg.type = MONO_TYPE_CLASS;
5399 if (is_corlib && !strcmp (nspace, "System")) {
5400 if (!strcmp (name, "ValueType")) {
5402 * do not set the valuetype bit for System.ValueType.
5403 * class->valuetype = 1;
5405 class->blittable = TRUE;
5406 } else if (!strcmp (name, "Enum")) {
5408 * do not set the valuetype bit for System.Enum.
5409 * class->valuetype = 1;
5411 class->valuetype = 0;
5412 class->enumtype = 0;
5413 } else if (!strcmp (name, "Object")) {
5414 class->this_arg.type = class->byval_arg.type = MONO_TYPE_OBJECT;
5415 } else if (!strcmp (name, "String")) {
5416 class->this_arg.type = class->byval_arg.type = MONO_TYPE_STRING;
5417 } else if (!strcmp (name, "TypedReference")) {
5418 class->this_arg.type = class->byval_arg.type = MONO_TYPE_TYPEDBYREF;
5422 if (class->valuetype) {
5423 int t = MONO_TYPE_VALUETYPE;
5425 if (is_corlib && !strcmp (nspace, "System")) {
5426 switch (*name) {
5427 case 'B':
5428 if (!strcmp (name, "Boolean")) {
5429 t = MONO_TYPE_BOOLEAN;
5430 } else if (!strcmp(name, "Byte")) {
5431 t = MONO_TYPE_U1;
5432 class->blittable = TRUE;
5434 break;
5435 case 'C':
5436 if (!strcmp (name, "Char")) {
5437 t = MONO_TYPE_CHAR;
5439 break;
5440 case 'D':
5441 if (!strcmp (name, "Double")) {
5442 t = MONO_TYPE_R8;
5443 class->blittable = TRUE;
5445 break;
5446 case 'I':
5447 if (!strcmp (name, "Int32")) {
5448 t = MONO_TYPE_I4;
5449 class->blittable = TRUE;
5450 } else if (!strcmp(name, "Int16")) {
5451 t = MONO_TYPE_I2;
5452 class->blittable = TRUE;
5453 } else if (!strcmp(name, "Int64")) {
5454 t = MONO_TYPE_I8;
5455 class->blittable = TRUE;
5456 } else if (!strcmp(name, "IntPtr")) {
5457 t = MONO_TYPE_I;
5458 class->blittable = TRUE;
5460 break;
5461 case 'S':
5462 if (!strcmp (name, "Single")) {
5463 t = MONO_TYPE_R4;
5464 class->blittable = TRUE;
5465 } else if (!strcmp(name, "SByte")) {
5466 t = MONO_TYPE_I1;
5467 class->blittable = TRUE;
5469 break;
5470 case 'U':
5471 if (!strcmp (name, "UInt32")) {
5472 t = MONO_TYPE_U4;
5473 class->blittable = TRUE;
5474 } else if (!strcmp(name, "UInt16")) {
5475 t = MONO_TYPE_U2;
5476 class->blittable = TRUE;
5477 } else if (!strcmp(name, "UInt64")) {
5478 t = MONO_TYPE_U8;
5479 class->blittable = TRUE;
5480 } else if (!strcmp(name, "UIntPtr")) {
5481 t = MONO_TYPE_U;
5482 class->blittable = TRUE;
5484 break;
5485 case 'T':
5486 if (!strcmp (name, "TypedReference")) {
5487 t = MONO_TYPE_TYPEDBYREF;
5488 class->blittable = TRUE;
5490 break;
5491 case 'V':
5492 if (!strcmp (name, "Void")) {
5493 t = MONO_TYPE_VOID;
5495 break;
5496 default:
5497 break;
5500 class->this_arg.type = class->byval_arg.type = t;
5503 if (MONO_CLASS_IS_INTERFACE (class))
5504 class->interface_id = mono_get_unique_iid (class);
5508 #ifndef DISABLE_COM
5510 * COM initialization is delayed until needed.
5511 * However when a [ComImport] attribute is present on a type it will trigger
5512 * the initialization. This is not a problem unless the BCL being executed
5513 * lacks the types that COM depends on (e.g. Variant on Silverlight).
5515 static void
5516 init_com_from_comimport (MonoClass *class)
5518 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
5519 if (mono_security_core_clr_enabled ()) {
5520 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
5521 if (!mono_security_core_clr_determine_platform_image (class->image)) {
5522 /* but it can not be made available for application (i.e. user code) since all COM calls
5523 * are considered native calls. In this case we fail with a TypeLoadException (just like
5524 * Silverlight 2 does */
5525 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5526 return;
5530 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
5532 #endif /*DISABLE_COM*/
5535 * LOCKING: this assumes the loader lock is held
5537 void
5538 mono_class_setup_parent (MonoClass *class, MonoClass *parent)
5540 gboolean system_namespace;
5541 gboolean is_corlib = mono_is_corlib_image (class->image);
5543 system_namespace = !strcmp (class->name_space, "System") && is_corlib;
5545 /* if root of the hierarchy */
5546 if (system_namespace && !strcmp (class->name, "Object")) {
5547 class->parent = NULL;
5548 class->instance_size = sizeof (MonoObject);
5549 return;
5551 if (!strcmp (class->name, "<Module>")) {
5552 class->parent = NULL;
5553 class->instance_size = 0;
5554 return;
5557 if (!MONO_CLASS_IS_INTERFACE (class)) {
5558 /* Imported COM Objects always derive from __ComObject. */
5559 #ifndef DISABLE_COM
5560 if (MONO_CLASS_IS_IMPORT (class)) {
5561 init_com_from_comimport (class);
5562 if (parent == mono_defaults.object_class)
5563 parent = mono_class_get_com_object_class ();
5565 #endif
5566 if (!parent) {
5567 /* set the parent to something useful and safe, but mark the type as broken */
5568 parent = mono_defaults.object_class;
5569 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5572 class->parent = parent;
5574 if (parent->generic_class && !parent->name) {
5576 * If the parent is a generic instance, we may get
5577 * called before it is fully initialized, especially
5578 * before it has its name.
5580 return;
5583 #ifndef DISABLE_REMOTING
5584 class->marshalbyref = parent->marshalbyref;
5585 class->contextbound = parent->contextbound;
5586 #endif
5588 class->delegate = parent->delegate;
5590 if (MONO_CLASS_IS_IMPORT (class) || mono_class_is_com_object (parent))
5591 mono_class_set_is_com_object (class);
5593 if (system_namespace) {
5594 #ifndef DISABLE_REMOTING
5595 if (*class->name == 'M' && !strcmp (class->name, "MarshalByRefObject"))
5596 class->marshalbyref = 1;
5598 if (*class->name == 'C' && !strcmp (class->name, "ContextBoundObject"))
5599 class->contextbound = 1;
5600 #endif
5601 if (*class->name == 'D' && !strcmp (class->name, "Delegate"))
5602 class->delegate = 1;
5605 if (class->parent->enumtype || (mono_is_corlib_image (class->parent->image) && (strcmp (class->parent->name, "ValueType") == 0) &&
5606 (strcmp (class->parent->name_space, "System") == 0)))
5607 class->valuetype = 1;
5608 if (mono_is_corlib_image (class->parent->image) && ((strcmp (class->parent->name, "Enum") == 0) && (strcmp (class->parent->name_space, "System") == 0))) {
5609 class->valuetype = class->enumtype = 1;
5611 /*class->enumtype = class->parent->enumtype; */
5612 } else {
5613 /* initialize com types if COM interfaces are present */
5614 #ifndef DISABLE_COM
5615 if (MONO_CLASS_IS_IMPORT (class))
5616 init_com_from_comimport (class);
5617 #endif
5618 class->parent = NULL;
5624 * mono_class_setup_supertypes:
5625 * @class: a class
5627 * Build the data structure needed to make fast type checks work.
5628 * This currently sets two fields in @class:
5629 * - idepth: distance between @class and System.Object in the type
5630 * hierarchy + 1
5631 * - supertypes: array of classes: each element has a class in the hierarchy
5632 * starting from @class up to System.Object
5634 * LOCKING: This function is atomic, in case of contention we waste memory.
5636 void
5637 mono_class_setup_supertypes (MonoClass *class)
5639 int ms;
5640 MonoClass **supertypes;
5642 mono_atomic_load_acquire (supertypes, void*, &class->supertypes);
5643 if (supertypes)
5644 return;
5646 if (class->parent && !class->parent->supertypes)
5647 mono_class_setup_supertypes (class->parent);
5648 if (class->parent)
5649 class->idepth = class->parent->idepth + 1;
5650 else
5651 class->idepth = 1;
5653 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, class->idepth);
5654 supertypes = mono_class_alloc0 (class, sizeof (MonoClass *) * ms);
5656 if (class->parent) {
5657 supertypes [class->idepth - 1] = class;
5658 memcpy (supertypes, class->parent->supertypes, class->parent->idepth * sizeof (gpointer));
5659 } else {
5660 supertypes [0] = class;
5663 mono_atomic_store_release (&class->supertypes, supertypes);
5666 static gboolean
5667 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
5669 MonoClass *gtd = (MonoClass*)user_data;
5670 /* Only try to fix generic instances of @gtd */
5671 if (gclass->generic_class->container_class != gtd)
5672 return FALSE;
5674 /* Check if the generic instance has no parent. */
5675 if (gtd->parent && !gclass->parent)
5676 mono_generic_class_setup_parent (gclass, gtd);
5678 return TRUE;
5681 static void
5682 mono_class_set_failure_and_error (MonoClass *class, MonoError *error, const char *msg)
5684 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (msg));
5685 mono_error_set_type_load_class (error, class, msg);
5688 static void
5689 mono_class_set_failure_from_loader_error (MonoClass *class, MonoError *error, char *msg)
5691 MonoLoaderError *lerror = mono_loader_get_last_error ();
5693 if (lerror) {
5694 set_failure_from_loader_error (class, lerror);
5695 mono_error_set_from_loader_error (error);
5696 if (msg)
5697 g_free (msg);
5698 } else {
5699 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, msg);
5700 mono_error_set_type_load_class (error, class, msg);
5705 * mono_class_create_from_typedef:
5706 * @image: image where the token is valid
5707 * @type_token: typedef token
5708 * @error: used to return any error found while creating the type
5710 * Create the MonoClass* representing the specified type token.
5711 * @type_token must be a TypeDef token.
5713 * FIXME: don't return NULL on failure, just the the caller figure it out.
5715 static MonoClass *
5716 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
5718 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
5719 MonoClass *class, *parent = NULL;
5720 guint32 cols [MONO_TYPEDEF_SIZE];
5721 guint32 cols_next [MONO_TYPEDEF_SIZE];
5722 guint tidx = mono_metadata_token_index (type_token);
5723 MonoGenericContext *context = NULL;
5724 const char *name, *nspace;
5725 guint icount = 0;
5726 MonoClass **interfaces;
5727 guint32 field_last, method_last;
5728 guint32 nesting_tokeen;
5730 mono_error_init (error);
5732 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
5733 mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
5734 g_assert (!mono_loader_get_last_error ());
5735 return NULL;
5738 mono_loader_lock ();
5740 if ((class = mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
5741 mono_loader_unlock ();
5742 g_assert (!mono_loader_get_last_error ());
5743 return class;
5746 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
5748 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
5749 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
5751 class = mono_image_alloc0 (image, sizeof (MonoClass));
5753 class->name = name;
5754 class->name_space = nspace;
5756 mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
5758 class->image = image;
5759 class->type_token = type_token;
5760 class->flags = cols [MONO_TYPEDEF_FLAGS];
5762 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), class);
5764 classes_size += sizeof (MonoClass);
5767 * Check whether we're a generic type definition.
5769 class->generic_container = mono_metadata_load_generic_params (image, class->type_token, NULL);
5770 if (class->generic_container) {
5771 class->is_generic = 1;
5772 class->generic_container->owner.klass = class;
5773 context = &class->generic_container->context;
5776 if (class->generic_container)
5777 enable_gclass_recording ();
5779 if (cols [MONO_TYPEDEF_EXTENDS]) {
5780 MonoClass *tmp;
5781 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
5783 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
5784 /*WARNING: this must satisfy mono_metadata_type_hash*/
5785 class->this_arg.byref = 1;
5786 class->this_arg.data.klass = class;
5787 class->this_arg.type = MONO_TYPE_CLASS;
5788 class->byval_arg.data.klass = class;
5789 class->byval_arg.type = MONO_TYPE_CLASS;
5791 parent = mono_class_get_checked (image, parent_token, error);
5792 if (parent && context) /* Always inflate */
5793 parent = mono_class_inflate_generic_class_checked (parent, context, error);
5795 if (parent == NULL) {
5796 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
5797 goto parent_failure;
5800 for (tmp = parent; tmp; tmp = tmp->parent) {
5801 if (tmp == class) {
5802 mono_class_set_failure_and_error (class, error, "Cycle found while resolving parent");
5803 goto parent_failure;
5805 if (class->generic_container && tmp->generic_class && tmp->generic_class->container_class == class) {
5806 mono_class_set_failure_and_error (class, error, "Parent extends generic instance of this type");
5807 goto parent_failure;
5812 mono_class_setup_parent (class, parent);
5814 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
5815 mono_class_setup_mono_type (class);
5817 if (class->generic_container)
5818 disable_gclass_recording (fix_gclass_incomplete_instantiation, class);
5821 * This might access class->byval_arg for recursion generated by generic constraints,
5822 * so it has to come after setup_mono_type ().
5824 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
5825 class->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
5826 if (!mono_error_ok (error)) {
5827 /*FIXME implement a mono_class_set_failure_from_mono_error */
5828 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
5829 mono_loader_unlock ();
5830 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5831 g_assert (!mono_loader_get_last_error ());
5832 return NULL;
5836 if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
5837 class->unicode = 1;
5839 #ifdef HOST_WIN32
5840 if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
5841 class->unicode = 1;
5842 #endif
5844 class->cast_class = class->element_class = class;
5846 if (!class->enumtype) {
5847 if (!mono_metadata_interfaces_from_typedef_full (
5848 image, type_token, &interfaces, &icount, FALSE, context, error)){
5850 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
5851 mono_loader_unlock ();
5852 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5853 return NULL;
5856 class->interfaces = interfaces;
5857 class->interface_count = icount;
5858 class->interfaces_inited = 1;
5861 /*g_print ("Load class %s\n", name);*/
5864 * Compute the field and method lists
5866 class->field.first = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
5867 class->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
5869 if (tt->rows > tidx){
5870 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
5871 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
5872 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
5873 } else {
5874 field_last = image->tables [MONO_TABLE_FIELD].rows;
5875 method_last = image->tables [MONO_TABLE_METHOD].rows;
5878 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
5879 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
5880 class->field.count = field_last - class->field.first;
5881 else
5882 class->field.count = 0;
5884 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
5885 class->method.count = method_last - class->method.first;
5886 else
5887 class->method.count = 0;
5889 /* reserve space to store vector pointer in arrays */
5890 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
5891 class->instance_size += 2 * sizeof (gpointer);
5892 g_assert (class->field.count == 0);
5895 if (class->enumtype) {
5896 MonoType *enum_basetype = mono_class_find_enum_basetype (class, error);
5897 if (!enum_basetype) {
5898 /*set it to a default value as the whole runtime can't handle this to be null*/
5899 class->cast_class = class->element_class = mono_defaults.int32_class;
5900 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
5901 mono_loader_unlock ();
5902 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5903 g_assert (!mono_loader_get_last_error ());
5904 return NULL;
5906 class->cast_class = class->element_class = mono_class_from_mono_type (enum_basetype);
5910 * If we're a generic type definition, load the constraints.
5911 * We must do this after the class has been constructed to make certain recursive scenarios
5912 * work.
5914 if (class->generic_container && !mono_metadata_load_generic_param_constraints_checked (image, type_token, class->generic_container, error)) {
5915 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load generic parameter constrains due to %s", mono_error_get_message (error)));
5916 mono_loader_unlock ();
5917 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5918 g_assert (!mono_loader_get_last_error ());
5919 return NULL;
5922 if (class->image->assembly_name && !strcmp (class->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
5923 if (!strncmp (name, "Vector", 6))
5924 class->simd_type = !strcmp (name + 6, "2d") || !strcmp (name + 6, "2ul") || !strcmp (name + 6, "2l") || !strcmp (name + 6, "4f") || !strcmp (name + 6, "4ui") || !strcmp (name + 6, "4i") || !strcmp (name + 6, "8s") || !strcmp (name + 6, "8us") || !strcmp (name + 6, "16b") || !strcmp (name + 6, "16sb");
5927 mono_loader_unlock ();
5929 mono_profiler_class_loaded (class, MONO_PROFILE_OK);
5930 g_assert (!mono_loader_get_last_error ());
5932 return class;
5934 parent_failure:
5935 mono_class_setup_mono_type (class);
5936 mono_loader_unlock ();
5937 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5938 g_assert (!mono_loader_get_last_error ());
5939 return NULL;
5942 /** is klass Nullable<T>? */
5943 gboolean
5944 mono_class_is_nullable (MonoClass *klass)
5946 return klass->generic_class != NULL &&
5947 klass->generic_class->container_class == mono_defaults.generic_nullable_class;
5951 /** if klass is T? return T */
5952 MonoClass*
5953 mono_class_get_nullable_param (MonoClass *klass)
5955 g_assert (mono_class_is_nullable (klass));
5956 return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
5959 static void
5960 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
5962 if (gtd->parent) {
5963 MonoError error;
5964 MonoGenericClass *gclass = klass->generic_class;
5966 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
5967 if (!mono_error_ok (&error)) {
5968 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
5969 klass->parent = mono_defaults.object_class;
5970 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
5971 mono_error_cleanup (&error);
5974 if (klass->parent)
5975 mono_class_setup_parent (klass, klass->parent);
5977 if (klass->enumtype) {
5978 klass->cast_class = gtd->cast_class;
5979 klass->element_class = gtd->element_class;
5985 * Create the `MonoClass' for an instantiation of a generic type.
5986 * We only do this if we actually need it.
5988 MonoClass*
5989 mono_generic_class_get_class (MonoGenericClass *gclass)
5991 MonoClass *klass, *gklass;
5993 if (gclass->cached_class)
5994 return gclass->cached_class;
5996 mono_loader_lock ();
5997 if (gclass->cached_class) {
5998 mono_loader_unlock ();
5999 return gclass->cached_class;
6002 klass = mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
6004 gklass = gclass->container_class;
6006 if (record_gclass_instantiation > 0)
6007 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
6009 if (gklass->nested_in) {
6010 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
6011 klass->nested_in = gklass->nested_in;
6014 klass->name = gklass->name;
6015 klass->name_space = gklass->name_space;
6017 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
6019 klass->image = gklass->image;
6020 klass->flags = gklass->flags;
6021 klass->type_token = gklass->type_token;
6022 klass->field.count = gklass->field.count;
6024 klass->is_inflated = 1;
6025 klass->generic_class = gclass;
6027 klass->this_arg.type = klass->byval_arg.type = MONO_TYPE_GENERICINST;
6028 klass->this_arg.data.generic_class = klass->byval_arg.data.generic_class = gclass;
6029 klass->this_arg.byref = TRUE;
6030 klass->enumtype = gklass->enumtype;
6031 klass->valuetype = gklass->valuetype;
6033 klass->cast_class = klass->element_class = klass;
6035 if (mono_class_is_nullable (klass))
6036 klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
6039 * We're not interested in the nested classes of a generic instance.
6040 * We use the generic type definition to look for nested classes.
6043 mono_generic_class_setup_parent (klass, gklass);
6045 if (gclass->is_dynamic) {
6046 klass->inited = 1;
6048 mono_class_setup_supertypes (klass);
6050 if (klass->enumtype) {
6052 * For enums, gklass->fields might not been set, but instance_size etc. is
6053 * already set in mono_reflection_create_internal_class (). For non-enums,
6054 * these will be computed normally in mono_class_layout_fields ().
6056 klass->instance_size = gklass->instance_size;
6057 klass->sizes.class_size = gklass->sizes.class_size;
6058 mono_memory_barrier ();
6059 klass->size_inited = 1;
6063 mono_memory_barrier ();
6064 gclass->cached_class = klass;
6066 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6068 inflated_classes ++;
6069 inflated_classes_size += sizeof (MonoClass);
6071 mono_loader_unlock ();
6073 return klass;
6076 static MonoClass*
6077 make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is_mvar, MonoGenericParamInfo *pinfo)
6079 MonoClass *klass, **ptr;
6080 int count, pos, i;
6081 MonoGenericContainer *container = mono_generic_param_owner (param);
6083 if (!image)
6084 /* FIXME: */
6085 image = mono_defaults.corlib;
6087 klass = mono_image_alloc0 (image, sizeof (MonoClass));
6088 classes_size += sizeof (MonoClass);
6090 if (pinfo) {
6091 klass->name = pinfo->name;
6092 } else {
6093 int n = mono_generic_param_num (param);
6094 klass->name = mono_image_alloc0 (image, 16);
6095 sprintf ((char*)klass->name, "%d", n);
6098 if (container) {
6099 if (is_mvar) {
6100 MonoMethod *omethod = container->owner.method;
6101 klass->name_space = (omethod && omethod->klass) ? omethod->klass->name_space : "";
6102 } else {
6103 MonoClass *oklass = container->owner.klass;
6104 klass->name_space = oklass ? oklass->name_space : "";
6106 } else {
6107 klass->name_space = "";
6110 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
6112 count = 0;
6113 if (pinfo)
6114 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
6117 pos = 0;
6118 if ((count > 0) && !MONO_CLASS_IS_INTERFACE (pinfo->constraints [0])) {
6119 klass->parent = pinfo->constraints [0];
6120 pos++;
6121 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
6122 klass->parent = mono_class_from_name (mono_defaults.corlib, "System", "ValueType");
6123 else
6124 klass->parent = mono_defaults.object_class;
6127 if (count - pos > 0) {
6128 klass->interface_count = count - pos;
6129 klass->interfaces = mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos));
6130 klass->interfaces_inited = TRUE;
6131 for (i = pos; i < count; i++)
6132 klass->interfaces [i - pos] = pinfo->constraints [i];
6135 klass->image = image;
6137 klass->inited = TRUE;
6138 klass->cast_class = klass->element_class = klass;
6139 klass->flags = TYPE_ATTRIBUTE_PUBLIC;
6141 klass->this_arg.type = klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
6142 klass->this_arg.data.generic_param = klass->byval_arg.data.generic_param = param;
6143 klass->this_arg.byref = TRUE;
6145 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
6146 klass->sizes.generic_param_token = pinfo ? pinfo->token : 0;
6148 /*Init these fields to sane values*/
6149 klass->min_align = 1;
6150 klass->instance_size = sizeof (gpointer);
6151 mono_memory_barrier ();
6152 klass->size_inited = 1;
6154 mono_class_setup_supertypes (klass);
6156 if (count - pos > 0) {
6157 mono_class_setup_vtable (klass->parent);
6158 if (klass->parent->exception_type)
6159 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to setup parent interfaces"));
6160 else
6161 setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
6164 return klass;
6167 #define FAST_CACHE_SIZE 16
6170 * LOCKING: Takes the image lock depending on @take_lock.
6172 static MonoClass *
6173 get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, gboolean take_lock)
6175 int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
6176 MonoImage *image = param->image;
6177 GHashTable *ht;
6179 g_assert (image);
6181 if (n < FAST_CACHE_SIZE) {
6182 if (is_mvar)
6183 return image->mvar_cache_fast ? image->mvar_cache_fast [n] : NULL;
6184 else
6185 return image->var_cache_fast ? image->var_cache_fast [n] : NULL;
6186 } else {
6187 MonoClass *klass = NULL;
6188 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6189 if (ht) {
6190 if (take_lock)
6191 mono_image_lock (image);
6192 klass = g_hash_table_lookup (ht, GINT_TO_POINTER (n));
6193 if (take_lock)
6194 mono_image_unlock (image);
6196 return klass;
6201 * LOCKING: Image lock (param->image) must be held
6203 static void
6204 set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
6206 int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
6207 MonoImage *image = param->image;
6209 g_assert (image);
6211 if (n < FAST_CACHE_SIZE) {
6212 if (is_mvar) {
6213 /* Requires locking to avoid droping an already published class */
6214 if (!image->mvar_cache_fast)
6215 image->mvar_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6216 image->mvar_cache_fast [n] = klass;
6217 } else {
6218 if (!image->var_cache_fast)
6219 image->var_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6220 image->var_cache_fast [n] = klass;
6222 } else {
6223 GHashTable *ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6224 if (!ht) {
6225 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6226 if (!ht) {
6227 ht = g_hash_table_new (NULL, NULL);
6228 mono_memory_barrier ();
6229 if (is_mvar)
6230 image->mvar_cache_slow = ht;
6231 else
6232 image->var_cache_slow = ht;
6235 g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
6240 * LOCKING: Acquires the image lock (@image).
6242 MonoClass *
6243 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar)
6245 MonoGenericContainer *container = mono_generic_param_owner (param);
6246 MonoGenericParamInfo *pinfo = NULL;
6247 MonoClass *klass, *klass2;
6249 if (container) {
6250 pinfo = mono_generic_param_info (param);
6251 klass = pinfo->pklass;
6252 } else {
6253 image = NULL;
6254 klass = get_anon_gparam_class (param, is_mvar, TRUE);
6256 if (klass)
6257 return klass;
6259 if (!image && container) {
6260 if (is_mvar) {
6261 MonoMethod *method = container->owner.method;
6262 image = (method && method->klass) ? method->klass->image : NULL;
6263 } else {
6264 MonoClass *klass = container->owner.klass;
6265 // FIXME: 'klass' should not be null
6266 // But, monodis creates GenericContainers without associating a owner to it
6267 image = klass ? klass->image : NULL;
6271 klass = make_generic_param_class (param, image, is_mvar, pinfo);
6273 mono_memory_barrier ();
6275 if (!image) //FIXME is this only needed by monodis? Can't we fix monodis instead of having this hack?
6276 image = mono_defaults.corlib;
6278 mono_image_lock (image);
6279 if (container)
6280 klass2 = pinfo->pklass;
6281 else
6282 klass2 = get_anon_gparam_class (param, is_mvar, FALSE);
6284 if (klass2) {
6285 klass = klass2;
6286 } else {
6287 if (container)
6288 pinfo->pklass = klass;
6289 else
6290 set_anon_gparam_class (param, is_mvar, klass);
6292 mono_image_unlock (image);
6294 /* FIXME: Should this go inside 'make_generic_param_klass'? */
6295 if (klass2)
6296 mono_profiler_class_loaded (klass2, MONO_PROFILE_FAILED);
6297 else
6298 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6300 return klass;
6303 MonoClass *
6304 mono_ptr_class_get (MonoType *type)
6306 MonoClass *result;
6307 MonoClass *el_class;
6308 MonoImage *image;
6309 char *name;
6311 el_class = mono_class_from_mono_type (type);
6312 image = el_class->image;
6314 mono_image_lock (image);
6315 if (image->ptr_cache) {
6316 if ((result = g_hash_table_lookup (image->ptr_cache, el_class))) {
6317 mono_image_unlock (image);
6318 return result;
6321 mono_image_unlock (image);
6323 result = mono_image_alloc0 (image, sizeof (MonoClass));
6325 classes_size += sizeof (MonoClass);
6327 result->parent = NULL; /* no parent for PTR types */
6328 result->name_space = el_class->name_space;
6329 name = g_strdup_printf ("%s*", el_class->name);
6330 result->name = mono_image_strdup (image, name);
6331 g_free (name);
6333 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6335 result->image = el_class->image;
6336 result->inited = TRUE;
6337 result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
6338 /* Can pointers get boxed? */
6339 result->instance_size = sizeof (gpointer);
6340 result->cast_class = result->element_class = el_class;
6341 result->blittable = TRUE;
6343 result->this_arg.type = result->byval_arg.type = MONO_TYPE_PTR;
6344 result->this_arg.data.type = result->byval_arg.data.type = &result->element_class->byval_arg;
6345 result->this_arg.byref = TRUE;
6347 mono_class_setup_supertypes (result);
6349 mono_image_lock (image);
6350 if (image->ptr_cache) {
6351 MonoClass *result2;
6352 if ((result2 = g_hash_table_lookup (image->ptr_cache, el_class))) {
6353 mono_image_unlock (image);
6354 mono_profiler_class_loaded (result, MONO_PROFILE_FAILED);
6355 return result2;
6357 } else {
6358 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6360 g_hash_table_insert (image->ptr_cache, el_class, result);
6361 mono_image_unlock (image);
6363 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6365 return result;
6368 static MonoClass *
6369 mono_fnptr_class_get (MonoMethodSignature *sig)
6371 MonoClass *result;
6372 static GHashTable *ptr_hash = NULL;
6374 /* FIXME: These should be allocate from a mempool as well, but which one ? */
6376 mono_loader_lock ();
6378 if (!ptr_hash)
6379 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
6381 if ((result = g_hash_table_lookup (ptr_hash, sig))) {
6382 mono_loader_unlock ();
6383 return result;
6385 result = g_new0 (MonoClass, 1);
6387 result->parent = NULL; /* no parent for PTR types */
6388 result->name_space = "System";
6389 result->name = "MonoFNPtrFakeClass";
6391 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6393 result->image = mono_defaults.corlib; /* need to fix... */
6394 result->inited = TRUE;
6395 result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */
6396 /* Can pointers get boxed? */
6397 result->instance_size = sizeof (gpointer);
6398 result->cast_class = result->element_class = result;
6399 result->blittable = TRUE;
6401 result->this_arg.type = result->byval_arg.type = MONO_TYPE_FNPTR;
6402 result->this_arg.data.method = result->byval_arg.data.method = sig;
6403 result->this_arg.byref = TRUE;
6404 result->blittable = TRUE;
6406 mono_class_setup_supertypes (result);
6408 g_hash_table_insert (ptr_hash, sig, result);
6410 mono_loader_unlock ();
6412 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6414 return result;
6417 MonoClass *
6418 mono_class_from_mono_type (MonoType *type)
6420 switch (type->type) {
6421 case MONO_TYPE_OBJECT:
6422 return type->data.klass? type->data.klass: mono_defaults.object_class;
6423 case MONO_TYPE_VOID:
6424 return type->data.klass? type->data.klass: mono_defaults.void_class;
6425 case MONO_TYPE_BOOLEAN:
6426 return type->data.klass? type->data.klass: mono_defaults.boolean_class;
6427 case MONO_TYPE_CHAR:
6428 return type->data.klass? type->data.klass: mono_defaults.char_class;
6429 case MONO_TYPE_I1:
6430 return type->data.klass? type->data.klass: mono_defaults.sbyte_class;
6431 case MONO_TYPE_U1:
6432 return type->data.klass? type->data.klass: mono_defaults.byte_class;
6433 case MONO_TYPE_I2:
6434 return type->data.klass? type->data.klass: mono_defaults.int16_class;
6435 case MONO_TYPE_U2:
6436 return type->data.klass? type->data.klass: mono_defaults.uint16_class;
6437 case MONO_TYPE_I4:
6438 return type->data.klass? type->data.klass: mono_defaults.int32_class;
6439 case MONO_TYPE_U4:
6440 return type->data.klass? type->data.klass: mono_defaults.uint32_class;
6441 case MONO_TYPE_I:
6442 return type->data.klass? type->data.klass: mono_defaults.int_class;
6443 case MONO_TYPE_U:
6444 return type->data.klass? type->data.klass: mono_defaults.uint_class;
6445 case MONO_TYPE_I8:
6446 return type->data.klass? type->data.klass: mono_defaults.int64_class;
6447 case MONO_TYPE_U8:
6448 return type->data.klass? type->data.klass: mono_defaults.uint64_class;
6449 case MONO_TYPE_R4:
6450 return type->data.klass? type->data.klass: mono_defaults.single_class;
6451 case MONO_TYPE_R8:
6452 return type->data.klass? type->data.klass: mono_defaults.double_class;
6453 case MONO_TYPE_STRING:
6454 return type->data.klass? type->data.klass: mono_defaults.string_class;
6455 case MONO_TYPE_TYPEDBYREF:
6456 return type->data.klass? type->data.klass: mono_defaults.typed_reference_class;
6457 case MONO_TYPE_ARRAY:
6458 return mono_bounded_array_class_get (type->data.array->eklass, type->data.array->rank, TRUE);
6459 case MONO_TYPE_PTR:
6460 return mono_ptr_class_get (type->data.type);
6461 case MONO_TYPE_FNPTR:
6462 return mono_fnptr_class_get (type->data.method);
6463 case MONO_TYPE_SZARRAY:
6464 return mono_array_class_get (type->data.klass, 1);
6465 case MONO_TYPE_CLASS:
6466 case MONO_TYPE_VALUETYPE:
6467 return type->data.klass;
6468 case MONO_TYPE_GENERICINST:
6469 return mono_generic_class_get_class (type->data.generic_class);
6470 case MONO_TYPE_VAR:
6471 return mono_class_from_generic_parameter (type->data.generic_param, NULL, FALSE);
6472 case MONO_TYPE_MVAR:
6473 return mono_class_from_generic_parameter (type->data.generic_param, NULL, TRUE);
6474 default:
6475 g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
6476 g_assert_not_reached ();
6479 return NULL;
6483 * mono_type_retrieve_from_typespec
6484 * @image: context where the image is created
6485 * @type_spec: typespec token
6486 * @context: the generic context used to evaluate generic instantiations in
6488 static MonoType *
6489 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
6491 MonoType *t = mono_type_create_from_typespec_checked (image, type_spec, error);
6493 *did_inflate = FALSE;
6495 if (!t)
6496 return NULL;
6498 if (context && (context->class_inst || context->method_inst)) {
6499 MonoType *inflated = inflate_generic_type (NULL, t, context, error);
6501 if (!mono_error_ok (error)) {
6502 g_assert (!mono_loader_get_last_error ());
6503 return NULL;
6506 if (inflated) {
6507 t = inflated;
6508 *did_inflate = TRUE;
6511 return t;
6515 * mono_class_create_from_typespec
6516 * @image: context where the image is created
6517 * @type_spec: typespec token
6518 * @context: the generic context used to evaluate generic instantiations in
6520 static MonoClass *
6521 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
6523 MonoClass *ret;
6524 gboolean inflated = FALSE;
6525 MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
6526 if (!mono_error_ok (error))
6527 return NULL;
6528 ret = mono_class_from_mono_type (t);
6529 if (inflated)
6530 mono_metadata_free_type (t);
6531 return ret;
6535 * mono_bounded_array_class_get:
6536 * @element_class: element class
6537 * @rank: the dimension of the array class
6538 * @bounded: whenever the array has non-zero bounds
6540 * Returns: a class object describing the array with element type @element_type and
6541 * dimension @rank.
6543 MonoClass *
6544 mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
6546 MonoImage *image;
6547 MonoClass *class;
6548 MonoClass *parent = NULL;
6549 GSList *list, *rootlist = NULL;
6550 int nsize;
6551 char *name;
6552 gboolean corlib_type = FALSE;
6554 g_assert (rank <= 255);
6556 if (rank > 1)
6557 /* bounded only matters for one-dimensional arrays */
6558 bounded = FALSE;
6560 image = eclass->image;
6562 if (rank == 1 && !bounded) {
6564 * This case is very frequent not just during compilation because of calls
6565 * from mono_class_from_mono_type (), mono_array_new (),
6566 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
6568 mono_mutex_lock (&image->szarray_cache_lock);
6569 if (!image->szarray_cache)
6570 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6571 class = g_hash_table_lookup (image->szarray_cache, eclass);
6572 mono_mutex_unlock (&image->szarray_cache_lock);
6573 if (class)
6574 return class;
6576 mono_loader_lock ();
6577 } else {
6578 mono_loader_lock ();
6580 if (!image->array_cache)
6581 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6583 if ((rootlist = list = g_hash_table_lookup (image->array_cache, eclass))) {
6584 for (; list; list = list->next) {
6585 class = list->data;
6586 if ((class->rank == rank) && (class->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
6587 mono_loader_unlock ();
6588 return class;
6594 /* for the building corlib use System.Array from it */
6595 if (image->assembly && assembly_is_dynamic (image->assembly) && image->assembly_name && strcmp (image->assembly_name, "mscorlib") == 0) {
6596 parent = mono_class_from_name (image, "System", "Array");
6597 corlib_type = TRUE;
6598 } else {
6599 parent = mono_defaults.array_class;
6600 if (!parent->inited)
6601 mono_class_init (parent);
6604 class = mono_image_alloc0 (image, sizeof (MonoClass));
6606 class->image = image;
6607 class->name_space = eclass->name_space;
6608 nsize = strlen (eclass->name);
6609 name = g_malloc (nsize + 2 + rank + 1);
6610 memcpy (name, eclass->name, nsize);
6611 name [nsize] = '[';
6612 if (rank > 1)
6613 memset (name + nsize + 1, ',', rank - 1);
6614 if (bounded)
6615 name [nsize + rank] = '*';
6616 name [nsize + rank + bounded] = ']';
6617 name [nsize + rank + bounded + 1] = 0;
6618 class->name = mono_image_strdup (image, name);
6619 g_free (name);
6621 mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
6623 classes_size += sizeof (MonoClass);
6625 class->type_token = 0;
6626 /* all arrays are marked serializable and sealed, bug #42779 */
6627 class->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC;
6628 class->parent = parent;
6629 class->instance_size = mono_class_instance_size (class->parent);
6631 if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
6632 /*Arrays of those two types are invalid.*/
6633 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
6634 } else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
6635 if (!eclass->ref_info_handle || eclass->wastypebuilder) {
6636 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
6637 g_assert (eclass->ref_info_handle && !eclass->wastypebuilder);
6639 /* element_size -1 is ok as this is not an instantitable type*/
6640 class->sizes.element_size = -1;
6641 } else
6642 class->sizes.element_size = mono_class_array_element_size (eclass);
6644 mono_class_setup_supertypes (class);
6646 if (eclass->generic_class)
6647 mono_class_init (eclass);
6648 if (!eclass->size_inited)
6649 mono_class_setup_fields (eclass);
6650 if (eclass->exception_type) /*FIXME we fail the array type, but we have to let other fields be set.*/
6651 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
6653 class->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
6655 class->rank = rank;
6657 if (eclass->enumtype)
6658 class->cast_class = eclass->element_class;
6659 else
6660 class->cast_class = eclass;
6662 switch (class->cast_class->byval_arg.type) {
6663 case MONO_TYPE_I1:
6664 class->cast_class = mono_defaults.byte_class;
6665 break;
6666 case MONO_TYPE_U2:
6667 class->cast_class = mono_defaults.int16_class;
6668 break;
6669 case MONO_TYPE_U4:
6670 #if SIZEOF_VOID_P == 4
6671 case MONO_TYPE_I:
6672 case MONO_TYPE_U:
6673 #endif
6674 class->cast_class = mono_defaults.int32_class;
6675 break;
6676 case MONO_TYPE_U8:
6677 #if SIZEOF_VOID_P == 8
6678 case MONO_TYPE_I:
6679 case MONO_TYPE_U:
6680 #endif
6681 class->cast_class = mono_defaults.int64_class;
6682 break;
6685 class->element_class = eclass;
6687 if ((rank > 1) || bounded) {
6688 MonoArrayType *at = mono_image_alloc0 (image, sizeof (MonoArrayType));
6689 class->byval_arg.type = MONO_TYPE_ARRAY;
6690 class->byval_arg.data.array = at;
6691 at->eklass = eclass;
6692 at->rank = rank;
6693 /* FIXME: complete.... */
6694 } else {
6695 class->byval_arg.type = MONO_TYPE_SZARRAY;
6696 class->byval_arg.data.klass = eclass;
6698 class->this_arg = class->byval_arg;
6699 class->this_arg.byref = 1;
6700 if (corlib_type) {
6701 class->inited = 1;
6704 class->generic_container = eclass->generic_container;
6706 if (rank == 1 && !bounded) {
6707 MonoClass *prev_class;
6709 mono_mutex_lock (&image->szarray_cache_lock);
6710 prev_class = g_hash_table_lookup (image->szarray_cache, eclass);
6711 if (prev_class)
6712 /* Someone got in before us */
6713 class = prev_class;
6714 else
6715 g_hash_table_insert (image->szarray_cache, eclass, class);
6716 mono_mutex_unlock (&image->szarray_cache_lock);
6717 } else {
6718 list = g_slist_append (rootlist, class);
6719 g_hash_table_insert (image->array_cache, eclass, list);
6722 mono_loader_unlock ();
6724 mono_profiler_class_loaded (class, MONO_PROFILE_OK);
6726 return class;
6730 * mono_array_class_get:
6731 * @element_class: element class
6732 * @rank: the dimension of the array class
6734 * Returns: a class object describing the array with element type @element_type and
6735 * dimension @rank.
6737 MonoClass *
6738 mono_array_class_get (MonoClass *eclass, guint32 rank)
6740 return mono_bounded_array_class_get (eclass, rank, FALSE);
6744 * mono_class_instance_size:
6745 * @klass: a class
6747 * Returns: the size of an object instance
6749 gint32
6750 mono_class_instance_size (MonoClass *klass)
6752 if (!klass->size_inited)
6753 mono_class_init (klass);
6755 return klass->instance_size;
6759 * mono_class_min_align:
6760 * @klass: a class
6762 * Returns: minimm alignment requirements
6764 gint32
6765 mono_class_min_align (MonoClass *klass)
6767 if (!klass->size_inited)
6768 mono_class_init (klass);
6770 return klass->min_align;
6774 * mono_class_value_size:
6775 * @klass: a class
6777 * This function is used for value types, and return the
6778 * space and the alignment to store that kind of value object.
6780 * Returns: the size of a value of kind @klass
6782 gint32
6783 mono_class_value_size (MonoClass *klass, guint32 *align)
6785 gint32 size;
6787 /* fixme: check disable, because we still have external revereces to
6788 * mscorlib and Dummy Objects
6790 /*g_assert (klass->valuetype);*/
6792 size = mono_class_instance_size (klass) - sizeof (MonoObject);
6794 if (align)
6795 *align = klass->min_align;
6797 return size;
6801 * mono_class_data_size:
6802 * @klass: a class
6804 * Returns: the size of the static class data
6806 gint32
6807 mono_class_data_size (MonoClass *klass)
6809 if (!klass->inited)
6810 mono_class_init (klass);
6811 /* This can happen with dynamically created types */
6812 if (!klass->fields_inited)
6813 mono_class_setup_fields_locking (klass);
6815 /* in arrays, sizes.class_size is unioned with element_size
6816 * and arrays have no static fields
6818 if (klass->rank)
6819 return 0;
6820 return klass->sizes.class_size;
6824 * Auxiliary routine to mono_class_get_field
6826 * Takes a field index instead of a field token.
6828 static MonoClassField *
6829 mono_class_get_field_idx (MonoClass *class, int idx)
6831 mono_class_setup_fields_locking (class);
6832 if (class->exception_type)
6833 return NULL;
6835 while (class) {
6836 if (class->image->uncompressed_metadata) {
6838 * class->field.first points to the FieldPtr table, while idx points into the
6839 * Field table, so we have to do a search.
6841 /*FIXME this is broken for types with multiple fields with the same name.*/
6842 const char *name = mono_metadata_string_heap (class->image, mono_metadata_decode_row_col (&class->image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
6843 int i;
6845 for (i = 0; i < class->field.count; ++i)
6846 if (mono_field_get_name (&class->fields [i]) == name)
6847 return &class->fields [i];
6848 g_assert_not_reached ();
6849 } else {
6850 if (class->field.count) {
6851 if ((idx >= class->field.first) && (idx < class->field.first + class->field.count)){
6852 return &class->fields [idx - class->field.first];
6856 class = class->parent;
6858 return NULL;
6862 * mono_class_get_field:
6863 * @class: the class to lookup the field.
6864 * @field_token: the field token
6866 * Returns: A MonoClassField representing the type and offset of
6867 * the field, or a NULL value if the field does not belong to this
6868 * class.
6870 MonoClassField *
6871 mono_class_get_field (MonoClass *class, guint32 field_token)
6873 int idx = mono_metadata_token_index (field_token);
6875 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
6877 return mono_class_get_field_idx (class, idx - 1);
6881 * mono_class_get_field_from_name:
6882 * @klass: the class to lookup the field.
6883 * @name: the field name
6885 * Search the class @klass and it's parents for a field with the name @name.
6887 * Returns: the MonoClassField pointer of the named field or NULL
6889 MonoClassField *
6890 mono_class_get_field_from_name (MonoClass *klass, const char *name)
6892 return mono_class_get_field_from_name_full (klass, name, NULL);
6896 * mono_class_get_field_from_name_full:
6897 * @klass: the class to lookup the field.
6898 * @name: the field name
6899 * @type: the type of the fields. This optional.
6901 * Search the class @klass and it's parents for a field with the name @name and type @type.
6903 * If @klass is an inflated generic type, the type comparison is done with the equivalent field
6904 * of its generic type definition.
6906 * Returns: the MonoClassField pointer of the named field or NULL
6908 MonoClassField *
6909 mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
6911 int i;
6913 mono_class_setup_fields_locking (klass);
6914 if (klass->exception_type)
6915 return NULL;
6917 while (klass) {
6918 for (i = 0; i < klass->field.count; ++i) {
6919 MonoClassField *field = &klass->fields [i];
6921 if (strcmp (name, mono_field_get_name (field)) != 0)
6922 continue;
6924 if (type) {
6925 MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
6926 if (!mono_metadata_type_equal_full (type, field_type, TRUE))
6927 continue;
6929 return field;
6931 klass = klass->parent;
6933 return NULL;
6937 * mono_class_get_field_token:
6938 * @field: the field we need the token of
6940 * Get the token of a field. Note that the tokesn is only valid for the image
6941 * the field was loaded from. Don't use this function for fields in dynamic types.
6943 * Returns: the token representing the field in the image it was loaded from.
6945 guint32
6946 mono_class_get_field_token (MonoClassField *field)
6948 MonoClass *klass = field->parent;
6949 int i;
6951 mono_class_setup_fields_locking (klass);
6953 while (klass) {
6954 if (!klass->fields)
6955 return 0;
6956 for (i = 0; i < klass->field.count; ++i) {
6957 if (&klass->fields [i] == field) {
6958 int idx = klass->field.first + i + 1;
6960 if (klass->image->uncompressed_metadata)
6961 idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx);
6962 return mono_metadata_make_token (MONO_TABLE_FIELD, idx);
6965 klass = klass->parent;
6968 g_assert_not_reached ();
6969 return 0;
6972 static int
6973 mono_field_get_index (MonoClassField *field)
6975 int index = field - field->parent->fields;
6977 g_assert (index >= 0 && index < field->parent->field.count);
6979 return index;
6983 * mono_class_get_field_default_value:
6985 * Return the default value of the field as a pointer into the metadata blob.
6987 const char*
6988 mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
6990 guint32 cindex;
6991 guint32 constant_cols [MONO_CONSTANT_SIZE];
6992 int field_index;
6993 MonoClass *klass = field->parent;
6995 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
6997 if (!klass->ext || !klass->ext->field_def_values) {
6998 MonoFieldDefaultValue *def_values;
7000 mono_class_alloc_ext (klass);
7002 def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
7004 mono_image_lock (klass->image);
7005 mono_memory_barrier ();
7006 if (!klass->ext->field_def_values)
7007 klass->ext->field_def_values = def_values;
7008 mono_image_unlock (klass->image);
7011 field_index = mono_field_get_index (field);
7013 if (!klass->ext->field_def_values [field_index].data) {
7014 cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
7015 if (!cindex)
7016 return NULL;
7018 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
7020 mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
7021 klass->ext->field_def_values [field_index].def_type = constant_cols [MONO_CONSTANT_TYPE];
7022 klass->ext->field_def_values [field_index].data = (gpointer)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
7025 *def_type = klass->ext->field_def_values [field_index].def_type;
7026 return klass->ext->field_def_values [field_index].data;
7029 static int
7030 mono_property_get_index (MonoProperty *prop)
7032 int index = prop - prop->parent->ext->properties;
7034 g_assert (index >= 0 && index < prop->parent->ext->property.count);
7036 return index;
7040 * mono_class_get_property_default_value:
7042 * Return the default value of the field as a pointer into the metadata blob.
7044 const char*
7045 mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type)
7047 guint32 cindex;
7048 guint32 constant_cols [MONO_CONSTANT_SIZE];
7049 MonoClass *klass = property->parent;
7051 g_assert (property->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT);
7053 * We don't cache here because it is not used by C# so it's quite rare, but
7054 * we still do the lookup in klass->ext because that is where the data
7055 * is stored for dynamic assemblies.
7058 if (image_is_dynamic (klass->image)) {
7059 int prop_index = mono_property_get_index (property);
7060 if (klass->ext->prop_def_values && klass->ext->prop_def_values [prop_index].data) {
7061 *def_type = klass->ext->prop_def_values [prop_index].def_type;
7062 return klass->ext->prop_def_values [prop_index].data;
7064 return NULL;
7066 cindex = mono_metadata_get_constant_index (klass->image, mono_class_get_property_token (property), 0);
7067 if (!cindex)
7068 return NULL;
7070 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
7071 *def_type = constant_cols [MONO_CONSTANT_TYPE];
7072 return (gpointer)mono_metadata_blob_heap (klass->image, constant_cols [MONO_CONSTANT_VALUE]);
7075 guint32
7076 mono_class_get_event_token (MonoEvent *event)
7078 MonoClass *klass = event->parent;
7079 int i;
7081 while (klass) {
7082 if (klass->ext) {
7083 for (i = 0; i < klass->ext->event.count; ++i) {
7084 if (&klass->ext->events [i] == event)
7085 return mono_metadata_make_token (MONO_TABLE_EVENT, klass->ext->event.first + i + 1);
7088 klass = klass->parent;
7091 g_assert_not_reached ();
7092 return 0;
7095 MonoProperty*
7096 mono_class_get_property_from_name (MonoClass *klass, const char *name)
7098 while (klass) {
7099 MonoProperty* p;
7100 gpointer iter = NULL;
7101 while ((p = mono_class_get_properties (klass, &iter))) {
7102 if (! strcmp (name, p->name))
7103 return p;
7105 klass = klass->parent;
7107 return NULL;
7110 guint32
7111 mono_class_get_property_token (MonoProperty *prop)
7113 MonoClass *klass = prop->parent;
7114 while (klass) {
7115 MonoProperty* p;
7116 int i = 0;
7117 gpointer iter = NULL;
7118 while ((p = mono_class_get_properties (klass, &iter))) {
7119 if (&klass->ext->properties [i] == prop)
7120 return mono_metadata_make_token (MONO_TABLE_PROPERTY, klass->ext->property.first + i + 1);
7122 i ++;
7124 klass = klass->parent;
7127 g_assert_not_reached ();
7128 return 0;
7131 char *
7132 mono_class_name_from_token (MonoImage *image, guint32 type_token)
7134 const char *name, *nspace;
7135 if (image_is_dynamic (image))
7136 return g_strdup_printf ("DynamicType 0x%08x", type_token);
7138 switch (type_token & 0xff000000){
7139 case MONO_TOKEN_TYPE_DEF: {
7140 guint32 cols [MONO_TYPEDEF_SIZE];
7141 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
7142 guint tidx = mono_metadata_token_index (type_token);
7144 if (tidx > tt->rows)
7145 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7147 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
7148 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7149 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7150 if (strlen (nspace) == 0)
7151 return g_strdup_printf ("%s", name);
7152 else
7153 return g_strdup_printf ("%s.%s", nspace, name);
7156 case MONO_TOKEN_TYPE_REF: {
7157 MonoError error;
7158 guint32 cols [MONO_TYPEREF_SIZE];
7159 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
7160 guint tidx = mono_metadata_token_index (type_token);
7162 if (tidx > t->rows)
7163 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7165 if (!mono_verifier_verify_typeref_row (image, tidx - 1, &error)) {
7166 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7167 mono_error_cleanup (&error);
7168 return msg;
7171 mono_metadata_decode_row (t, tidx-1, cols, MONO_TYPEREF_SIZE);
7172 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
7173 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
7174 if (strlen (nspace) == 0)
7175 return g_strdup_printf ("%s", name);
7176 else
7177 return g_strdup_printf ("%s.%s", nspace, name);
7180 case MONO_TOKEN_TYPE_SPEC:
7181 return g_strdup_printf ("Typespec 0x%08x", type_token);
7182 default:
7183 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7187 static char *
7188 mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
7190 if (image_is_dynamic (image))
7191 return g_strdup_printf ("DynamicAssembly %s", image->name);
7193 switch (type_token & 0xff000000){
7194 case MONO_TOKEN_TYPE_DEF:
7195 if (image->assembly)
7196 return mono_stringify_assembly_name (&image->assembly->aname);
7197 else if (image->assembly_name)
7198 return g_strdup (image->assembly_name);
7199 return g_strdup_printf ("%s", image->name ? image->name : "[Could not resolve assembly name");
7200 case MONO_TOKEN_TYPE_REF: {
7201 MonoError error;
7202 MonoAssemblyName aname;
7203 guint32 cols [MONO_TYPEREF_SIZE];
7204 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
7205 guint32 idx = mono_metadata_token_index (type_token);
7207 if (idx > t->rows)
7208 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7210 if (!mono_verifier_verify_typeref_row (image, idx - 1, &error)) {
7211 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7212 mono_error_cleanup (&error);
7213 return msg;
7215 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
7217 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
7218 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
7219 case MONO_RESOLUTION_SCOPE_MODULE:
7220 /* FIXME: */
7221 return g_strdup ("");
7222 case MONO_RESOLUTION_SCOPE_MODULEREF:
7223 /* FIXME: */
7224 return g_strdup ("");
7225 case MONO_RESOLUTION_SCOPE_TYPEREF:
7226 /* FIXME: */
7227 return g_strdup ("");
7228 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
7229 mono_assembly_get_assemblyref (image, idx - 1, &aname);
7230 return mono_stringify_assembly_name (&aname);
7231 default:
7232 g_assert_not_reached ();
7234 break;
7236 case MONO_TOKEN_TYPE_SPEC:
7237 /* FIXME: */
7238 return g_strdup ("");
7239 default:
7240 g_assert_not_reached ();
7243 return NULL;
7247 * mono_class_get_full:
7248 * @image: the image where the class resides
7249 * @type_token: the token for the class
7250 * @context: the generic context used to evaluate generic instantiations in
7251 * @deprecated: Functions that expose MonoGenericContext are going away in mono 4.0
7253 * Returns: the MonoClass that represents @type_token in @image
7255 MonoClass *
7256 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
7258 MonoError error;
7259 MonoClass *class;
7260 class = mono_class_get_checked (image, type_token, &error);
7262 if (class && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
7263 class = mono_class_inflate_generic_class_checked (class, context, &error);
7265 g_assert (mono_error_ok (&error)); /* FIXME deprecate this function and forbit the runtime from using it. */
7266 return class;
7270 MonoClass *
7271 mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
7273 MonoClass *class;
7275 mono_error_init (error);
7276 class = mono_class_get_checked (image, type_token, error);
7278 if (class && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
7279 class = mono_class_inflate_generic_class_checked (class, context, error);
7281 return class;
7284 * mono_class_get_checked:
7285 * @image: the image where the class resides
7286 * @type_token: the token for the class
7287 * @error: error object to return any error
7289 * Returns: the MonoClass that represents @type_token in @image
7291 MonoClass *
7292 mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
7294 MonoClass *class = NULL;
7296 mono_error_init (error);
7298 if (image_is_dynamic (image)) {
7299 int table = mono_metadata_token_table (type_token);
7301 if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
7302 mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
7303 return NULL;
7305 class = mono_lookup_dynamic_token (image, type_token, NULL); /*FIXME proper error handling*/
7306 goto done;
7309 switch (type_token & 0xff000000){
7310 case MONO_TOKEN_TYPE_DEF:
7311 class = mono_class_create_from_typedef (image, type_token, error);
7312 break;
7313 case MONO_TOKEN_TYPE_REF:
7314 class = mono_class_from_typeref_checked (image, type_token, error);
7315 break;
7316 case MONO_TOKEN_TYPE_SPEC:
7317 class = mono_class_create_from_typespec (image, type_token, NULL, error);
7318 break;
7319 default:
7320 mono_error_set_bad_image (error, image, "Unknown type token %x", type_token & 0xff000000);
7323 done:
7324 /* Generic case, should be avoided for when a better error is possible. */
7325 if (!class && mono_error_ok (error)) {
7326 char *name = mono_class_name_from_token (image, type_token);
7327 char *assembly = mono_assembly_name_from_token (image, type_token);
7328 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
7331 return class;
7336 * mono_type_get_checked:
7337 * @image: the image where the type resides
7338 * @type_token: the token for the type
7339 * @context: the generic context used to evaluate generic instantiations in
7340 * @error: Error handling context
7342 * This functions exists to fullfill the fact that sometimes it's desirable to have access to the
7344 * Returns: the MonoType that represents @type_token in @image
7346 MonoType *
7347 mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
7349 MonoType *type = NULL;
7350 gboolean inflated = FALSE;
7352 mono_error_init (error);
7354 //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
7355 if (image_is_dynamic (image))
7356 return mono_class_get_type (mono_lookup_dynamic_token (image, type_token, context));
7358 if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
7359 MonoClass *class = mono_class_get_checked (image, type_token, error);
7361 if (!class) {
7362 g_assert (!mono_loader_get_last_error ());
7363 return NULL;
7366 g_assert (class);
7367 return mono_class_get_type (class);
7370 type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
7372 if (!type) {
7373 g_assert (!mono_loader_get_last_error ());
7374 return NULL;
7377 if (inflated) {
7378 MonoType *tmp = type;
7379 type = mono_class_get_type (mono_class_from_mono_type (type));
7380 /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
7381 * A MonoClass::byval_arg of a generic type definion has type CLASS.
7382 * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with byval_arg.
7384 * The long term solution is to chaise this places and make then set MonoType::type correctly.
7385 * */
7386 if (type->type != tmp->type)
7387 type = tmp;
7388 else
7389 mono_metadata_free_type (tmp);
7391 return type;
7395 MonoClass *
7396 mono_class_get (MonoImage *image, guint32 type_token)
7398 return mono_class_get_full (image, type_token, NULL);
7402 * mono_image_init_name_cache:
7404 * Initializes the class name cache stored in image->name_cache.
7406 * LOCKING: Acquires the corresponding image lock.
7408 void
7409 mono_image_init_name_cache (MonoImage *image)
7411 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7412 guint32 cols [MONO_TYPEDEF_SIZE];
7413 const char *name;
7414 const char *nspace;
7415 guint32 i, visib, nspace_index;
7416 GHashTable *name_cache2, *nspace_table;
7418 mono_image_lock (image);
7420 if (image->name_cache) {
7421 mono_image_unlock (image);
7422 return;
7425 image->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
7427 if (image_is_dynamic (image)) {
7428 mono_image_unlock (image);
7429 return;
7432 /* Temporary hash table to avoid lookups in the nspace_table */
7433 name_cache2 = g_hash_table_new (NULL, NULL);
7435 for (i = 1; i <= t->rows; ++i) {
7436 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7437 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7439 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7440 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7442 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7443 continue;
7444 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7445 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7447 nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
7448 nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7449 if (!nspace_table) {
7450 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7451 g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
7452 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7453 nspace_table);
7455 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
7458 /* Load type names from EXPORTEDTYPES table */
7460 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7461 guint32 cols [MONO_EXP_TYPE_SIZE];
7462 int i;
7464 for (i = 0; i < t->rows; ++i) {
7465 mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
7466 name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
7467 nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
7469 nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
7470 nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7471 if (!nspace_table) {
7472 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7473 g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
7474 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7475 nspace_table);
7477 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
7481 g_hash_table_destroy (name_cache2);
7482 mono_image_unlock (image);
7485 /*FIXME Only dynamic assemblies should allow this operation.*/
7486 void
7487 mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
7488 const char *name, guint32 index)
7490 GHashTable *nspace_table;
7491 GHashTable *name_cache;
7492 guint32 old_index;
7494 mono_image_lock (image);
7496 if (!image->name_cache)
7497 mono_image_init_name_cache (image);
7499 name_cache = image->name_cache;
7500 if (!(nspace_table = g_hash_table_lookup (name_cache, nspace))) {
7501 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7502 g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
7505 if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
7506 g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
7508 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
7510 mono_image_unlock (image);
7513 typedef struct {
7514 gconstpointer key;
7515 gpointer value;
7516 } FindUserData;
7518 static void
7519 find_nocase (gpointer key, gpointer value, gpointer user_data)
7521 char *name = (char*)key;
7522 FindUserData *data = (FindUserData*)user_data;
7524 if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
7525 data->value = value;
7529 * mono_class_from_name_case:
7530 * @image: The MonoImage where the type is looked up in
7531 * @name_space: the type namespace
7532 * @name: the type short name.
7533 * @deprecated: use the _checked variant
7535 * Obtains a MonoClass with a given namespace and a given name which
7536 * is located in the given MonoImage. The namespace and name
7537 * lookups are case insensitive.
7539 MonoClass *
7540 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
7542 MonoError error;
7543 MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error);
7544 g_assert (!mono_error_ok (&error));
7545 return res;
7548 MonoClass *
7549 mono_class_from_name_case_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
7551 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7552 guint32 cols [MONO_TYPEDEF_SIZE];
7553 const char *n;
7554 const char *nspace;
7555 guint32 i, visib;
7557 mono_error_init (error);
7559 if (image_is_dynamic (image)) {
7560 guint32 token = 0;
7561 FindUserData user_data;
7563 mono_image_lock (image);
7565 if (!image->name_cache)
7566 mono_image_init_name_cache (image);
7568 user_data.key = name_space;
7569 user_data.value = NULL;
7570 g_hash_table_foreach (image->name_cache, find_nocase, &user_data);
7572 if (user_data.value) {
7573 GHashTable *nspace_table = (GHashTable*)user_data.value;
7575 user_data.key = name;
7576 user_data.value = NULL;
7578 g_hash_table_foreach (nspace_table, find_nocase, &user_data);
7580 if (user_data.value)
7581 token = GPOINTER_TO_UINT (user_data.value);
7584 mono_image_unlock (image);
7586 if (token)
7587 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | token, error);
7588 else
7589 return NULL;
7593 /* add a cache if needed */
7594 for (i = 1; i <= t->rows; ++i) {
7595 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7596 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7598 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7599 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7601 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7602 continue;
7603 n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7604 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7605 if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
7606 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | i, error);
7608 return NULL;
7611 static MonoClass*
7612 return_nested_in (MonoClass *class, char *nested)
7614 MonoClass *found;
7615 char *s = strchr (nested, '/');
7616 gpointer iter = NULL;
7618 if (s) {
7619 *s = 0;
7620 s++;
7623 while ((found = mono_class_get_nested_types (class, &iter))) {
7624 if (strcmp (found->name, nested) == 0) {
7625 if (s)
7626 return return_nested_in (found, s);
7627 return found;
7630 return NULL;
7633 static MonoClass*
7634 search_modules (MonoImage *image, const char *name_space, const char *name)
7636 MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
7637 MonoImage *file_image;
7638 MonoClass *class;
7639 int i;
7642 * The EXPORTEDTYPES table only contains public types, so have to search the
7643 * modules as well.
7644 * Note: image->modules contains the contents of the MODULEREF table, while
7645 * the real module list is in the FILE table.
7647 for (i = 0; i < file_table->rows; i++) {
7648 guint32 cols [MONO_FILE_SIZE];
7649 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
7650 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
7651 continue;
7653 file_image = mono_image_load_file_for_image (image, i + 1);
7654 if (file_image) {
7655 class = mono_class_from_name (file_image, name_space, name);
7656 if (class)
7657 return class;
7661 return NULL;
7665 * mono_class_from_name:
7666 * @image: The MonoImage where the type is looked up in
7667 * @name_space: the type namespace
7668 * @name: the type short name.
7670 * Obtains a MonoClass with a given namespace and a given name which
7671 * is located in the given MonoImage.
7673 * To reference nested classes, use the "/" character as a separator.
7674 * For example use "Foo/Bar" to reference the class Bar that is nested
7675 * inside Foo, like this: "class Foo { class Bar {} }".
7677 MonoClass *
7678 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
7680 MonoError error;
7681 GHashTable *nspace_table;
7682 MonoImage *loaded_image;
7683 guint32 token = 0;
7684 int i;
7685 MonoClass *class;
7686 char *nested;
7687 char buf [1024];
7689 if ((nested = strchr (name, '/'))) {
7690 int pos = nested - name;
7691 int len = strlen (name);
7692 if (len > 1023)
7693 return NULL;
7694 memcpy (buf, name, len + 1);
7695 buf [pos] = 0;
7696 nested = buf + pos + 1;
7697 name = buf;
7700 /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */
7701 if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
7702 gboolean res = get_class_from_name (image, name_space, name, &class);
7703 if (res) {
7704 if (!class)
7705 class = search_modules (image, name_space, name);
7706 if (nested)
7707 return class ? return_nested_in (class, nested) : NULL;
7708 else
7709 return class;
7713 mono_image_lock (image);
7715 if (!image->name_cache)
7716 mono_image_init_name_cache (image);
7718 nspace_table = g_hash_table_lookup (image->name_cache, name_space);
7720 if (nspace_table)
7721 token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
7723 mono_image_unlock (image);
7725 if (!token && image_is_dynamic (image) && image->modules) {
7726 /* Search modules as well */
7727 for (i = 0; i < image->module_count; ++i) {
7728 MonoImage *module = image->modules [i];
7730 class = mono_class_from_name (module, name_space, name);
7731 if (class)
7732 return class;
7736 if (!token) {
7737 class = search_modules (image, name_space, name);
7738 if (class)
7739 return class;
7742 if (!token)
7743 return NULL;
7745 if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
7746 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7747 guint32 cols [MONO_EXP_TYPE_SIZE];
7748 guint32 idx, impl;
7750 idx = mono_metadata_token_index (token);
7752 mono_metadata_decode_row (t, idx - 1, cols, MONO_EXP_TYPE_SIZE);
7754 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
7755 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
7756 loaded_image = mono_assembly_load_module (image->assembly, impl >> MONO_IMPLEMENTATION_BITS);
7757 if (!loaded_image)
7758 return NULL;
7759 class = mono_class_from_name (loaded_image, name_space, name);
7760 if (nested)
7761 return return_nested_in (class, nested);
7762 return class;
7763 } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
7764 guint32 assembly_idx;
7766 assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
7768 mono_assembly_load_reference (image, assembly_idx - 1);
7769 g_assert (image->references [assembly_idx - 1]);
7770 if (image->references [assembly_idx - 1] == (gpointer)-1)
7771 return NULL;
7772 else
7773 /* FIXME: Cycle detection */
7774 return mono_class_from_name (image->references [assembly_idx - 1]->image, name_space, name);
7775 } else {
7776 g_error ("not yet implemented");
7780 token = MONO_TOKEN_TYPE_DEF | token;
7782 class = mono_class_get_checked (image, token, &error);
7783 if (!mono_error_ok (&error)) {
7784 mono_loader_set_error_from_mono_error (&error);
7785 mono_error_cleanup (&error); /* FIXME Don't swallow the error */
7787 if (nested)
7788 return return_nested_in (class, nested);
7789 return class;
7793 * mono_class_is_subclass_of:
7794 * @klass: class to probe if it is a subclass of another one
7795 * @klassc: the class we suspect is the base class
7796 * @check_interfaces: whether we should perform interface checks
7798 * This method determines whether @klass is a subclass of @klassc.
7800 * If the @check_interfaces flag is set, then if @klassc is an interface
7801 * this method return true if the @klass implements the interface or
7802 * if @klass is an interface, if one of its base classes is @klass.
7804 * If @check_interfaces is false then, then if @klass is not an interface
7805 * then it returns true if the @klass is a subclass of @klassc.
7807 * if @klass is an interface and @klassc is System.Object, then this function
7808 * return true.
7811 gboolean
7812 mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
7813 gboolean check_interfaces)
7815 /*FIXME test for interfaces with variant generic arguments*/
7817 if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
7818 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
7819 return TRUE;
7820 } else if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && MONO_CLASS_IS_INTERFACE (klass)) {
7821 int i;
7823 for (i = 0; i < klass->interface_count; i ++) {
7824 MonoClass *ic = klass->interfaces [i];
7825 if (ic == klassc)
7826 return TRUE;
7828 } else {
7829 if (!MONO_CLASS_IS_INTERFACE (klass) && mono_class_has_parent (klass, klassc))
7830 return TRUE;
7834 * MS.NET thinks interfaces are a subclass of Object, so we think it as
7835 * well.
7837 if (klassc == mono_defaults.object_class)
7838 return TRUE;
7840 return FALSE;
7843 static gboolean
7844 mono_type_is_generic_argument (MonoType *type)
7846 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
7849 gboolean
7850 mono_class_has_variant_generic_params (MonoClass *klass)
7852 int i;
7853 MonoGenericContainer *container;
7855 if (!klass->generic_class)
7856 return FALSE;
7858 container = klass->generic_class->container_class->generic_container;
7860 for (i = 0; i < container->type_argc; ++i)
7861 if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
7862 return TRUE;
7864 return FALSE;
7867 static gboolean
7868 mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
7870 if (target == candidate)
7871 return TRUE;
7873 if (check_for_reference_conv &&
7874 mono_type_is_generic_argument (&target->byval_arg) &&
7875 mono_type_is_generic_argument (&candidate->byval_arg)) {
7876 MonoGenericParam *gparam = candidate->byval_arg.data.generic_param;
7877 MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
7879 if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
7880 return FALSE;
7882 if (!mono_class_is_assignable_from (target, candidate))
7883 return FALSE;
7884 return TRUE;
7888 * @container the generic container from the GTD
7889 * @klass: the class to be assigned to
7890 * @oklass: the source class
7892 * Both klass and oklass must be instances of the same generic interface.
7893 * Return true if @klass can be assigned to a @klass variable
7895 gboolean
7896 mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
7898 int j;
7899 MonoType **klass_argv, **oklass_argv;
7900 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
7901 MonoGenericContainer *container = klass_gtd->generic_container;
7903 if (klass == oklass)
7904 return TRUE;
7906 /*Viable candidates are instances of the same generic interface*/
7907 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
7908 return FALSE;
7910 klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
7911 oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
7913 for (j = 0; j < container->type_argc; ++j) {
7914 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
7915 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
7917 if (param1_class->valuetype != param2_class->valuetype || (param1_class->valuetype && param1_class != param2_class))
7918 return FALSE;
7921 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
7922 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
7924 if (param1_class != param2_class) {
7925 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
7926 if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
7927 return FALSE;
7928 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
7929 if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
7930 return FALSE;
7931 } else
7932 return FALSE;
7935 return TRUE;
7938 static gboolean
7939 mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
7941 MonoGenericParam *gparam, *ogparam;
7942 MonoGenericParamInfo *tinfo, *cinfo;
7943 MonoClass **candidate_class;
7944 gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
7945 int tmask, cmask;
7947 if (target == candidate)
7948 return TRUE;
7949 if (target->byval_arg.type != candidate->byval_arg.type)
7950 return FALSE;
7952 gparam = target->byval_arg.data.generic_param;
7953 ogparam = candidate->byval_arg.data.generic_param;
7954 tinfo = mono_generic_param_info (gparam);
7955 cinfo = mono_generic_param_info (ogparam);
7957 class_constraint_satisfied = FALSE;
7958 valuetype_constraint_satisfied = FALSE;
7960 /*candidate must have a super set of target's special constraints*/
7961 tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
7962 cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
7964 if (cinfo->constraints) {
7965 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
7966 MonoClass *cc = *candidate_class;
7968 if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
7969 class_constraint_satisfied = TRUE;
7970 else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
7971 valuetype_constraint_satisfied = TRUE;
7974 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
7975 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
7977 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
7978 return FALSE;
7979 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
7980 return FALSE;
7981 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
7982 valuetype_constraint_satisfied)) {
7983 return FALSE;
7987 /*candidate type constraints must be a superset of target's*/
7988 if (tinfo->constraints) {
7989 MonoClass **target_class;
7990 for (target_class = tinfo->constraints; *target_class; ++target_class) {
7991 MonoClass *tc = *target_class;
7994 * A constraint from @target might inflate into @candidate itself and in that case we don't need
7995 * check it's constraints since it satisfy the constraint by itself.
7997 if (mono_metadata_type_equal (&tc->byval_arg, &candidate->byval_arg))
7998 continue;
8000 if (!cinfo->constraints)
8001 return FALSE;
8003 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8004 MonoClass *cc = *candidate_class;
8006 if (mono_class_is_assignable_from (tc, cc))
8007 break;
8010 * This happens when we have the following:
8012 * Bar<K> where K : IFace
8013 * Foo<T, U> where T : U where U : IFace
8014 * ...
8015 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
8018 if (mono_type_is_generic_argument (&cc->byval_arg)) {
8019 if (mono_gparam_is_assignable_from (target, cc))
8020 break;
8023 if (!*candidate_class)
8024 return FALSE;
8028 /*candidate itself must have a constraint that satisfy target*/
8029 if (cinfo->constraints) {
8030 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8031 MonoClass *cc = *candidate_class;
8032 if (mono_class_is_assignable_from (target, cc))
8033 return TRUE;
8036 return FALSE;
8040 * mono_class_is_assignable_from:
8041 * @klass: the class to be assigned to
8042 * @oklass: the source class
8044 * Return: true if an instance of object oklass can be assigned to an
8045 * instance of object @klass
8047 gboolean
8048 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
8050 /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
8051 if (!klass->inited)
8052 mono_class_init (klass);
8054 if (!oklass->inited)
8055 mono_class_init (oklass);
8057 if (klass->exception_type || oklass->exception_type)
8058 return FALSE;
8060 if (mono_type_is_generic_argument (&klass->byval_arg)) {
8061 if (!mono_type_is_generic_argument (&oklass->byval_arg))
8062 return FALSE;
8063 return mono_gparam_is_assignable_from (klass, oklass);
8066 if (MONO_CLASS_IS_INTERFACE (klass)) {
8067 if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
8068 MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
8069 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
8070 int i;
8072 if (constraints) {
8073 for (i = 0; constraints [i]; ++i) {
8074 if (mono_class_is_assignable_from (klass, constraints [i]))
8075 return TRUE;
8079 return FALSE;
8082 /* interface_offsets might not be set for dynamic classes */
8083 if (oklass->ref_info_handle && !oklass->interface_bitmap)
8085 * oklass might be a generic type parameter but they have
8086 * interface_offsets set.
8088 return mono_reflection_call_is_assignable_to (oklass, klass);
8089 if (!oklass->interface_bitmap)
8090 /* Happens with generic instances of not-yet created dynamic types */
8091 return FALSE;
8092 if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
8093 return TRUE;
8095 if (mono_class_has_variant_generic_params (klass)) {
8096 MonoError error;
8097 int i;
8098 mono_class_setup_interfaces (oklass, &error);
8099 if (!mono_error_ok (&error)) {
8100 mono_error_cleanup (&error);
8101 return FALSE;
8104 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
8105 for (i = 0; i < oklass->interface_offsets_count; ++i) {
8106 MonoClass *iface = oklass->interfaces_packed [i];
8108 if (mono_class_is_variant_compatible (klass, iface, FALSE))
8109 return TRUE;
8112 return FALSE;
8113 } else if (klass->delegate) {
8114 if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE))
8115 return TRUE;
8116 }else if (klass->rank) {
8117 MonoClass *eclass, *eoclass;
8119 if (oklass->rank != klass->rank)
8120 return FALSE;
8122 /* vectors vs. one dimensional arrays */
8123 if (oklass->byval_arg.type != klass->byval_arg.type)
8124 return FALSE;
8126 eclass = klass->cast_class;
8127 eoclass = oklass->cast_class;
8130 * a is b does not imply a[] is b[] when a is a valuetype, and
8131 * b is a reference type.
8134 if (eoclass->valuetype) {
8135 if ((eclass == mono_defaults.enum_class) ||
8136 (eclass == mono_defaults.enum_class->parent) ||
8137 (eclass == mono_defaults.object_class))
8138 return FALSE;
8141 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
8142 } else if (mono_class_is_nullable (klass)) {
8143 if (mono_class_is_nullable (oklass))
8144 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
8145 else
8146 return mono_class_is_assignable_from (klass->cast_class, oklass);
8147 } else if (klass == mono_defaults.object_class)
8148 return TRUE;
8150 return mono_class_has_parent (oklass, klass);
8153 /*Check if @oklass is variant compatible with @klass.*/
8154 static gboolean
8155 mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
8157 int j;
8158 MonoType **klass_argv, **oklass_argv;
8159 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
8160 MonoGenericContainer *container = klass_gtd->generic_container;
8162 /*Viable candidates are instances of the same generic interface*/
8163 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
8164 return FALSE;
8166 klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
8167 oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
8169 for (j = 0; j < container->type_argc; ++j) {
8170 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
8171 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
8173 if (param1_class->valuetype != param2_class->valuetype)
8174 return FALSE;
8177 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
8178 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
8180 if (param1_class != param2_class) {
8181 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
8182 if (!mono_class_is_assignable_from_slow (param1_class, param2_class))
8183 return FALSE;
8184 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
8185 if (!mono_class_is_assignable_from_slow (param2_class, param1_class))
8186 return FALSE;
8187 } else
8188 return FALSE;
8191 return TRUE;
8193 /*Check if @candidate implements the interface @target*/
8194 static gboolean
8195 mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
8197 MonoError error;
8198 int i;
8199 gboolean is_variant = mono_class_has_variant_generic_params (target);
8201 if (is_variant && MONO_CLASS_IS_INTERFACE (candidate)) {
8202 if (mono_class_is_variant_compatible_slow (target, candidate))
8203 return TRUE;
8206 do {
8207 if (candidate == target)
8208 return TRUE;
8210 /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
8211 if (image_is_dynamic (candidate->image) && !candidate->wastypebuilder) {
8212 MonoReflectionTypeBuilder *tb = mono_class_get_ref_info (candidate);
8213 int j;
8214 if (tb && tb->interfaces) {
8215 for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
8216 MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
8217 MonoClass *iface_class;
8219 /* we can't realize the type here since it can do pretty much anything. */
8220 if (!iface->type)
8221 continue;
8222 iface_class = mono_class_from_mono_type (iface->type);
8223 if (iface_class == target)
8224 return TRUE;
8225 if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class))
8226 return TRUE;
8227 if (mono_class_implement_interface_slow (target, iface_class))
8228 return TRUE;
8231 } else {
8232 /*setup_interfaces don't mono_class_init anything*/
8233 /*FIXME this doesn't handle primitive type arrays.
8234 ICollection<sbyte> x byte [] won't work because candidate->interfaces, for byte[], won't have IList<sbyte>.
8235 A possible way to fix this would be to move that to setup_interfaces from setup_interface_offsets.
8237 mono_class_setup_interfaces (candidate, &error);
8238 if (!mono_error_ok (&error)) {
8239 mono_error_cleanup (&error);
8240 return FALSE;
8243 for (i = 0; i < candidate->interface_count; ++i) {
8244 if (candidate->interfaces [i] == target)
8245 return TRUE;
8247 if (is_variant && mono_class_is_variant_compatible_slow (target, candidate->interfaces [i]))
8248 return TRUE;
8250 if (mono_class_implement_interface_slow (target, candidate->interfaces [i]))
8251 return TRUE;
8254 candidate = candidate->parent;
8255 } while (candidate);
8257 return FALSE;
8261 * Check if @oklass can be assigned to @klass.
8262 * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context.
8264 gboolean
8265 mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
8267 if (candidate == target)
8268 return TRUE;
8269 if (target == mono_defaults.object_class)
8270 return TRUE;
8272 if (mono_class_has_parent (candidate, target))
8273 return TRUE;
8275 /*If target is not an interface there is no need to check them.*/
8276 if (MONO_CLASS_IS_INTERFACE (target))
8277 return mono_class_implement_interface_slow (target, candidate);
8279 if (target->delegate && mono_class_has_variant_generic_params (target))
8280 return mono_class_is_variant_compatible (target, candidate, FALSE);
8282 if (target->rank) {
8283 MonoClass *eclass, *eoclass;
8285 if (target->rank != candidate->rank)
8286 return FALSE;
8288 /* vectors vs. one dimensional arrays */
8289 if (target->byval_arg.type != candidate->byval_arg.type)
8290 return FALSE;
8292 eclass = target->cast_class;
8293 eoclass = candidate->cast_class;
8296 * a is b does not imply a[] is b[] when a is a valuetype, and
8297 * b is a reference type.
8300 if (eoclass->valuetype) {
8301 if ((eclass == mono_defaults.enum_class) ||
8302 (eclass == mono_defaults.enum_class->parent) ||
8303 (eclass == mono_defaults.object_class))
8304 return FALSE;
8307 return mono_class_is_assignable_from_slow (target->cast_class, candidate->cast_class);
8309 /*FIXME properly handle nullables */
8310 /*FIXME properly handle (M)VAR */
8311 return FALSE;
8315 * mono_class_get_cctor:
8316 * @klass: A MonoClass pointer
8318 * Returns: the static constructor of @klass if it exists, NULL otherwise.
8320 MonoMethod*
8321 mono_class_get_cctor (MonoClass *klass)
8323 MonoCachedClassInfo cached_info;
8325 if (image_is_dynamic (klass->image)) {
8327 * has_cctor is not set for these classes because mono_class_init () is
8328 * not run for them.
8330 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8333 if (!klass->has_cctor)
8334 return NULL;
8336 if (mono_class_get_cached_class_info (klass, &cached_info)) {
8337 MonoError error;
8338 MonoMethod *result = mono_get_method_checked (klass->image, cached_info.cctor_token, klass, NULL, &error);
8339 if (!mono_error_ok (&error))
8340 g_error ("Could not lookup class cctor from cached metadata due to %s", mono_error_get_message (&error));
8341 return result;
8344 if (klass->generic_class && !klass->methods)
8345 return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class));
8347 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8351 * mono_class_get_finalizer:
8352 * @klass: The MonoClass pointer
8354 * Returns: the finalizer method of @klass if it exists, NULL otherwise.
8356 MonoMethod*
8357 mono_class_get_finalizer (MonoClass *klass)
8359 MonoCachedClassInfo cached_info;
8361 if (!klass->inited)
8362 mono_class_init (klass);
8363 if (!mono_class_has_finalizer (klass))
8364 return NULL;
8366 if (mono_class_get_cached_class_info (klass, &cached_info)) {
8367 MonoError error;
8368 MonoMethod *result = mono_get_method_checked (cached_info.finalize_image, cached_info.finalize_token, NULL, NULL, &error);
8369 if (!mono_error_ok (&error))
8370 g_error ("Could not lookup finalizer from cached metadata due to %s", mono_error_get_message (&error));
8371 return result;
8372 }else {
8373 mono_class_setup_vtable (klass);
8374 return klass->vtable [finalize_slot];
8379 * mono_class_needs_cctor_run:
8380 * @klass: the MonoClass pointer
8381 * @caller: a MonoMethod describing the caller
8383 * Determines whenever the class has a static constructor and whenever it
8384 * needs to be called when executing CALLER.
8386 gboolean
8387 mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
8389 MonoMethod *method;
8391 method = mono_class_get_cctor (klass);
8392 if (method)
8393 return (method == caller) ? FALSE : TRUE;
8394 else
8395 return FALSE;
8399 * mono_class_array_element_size:
8400 * @klass:
8402 * Returns: the number of bytes an element of type @klass
8403 * uses when stored into an array.
8405 gint32
8406 mono_class_array_element_size (MonoClass *klass)
8408 MonoType *type = &klass->byval_arg;
8410 handle_enum:
8411 switch (type->type) {
8412 case MONO_TYPE_I1:
8413 case MONO_TYPE_U1:
8414 case MONO_TYPE_BOOLEAN:
8415 return 1;
8416 case MONO_TYPE_I2:
8417 case MONO_TYPE_U2:
8418 case MONO_TYPE_CHAR:
8419 return 2;
8420 case MONO_TYPE_I4:
8421 case MONO_TYPE_U4:
8422 case MONO_TYPE_R4:
8423 return 4;
8424 case MONO_TYPE_I:
8425 case MONO_TYPE_U:
8426 case MONO_TYPE_PTR:
8427 case MONO_TYPE_CLASS:
8428 case MONO_TYPE_STRING:
8429 case MONO_TYPE_OBJECT:
8430 case MONO_TYPE_SZARRAY:
8431 case MONO_TYPE_ARRAY:
8432 case MONO_TYPE_VAR:
8433 case MONO_TYPE_MVAR:
8434 return sizeof (gpointer);
8435 case MONO_TYPE_I8:
8436 case MONO_TYPE_U8:
8437 case MONO_TYPE_R8:
8438 return 8;
8439 case MONO_TYPE_VALUETYPE:
8440 if (type->data.klass->enumtype) {
8441 type = mono_class_enum_basetype (type->data.klass);
8442 klass = klass->element_class;
8443 goto handle_enum;
8445 return mono_class_instance_size (klass) - sizeof (MonoObject);
8446 case MONO_TYPE_GENERICINST:
8447 type = &type->data.generic_class->container_class->byval_arg;
8448 goto handle_enum;
8450 case MONO_TYPE_VOID:
8451 return 0;
8453 default:
8454 g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
8456 return -1;
8460 * mono_array_element_size:
8461 * @ac: pointer to a #MonoArrayClass
8463 * Returns: the size of single array element.
8465 gint32
8466 mono_array_element_size (MonoClass *ac)
8468 g_assert (ac->rank);
8469 return ac->sizes.element_size;
8472 gpointer
8473 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
8474 MonoGenericContext *context)
8476 MonoError error;
8477 gpointer res = mono_ldtoken_checked (image, token, handle_class, context, &error);
8478 g_assert (mono_error_ok (&error));
8479 return res;
8482 gpointer
8483 mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
8484 MonoGenericContext *context, MonoError *error)
8486 mono_error_init (error);
8488 if (image_is_dynamic (image)) {
8489 MonoClass *tmp_handle_class;
8490 gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context);
8492 g_assert (tmp_handle_class);
8493 if (handle_class)
8494 *handle_class = tmp_handle_class;
8496 if (tmp_handle_class == mono_defaults.typehandle_class)
8497 return &((MonoClass*)obj)->byval_arg;
8498 else
8499 return obj;
8502 switch (token & 0xff000000) {
8503 case MONO_TOKEN_TYPE_DEF:
8504 case MONO_TOKEN_TYPE_REF:
8505 case MONO_TOKEN_TYPE_SPEC: {
8506 MonoType *type;
8507 if (handle_class)
8508 *handle_class = mono_defaults.typehandle_class;
8509 type = mono_type_get_checked (image, token, context, error);
8510 if (!type)
8511 return NULL;
8513 mono_class_init (mono_class_from_mono_type (type));
8514 /* We return a MonoType* as handle */
8515 return type;
8517 case MONO_TOKEN_FIELD_DEF: {
8518 MonoClass *class;
8519 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
8520 if (!type) {
8521 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
8522 return NULL;
8524 if (handle_class)
8525 *handle_class = mono_defaults.fieldhandle_class;
8526 class = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_DEF | type, context, error);
8527 if (!class)
8528 return NULL;
8530 mono_class_init (class);
8531 return mono_class_get_field (class, token);
8533 case MONO_TOKEN_METHOD_DEF:
8534 case MONO_TOKEN_METHOD_SPEC: {
8535 MonoMethod *meth;
8536 meth = mono_get_method_checked (image, token, NULL, context, error);
8537 if (handle_class)
8538 *handle_class = mono_defaults.methodhandle_class;
8539 if (!meth)
8540 return NULL;
8542 return meth;
8544 case MONO_TOKEN_MEMBER_REF: {
8545 guint32 cols [MONO_MEMBERREF_SIZE];
8546 const char *sig;
8547 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE);
8548 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
8549 mono_metadata_decode_blob_size (sig, &sig);
8550 if (*sig == 0x6) { /* it's a field */
8551 MonoClass *klass;
8552 MonoClassField *field;
8553 field = mono_field_from_token_checked (image, token, &klass, context, error);
8554 if (handle_class)
8555 *handle_class = mono_defaults.fieldhandle_class;
8556 return field;
8557 } else {
8558 MonoMethod *meth;
8559 meth = mono_get_method_checked (image, token, NULL, context, error);
8560 if (handle_class)
8561 *handle_class = mono_defaults.methodhandle_class;
8562 return meth;
8565 default:
8566 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
8568 return NULL;
8572 * This function might need to call runtime functions so it can't be part
8573 * of the metadata library.
8575 static MonoLookupDynamicToken lookup_dynamic = NULL;
8577 void
8578 mono_install_lookup_dynamic_token (MonoLookupDynamicToken func)
8580 lookup_dynamic = func;
8583 gpointer
8584 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
8586 MonoClass *handle_class;
8588 return lookup_dynamic (image, token, TRUE, &handle_class, context);
8591 gpointer
8592 mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
8594 return lookup_dynamic (image, token, valid_token, handle_class, context);
8597 static MonoGetCachedClassInfo get_cached_class_info = NULL;
8599 void
8600 mono_install_get_cached_class_info (MonoGetCachedClassInfo func)
8602 get_cached_class_info = func;
8605 static gboolean
8606 mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
8608 if (!get_cached_class_info)
8609 return FALSE;
8610 else
8611 return get_cached_class_info (klass, res);
8614 void
8615 mono_install_get_class_from_name (MonoGetClassFromName func)
8617 get_class_from_name = func;
8620 MonoImage*
8621 mono_class_get_image (MonoClass *klass)
8623 return klass->image;
8627 * mono_class_get_element_class:
8628 * @klass: the MonoClass to act on
8630 * Returns: the element class of an array or an enumeration.
8632 MonoClass*
8633 mono_class_get_element_class (MonoClass *klass)
8635 return klass->element_class;
8639 * mono_class_is_valuetype:
8640 * @klass: the MonoClass to act on
8642 * Returns: true if the MonoClass represents a ValueType.
8644 gboolean
8645 mono_class_is_valuetype (MonoClass *klass)
8647 return klass->valuetype;
8651 * mono_class_is_enum:
8652 * @klass: the MonoClass to act on
8654 * Returns: true if the MonoClass represents an enumeration.
8656 gboolean
8657 mono_class_is_enum (MonoClass *klass)
8659 return klass->enumtype;
8663 * mono_class_enum_basetype:
8664 * @klass: the MonoClass to act on
8666 * Returns: the underlying type representation for an enumeration.
8668 MonoType*
8669 mono_class_enum_basetype (MonoClass *klass)
8671 if (klass->element_class == klass)
8672 /* SRE or broken types */
8673 return NULL;
8674 else
8675 return &klass->element_class->byval_arg;
8679 * mono_class_get_parent
8680 * @klass: the MonoClass to act on
8682 * Returns: the parent class for this class.
8684 MonoClass*
8685 mono_class_get_parent (MonoClass *klass)
8687 return klass->parent;
8691 * mono_class_get_nesting_type;
8692 * @klass: the MonoClass to act on
8694 * Returns: the container type where this type is nested or NULL if this type is not a nested type.
8696 MonoClass*
8697 mono_class_get_nesting_type (MonoClass *klass)
8699 return klass->nested_in;
8703 * mono_class_get_rank:
8704 * @klass: the MonoClass to act on
8706 * Returns: the rank for the array (the number of dimensions).
8709 mono_class_get_rank (MonoClass *klass)
8711 return klass->rank;
8715 * mono_class_get_flags:
8716 * @klass: the MonoClass to act on
8718 * The type flags from the TypeDef table from the metadata.
8719 * see the TYPE_ATTRIBUTE_* definitions on tabledefs.h for the
8720 * different values.
8722 * Returns: the flags from the TypeDef table.
8724 guint32
8725 mono_class_get_flags (MonoClass *klass)
8727 return klass->flags;
8731 * mono_class_get_name
8732 * @klass: the MonoClass to act on
8734 * Returns: the name of the class.
8736 const char*
8737 mono_class_get_name (MonoClass *klass)
8739 return klass->name;
8743 * mono_class_get_namespace:
8744 * @klass: the MonoClass to act on
8746 * Returns: the namespace of the class.
8748 const char*
8749 mono_class_get_namespace (MonoClass *klass)
8751 return klass->name_space;
8755 * mono_class_get_type:
8756 * @klass: the MonoClass to act on
8758 * This method returns the internal Type representation for the class.
8760 * Returns: the MonoType from the class.
8762 MonoType*
8763 mono_class_get_type (MonoClass *klass)
8765 return &klass->byval_arg;
8769 * mono_class_get_type_token
8770 * @klass: the MonoClass to act on
8772 * This method returns type token for the class.
8774 * Returns: the type token for the class.
8776 guint32
8777 mono_class_get_type_token (MonoClass *klass)
8779 return klass->type_token;
8783 * mono_class_get_byref_type:
8784 * @klass: the MonoClass to act on
8788 MonoType*
8789 mono_class_get_byref_type (MonoClass *klass)
8791 return &klass->this_arg;
8795 * mono_class_num_fields:
8796 * @klass: the MonoClass to act on
8798 * Returns: the number of static and instance fields in the class.
8801 mono_class_num_fields (MonoClass *klass)
8803 return klass->field.count;
8807 * mono_class_num_methods:
8808 * @klass: the MonoClass to act on
8810 * Returns: the number of methods in the class.
8813 mono_class_num_methods (MonoClass *klass)
8815 return klass->method.count;
8819 * mono_class_num_properties
8820 * @klass: the MonoClass to act on
8822 * Returns: the number of properties in the class.
8825 mono_class_num_properties (MonoClass *klass)
8827 mono_class_setup_properties (klass);
8829 return klass->ext->property.count;
8833 * mono_class_num_events:
8834 * @klass: the MonoClass to act on
8836 * Returns: the number of events in the class.
8839 mono_class_num_events (MonoClass *klass)
8841 mono_class_setup_events (klass);
8843 return klass->ext->event.count;
8847 * mono_class_get_fields:
8848 * @klass: the MonoClass to act on
8850 * This routine is an iterator routine for retrieving the fields in a class.
8852 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8853 * iterate over all of the elements. When no more values are
8854 * available, the return value is NULL.
8856 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
8858 MonoClassField*
8859 mono_class_get_fields (MonoClass* klass, gpointer *iter)
8861 MonoClassField* field;
8862 if (!iter)
8863 return NULL;
8864 if (!*iter) {
8865 mono_class_setup_fields_locking (klass);
8866 if (klass->exception_type)
8867 return NULL;
8868 /* start from the first */
8869 if (klass->field.count) {
8870 return *iter = &klass->fields [0];
8871 } else {
8872 /* no fields */
8873 return NULL;
8876 field = *iter;
8877 field++;
8878 if (field < &klass->fields [klass->field.count]) {
8879 return *iter = field;
8881 return NULL;
8885 * mono_class_get_methods
8886 * @klass: the MonoClass to act on
8888 * This routine is an iterator routine for retrieving the fields in a class.
8890 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8891 * iterate over all of the elements. When no more values are
8892 * available, the return value is NULL.
8894 * Returns: a MonoMethod on each iteration or NULL when no more methods are available.
8896 MonoMethod*
8897 mono_class_get_methods (MonoClass* klass, gpointer *iter)
8899 MonoMethod** method;
8900 if (!iter)
8901 return NULL;
8902 if (!*iter) {
8903 mono_class_setup_methods (klass);
8906 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
8907 * FIXME we should better report this error to the caller
8909 if (!klass->methods)
8910 return NULL;
8911 /* start from the first */
8912 if (klass->method.count) {
8913 *iter = &klass->methods [0];
8914 return klass->methods [0];
8915 } else {
8916 /* no method */
8917 return NULL;
8920 method = *iter;
8921 method++;
8922 if (method < &klass->methods [klass->method.count]) {
8923 *iter = method;
8924 return *method;
8926 return NULL;
8930 * mono_class_get_virtual_methods:
8932 * Iterate over the virtual methods of KLASS.
8934 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
8936 static MonoMethod*
8937 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
8939 MonoMethod** method;
8940 if (!iter)
8941 return NULL;
8942 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
8943 if (!*iter) {
8944 mono_class_setup_methods (klass);
8946 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
8947 * FIXME we should better report this error to the caller
8949 if (!klass->methods)
8950 return NULL;
8951 /* start from the first */
8952 method = &klass->methods [0];
8953 } else {
8954 method = *iter;
8955 method++;
8957 while (method < &klass->methods [klass->method.count]) {
8958 if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
8959 break;
8960 method ++;
8962 if (method < &klass->methods [klass->method.count]) {
8963 *iter = method;
8964 return *method;
8965 } else {
8966 return NULL;
8968 } else {
8969 /* Search directly in metadata to avoid calling setup_methods () */
8970 MonoMethod *res = NULL;
8971 int i, start_index;
8973 if (!*iter) {
8974 start_index = 0;
8975 } else {
8976 start_index = GPOINTER_TO_UINT (*iter);
8979 for (i = start_index; i < klass->method.count; ++i) {
8980 guint32 flags;
8982 /* class->method.first points into the methodptr table */
8983 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
8985 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
8986 break;
8989 if (i < klass->method.count) {
8990 MonoError error;
8991 res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
8992 mono_error_cleanup (&error); /* FIXME don't swallow the error */
8994 /* Add 1 here so the if (*iter) check fails */
8995 *iter = GUINT_TO_POINTER (i + 1);
8996 return res;
8997 } else {
8998 return NULL;
9004 * mono_class_get_properties:
9005 * @klass: the MonoClass to act on
9007 * This routine is an iterator routine for retrieving the properties in a class.
9009 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9010 * iterate over all of the elements. When no more values are
9011 * available, the return value is NULL.
9013 * Returns: a @MonoProperty* on each invocation, or NULL when no more are available.
9015 MonoProperty*
9016 mono_class_get_properties (MonoClass* klass, gpointer *iter)
9018 MonoProperty* property;
9019 if (!iter)
9020 return NULL;
9021 if (!*iter) {
9022 mono_class_setup_properties (klass);
9023 /* start from the first */
9024 if (klass->ext->property.count) {
9025 return *iter = &klass->ext->properties [0];
9026 } else {
9027 /* no fields */
9028 return NULL;
9031 property = *iter;
9032 property++;
9033 if (property < &klass->ext->properties [klass->ext->property.count]) {
9034 return *iter = property;
9036 return NULL;
9040 * mono_class_get_events:
9041 * @klass: the MonoClass to act on
9043 * This routine is an iterator routine for retrieving the properties in a class.
9045 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9046 * iterate over all of the elements. When no more values are
9047 * available, the return value is NULL.
9049 * Returns: a @MonoEvent* on each invocation, or NULL when no more are available.
9051 MonoEvent*
9052 mono_class_get_events (MonoClass* klass, gpointer *iter)
9054 MonoEvent* event;
9055 if (!iter)
9056 return NULL;
9057 if (!*iter) {
9058 mono_class_setup_events (klass);
9059 /* start from the first */
9060 if (klass->ext->event.count) {
9061 return *iter = &klass->ext->events [0];
9062 } else {
9063 /* no fields */
9064 return NULL;
9067 event = *iter;
9068 event++;
9069 if (event < &klass->ext->events [klass->ext->event.count]) {
9070 return *iter = event;
9072 return NULL;
9076 * mono_class_get_interfaces
9077 * @klass: the MonoClass to act on
9079 * This routine is an iterator routine for retrieving the interfaces implemented by this class.
9081 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9082 * iterate over all of the elements. When no more values are
9083 * available, the return value is NULL.
9085 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
9087 MonoClass*
9088 mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
9090 MonoError error;
9091 MonoClass** iface;
9092 if (!iter)
9093 return NULL;
9094 if (!*iter) {
9095 if (!klass->inited)
9096 mono_class_init (klass);
9097 if (!klass->interfaces_inited) {
9098 mono_class_setup_interfaces (klass, &error);
9099 if (!mono_error_ok (&error)) {
9100 mono_error_cleanup (&error);
9101 return NULL;
9104 /* start from the first */
9105 if (klass->interface_count) {
9106 *iter = &klass->interfaces [0];
9107 return klass->interfaces [0];
9108 } else {
9109 /* no interface */
9110 return NULL;
9113 iface = *iter;
9114 iface++;
9115 if (iface < &klass->interfaces [klass->interface_count]) {
9116 *iter = iface;
9117 return *iface;
9119 return NULL;
9122 static void
9123 setup_nested_types (MonoClass *klass)
9125 MonoError error;
9126 GList *classes, *nested_classes, *l;
9127 int i;
9129 if (klass->nested_classes_inited)
9130 return;
9132 if (!klass->type_token)
9133 klass->nested_classes_inited = TRUE;
9135 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
9136 classes = NULL;
9137 while (i) {
9138 MonoClass* nclass;
9139 guint32 cols [MONO_NESTED_CLASS_SIZE];
9140 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
9141 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error);
9142 if (!mono_error_ok (&error)) {
9143 /*FIXME don't swallow the error message*/
9144 mono_error_cleanup (&error);
9146 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
9147 continue;
9150 classes = g_list_prepend (classes, nclass);
9152 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
9155 mono_class_alloc_ext (klass);
9157 nested_classes = NULL;
9158 for (l = classes; l; l = l->next)
9159 nested_classes = g_list_prepend_image (klass->image, nested_classes, l->data);
9160 g_list_free (classes);
9162 mono_image_lock (klass->image);
9164 mono_memory_barrier ();
9165 if (!klass->nested_classes_inited) {
9166 klass->ext->nested_classes = nested_classes;
9167 mono_memory_barrier ();
9168 klass->nested_classes_inited = TRUE;
9171 mono_image_unlock (klass->image);
9175 * mono_class_get_nested_types
9176 * @klass: the MonoClass to act on
9178 * This routine is an iterator routine for retrieving the nested types of a class.
9179 * This works only if @klass is non-generic, or a generic type definition.
9181 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9182 * iterate over all of the elements. When no more values are
9183 * available, the return value is NULL.
9185 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
9187 MonoClass*
9188 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
9190 GList *item;
9192 if (!iter)
9193 return NULL;
9194 if (!klass->nested_classes_inited)
9195 setup_nested_types (klass);
9197 if (!*iter) {
9198 /* start from the first */
9199 if (klass->ext && klass->ext->nested_classes) {
9200 *iter = klass->ext->nested_classes;
9201 return klass->ext->nested_classes->data;
9202 } else {
9203 /* no nested types */
9204 return NULL;
9207 item = *iter;
9208 item = item->next;
9209 if (item) {
9210 *iter = item;
9211 return item->data;
9213 return NULL;
9218 * mono_class_is_delegate
9219 * @klass: the MonoClass to act on
9221 * Returns: true if the MonoClass represents a System.Delegate.
9223 mono_bool
9224 mono_class_is_delegate (MonoClass *klass)
9226 return klass->delegate;
9230 * mono_class_implements_interface
9231 * @klass: The MonoClass to act on
9232 * @interface: The interface to check if @klass implements.
9234 * Returns: true if @klass implements @interface.
9236 mono_bool
9237 mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
9239 return mono_class_is_assignable_from (iface, klass);
9243 * mono_field_get_name:
9244 * @field: the MonoClassField to act on
9246 * Returns: the name of the field.
9248 const char*
9249 mono_field_get_name (MonoClassField *field)
9251 return field->name;
9255 * mono_field_get_type:
9256 * @field: the MonoClassField to act on
9258 * Returns: MonoType of the field.
9260 MonoType*
9261 mono_field_get_type (MonoClassField *field)
9263 MonoError error;
9264 MonoType *type = mono_field_get_type_checked (field, &error);
9265 if (!mono_error_ok (&error)) {
9266 mono_trace_warning (MONO_TRACE_TYPE, "Could not load field's type due to %s", mono_error_get_message (&error));
9267 mono_error_cleanup (&error);
9269 return type;
9274 * mono_field_get_type_checked:
9275 * @field: the MonoClassField to act on
9276 * @error: used to return any erro found while retrieving @field type
9278 * Returns: MonoType of the field.
9280 MonoType*
9281 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
9283 mono_error_init (error);
9284 if (!field->type)
9285 mono_field_resolve_type (field, error);
9286 return field->type;
9290 * mono_field_get_parent:
9291 * @field: the MonoClassField to act on
9293 * Returns: MonoClass where the field was defined.
9295 MonoClass*
9296 mono_field_get_parent (MonoClassField *field)
9298 return field->parent;
9302 * mono_field_get_flags;
9303 * @field: the MonoClassField to act on
9305 * The metadata flags for a field are encoded using the
9306 * FIELD_ATTRIBUTE_* constants. See the tabledefs.h file for details.
9308 * Returns: the flags for the field.
9310 guint32
9311 mono_field_get_flags (MonoClassField *field)
9313 if (!field->type)
9314 return mono_field_resolve_flags (field);
9315 return field->type->attrs;
9319 * mono_field_get_offset;
9320 * @field: the MonoClassField to act on
9322 * Returns: the field offset.
9324 guint32
9325 mono_field_get_offset (MonoClassField *field)
9327 return field->offset;
9330 static const char *
9331 mono_field_get_rva (MonoClassField *field)
9333 guint32 rva;
9334 int field_index;
9335 MonoClass *klass = field->parent;
9336 MonoFieldDefaultValue *field_def_values;
9338 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
9340 if (!klass->ext || !klass->ext->field_def_values) {
9341 mono_class_alloc_ext (klass);
9343 field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
9345 mono_image_lock (klass->image);
9346 if (!klass->ext->field_def_values)
9347 klass->ext->field_def_values = field_def_values;
9348 mono_image_unlock (klass->image);
9351 field_index = mono_field_get_index (field);
9353 if (!klass->ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) {
9354 mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL);
9355 if (!rva)
9356 g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
9357 klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
9360 return klass->ext->field_def_values [field_index].data;
9364 * mono_field_get_data;
9365 * @field: the MonoClassField to act on
9367 * Returns: pointer to the metadata constant value or to the field
9368 * data if it has an RVA flag.
9370 const char *
9371 mono_field_get_data (MonoClassField *field)
9373 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
9374 MonoTypeEnum def_type;
9376 return mono_class_get_field_default_value (field, &def_type);
9377 } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
9378 return mono_field_get_rva (field);
9379 } else {
9380 return NULL;
9385 * mono_property_get_name:
9386 * @prop: the MonoProperty to act on
9388 * Returns: the name of the property
9390 const char*
9391 mono_property_get_name (MonoProperty *prop)
9393 return prop->name;
9397 * mono_property_get_set_method
9398 * @prop: the MonoProperty to act on.
9400 * Returns: the setter method of the property (A MonoMethod)
9402 MonoMethod*
9403 mono_property_get_set_method (MonoProperty *prop)
9405 return prop->set;
9409 * mono_property_get_get_method
9410 * @prop: the MonoProperty to act on.
9412 * Returns: the setter method of the property (A MonoMethod)
9414 MonoMethod*
9415 mono_property_get_get_method (MonoProperty *prop)
9417 return prop->get;
9421 * mono_property_get_parent:
9422 * @prop: the MonoProperty to act on.
9424 * Returns: the MonoClass where the property was defined.
9426 MonoClass*
9427 mono_property_get_parent (MonoProperty *prop)
9429 return prop->parent;
9433 * mono_property_get_flags:
9434 * @prop: the MonoProperty to act on.
9436 * The metadata flags for a property are encoded using the
9437 * PROPERTY_ATTRIBUTE_* constants. See the tabledefs.h file for details.
9439 * Returns: the flags for the property.
9441 guint32
9442 mono_property_get_flags (MonoProperty *prop)
9444 return prop->attrs;
9448 * mono_event_get_name:
9449 * @event: the MonoEvent to act on
9451 * Returns: the name of the event.
9453 const char*
9454 mono_event_get_name (MonoEvent *event)
9456 return event->name;
9460 * mono_event_get_add_method:
9461 * @event: The MonoEvent to act on.
9463 * Returns: the @add' method for the event (a MonoMethod).
9465 MonoMethod*
9466 mono_event_get_add_method (MonoEvent *event)
9468 return event->add;
9472 * mono_event_get_remove_method:
9473 * @event: The MonoEvent to act on.
9475 * Returns: the @remove method for the event (a MonoMethod).
9477 MonoMethod*
9478 mono_event_get_remove_method (MonoEvent *event)
9480 return event->remove;
9484 * mono_event_get_raise_method:
9485 * @event: The MonoEvent to act on.
9487 * Returns: the @raise method for the event (a MonoMethod).
9489 MonoMethod*
9490 mono_event_get_raise_method (MonoEvent *event)
9492 return event->raise;
9496 * mono_event_get_parent:
9497 * @event: the MonoEvent to act on.
9499 * Returns: the MonoClass where the event is defined.
9501 MonoClass*
9502 mono_event_get_parent (MonoEvent *event)
9504 return event->parent;
9508 * mono_event_get_flags
9509 * @event: the MonoEvent to act on.
9511 * The metadata flags for an event are encoded using the
9512 * EVENT_* constants. See the tabledefs.h file for details.
9514 * Returns: the flags for the event.
9516 guint32
9517 mono_event_get_flags (MonoEvent *event)
9519 return event->attrs;
9523 * mono_class_get_method_from_name:
9524 * @klass: where to look for the method
9525 * @name: name of the method
9526 * @param_count: number of parameters. -1 for any number.
9528 * Obtains a MonoMethod with a given name and number of parameters.
9529 * It only works if there are no multiple signatures for any given method name.
9531 MonoMethod *
9532 mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_count)
9534 return mono_class_get_method_from_name_flags (klass, name, param_count, 0);
9537 static MonoMethod*
9538 find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
9540 MonoMethod *res = NULL;
9541 int i;
9543 /* Search directly in the metadata to avoid calling setup_methods () */
9544 for (i = 0; i < klass->method.count; ++i) {
9545 MonoError error;
9546 guint32 cols [MONO_METHOD_SIZE];
9547 MonoMethod *method;
9548 MonoMethodSignature *sig;
9550 /* class->method.first points into the methodptr table */
9551 mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE);
9553 if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
9554 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
9555 if (!method) {
9556 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9557 continue;
9559 if (param_count == -1) {
9560 res = method;
9561 break;
9563 sig = mono_method_signature_checked (method, &error);
9564 if (!sig) {
9565 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9566 continue;
9568 if (sig->param_count == param_count) {
9569 res = method;
9570 break;
9575 return res;
9579 * mono_class_get_method_from_name_flags:
9580 * @klass: where to look for the method
9581 * @name_space: name of the method
9582 * @param_count: number of parameters. -1 for any number.
9583 * @flags: flags which must be set in the method
9585 * Obtains a MonoMethod with a given name and number of parameters.
9586 * It only works if there are no multiple signatures for any given method name.
9588 MonoMethod *
9589 mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int param_count, int flags)
9591 MonoMethod *res = NULL;
9592 int i;
9594 mono_class_init (klass);
9596 if (klass->generic_class && !klass->methods) {
9597 res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags);
9598 if (res) {
9599 MonoError error;
9600 res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), &error);
9601 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
9603 return res;
9606 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
9607 mono_class_setup_methods (klass);
9609 We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9610 See mono/tests/array_load_exception.il
9611 FIXME we should better report this error to the caller
9613 if (!klass->methods)
9614 return NULL;
9615 for (i = 0; i < klass->method.count; ++i) {
9616 MonoMethod *method = klass->methods [i];
9618 if (method->name[0] == name [0] &&
9619 !strcmp (name, method->name) &&
9620 (param_count == -1 || mono_method_signature (method)->param_count == param_count) &&
9621 ((method->flags & flags) == flags)) {
9622 res = method;
9623 break;
9627 else {
9628 res = find_method_in_metadata (klass, name, param_count, flags);
9631 return res;
9635 * mono_class_set_failure:
9636 * @klass: class in which the failure was detected
9637 * @ex_type: the kind of exception/error to be thrown (later)
9638 * @ex_data: exception data (specific to each type of exception/error)
9640 * Keep a detected failure informations in the class for later processing.
9641 * Note that only the first failure is kept.
9643 * LOCKING: Acquires the loader lock.
9645 gboolean
9646 mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
9648 if (klass->exception_type)
9649 return FALSE;
9651 mono_loader_lock ();
9652 klass->exception_type = ex_type;
9653 if (ex_data)
9654 mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
9655 mono_loader_unlock ();
9657 return TRUE;
9661 * mono_class_get_exception_data:
9663 * Return the exception_data property of KLASS.
9665 * LOCKING: Acquires the loader lock.
9667 gpointer
9668 mono_class_get_exception_data (MonoClass *klass)
9670 return mono_image_property_lookup (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA);
9674 * mono_classes_init:
9676 * Initialize the resources used by this module.
9678 void
9679 mono_classes_init (void)
9681 mono_mutex_init (&classes_mutex);
9683 mono_counters_register ("Inflated methods size",
9684 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
9685 mono_counters_register ("Inflated classes",
9686 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes);
9687 mono_counters_register ("Inflated classes size",
9688 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
9689 mono_counters_register ("MonoClass size",
9690 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
9691 mono_counters_register ("MonoClassExt size",
9692 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size);
9696 * mono_classes_cleanup:
9698 * Free the resources used by this module.
9700 void
9701 mono_classes_cleanup (void)
9703 if (global_interface_bitset)
9704 mono_bitset_free (global_interface_bitset);
9705 global_interface_bitset = NULL;
9706 mono_mutex_destroy (&classes_mutex);
9710 * mono_class_get_exception_for_failure:
9711 * @klass: class in which the failure was detected
9713 * Return a constructed MonoException than the caller can then throw
9714 * using mono_raise_exception - or NULL if no failure is present (or
9715 * doesn't result in an exception).
9717 MonoException*
9718 mono_class_get_exception_for_failure (MonoClass *klass)
9720 gpointer exception_data = mono_class_get_exception_data (klass);
9722 switch (klass->exception_type) {
9723 #ifndef DISABLE_SECURITY
9724 case MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND: {
9725 MonoDomain *domain = mono_domain_get ();
9726 MonoSecurityManager* secman = mono_security_manager_get_methods ();
9727 MonoMethod *method = exception_data;
9728 guint32 error = (method) ? MONO_METADATA_INHERITANCEDEMAND_METHOD : MONO_METADATA_INHERITANCEDEMAND_CLASS;
9729 MonoObject *exc = NULL;
9730 gpointer args [4];
9732 args [0] = &error;
9733 args [1] = mono_assembly_get_object (domain, mono_image_get_assembly (klass->image));
9734 args [2] = mono_type_get_object (domain, &klass->byval_arg);
9735 args [3] = (method) ? mono_method_get_object (domain, method, NULL) : NULL;
9737 mono_runtime_invoke (secman->inheritsecurityexception, NULL, args, &exc);
9738 return (MonoException*) exc;
9740 #endif
9741 case MONO_EXCEPTION_TYPE_LOAD: {
9742 MonoString *name;
9743 MonoException *ex;
9744 char *str = mono_type_get_full_name (klass);
9745 char *astr = klass->image->assembly? mono_stringify_assembly_name (&klass->image->assembly->aname): NULL;
9746 name = mono_string_new (mono_domain_get (), str);
9747 g_free (str);
9748 ex = mono_get_exception_type_load (name, astr);
9749 g_free (astr);
9750 return ex;
9752 case MONO_EXCEPTION_MISSING_METHOD: {
9753 char *class_name = exception_data;
9754 char *assembly_name = class_name + strlen (class_name) + 1;
9756 return mono_get_exception_missing_method (class_name, assembly_name);
9758 case MONO_EXCEPTION_MISSING_FIELD: {
9759 char *class_name = exception_data;
9760 char *member_name = class_name + strlen (class_name) + 1;
9762 return mono_get_exception_missing_field (class_name, member_name);
9764 case MONO_EXCEPTION_FILE_NOT_FOUND: {
9765 char *msg_format = exception_data;
9766 char *assembly_name = msg_format + strlen (msg_format) + 1;
9767 char *msg = g_strdup_printf (msg_format, assembly_name);
9768 MonoException *ex;
9770 ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), assembly_name));
9772 g_free (msg);
9774 return ex;
9776 case MONO_EXCEPTION_BAD_IMAGE: {
9777 return mono_get_exception_bad_image_format (exception_data);
9779 default: {
9780 MonoLoaderError *error;
9781 MonoException *ex;
9783 error = mono_loader_get_last_error ();
9784 if (error != NULL){
9785 ex = mono_loader_error_prepare_exception (error);
9786 return ex;
9789 /* TODO - handle other class related failures */
9790 return NULL;
9795 static gboolean
9796 is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
9798 outer_klass = mono_class_get_generic_type_definition (outer_klass);
9799 inner_klass = mono_class_get_generic_type_definition (inner_klass);
9800 do {
9801 if (outer_klass == inner_klass)
9802 return TRUE;
9803 inner_klass = inner_klass->nested_in;
9804 } while (inner_klass);
9805 return FALSE;
9808 MonoClass *
9809 mono_class_get_generic_type_definition (MonoClass *klass)
9811 return klass->generic_class ? klass->generic_class->container_class : klass;
9815 * Check if @klass is a subtype of @parent ignoring generic instantiations.
9817 * Generic instantiations are ignored for all super types of @klass.
9819 * Visibility checks ignoring generic instantiations.
9821 gboolean
9822 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
9824 int i;
9825 klass = mono_class_get_generic_type_definition (klass);
9826 parent = mono_class_get_generic_type_definition (parent);
9827 mono_class_setup_supertypes (klass);
9829 for (i = 0; i < klass->idepth; ++i) {
9830 if (parent == mono_class_get_generic_type_definition (klass->supertypes [i]))
9831 return TRUE;
9833 return FALSE;
9836 * Subtype can only access parent members with family protection if the site object
9837 * is subclass of Subtype. For example:
9838 * class A { protected int x; }
9839 * class B : A {
9840 * void valid_access () {
9841 * B b;
9842 * b.x = 0;
9844 * void invalid_access () {
9845 * A a;
9846 * a.x = 0;
9849 * */
9850 static gboolean
9851 is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
9853 if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
9854 return FALSE;
9856 if (context_klass == NULL)
9857 return TRUE;
9858 /*if access_klass is not member_klass context_klass must be type compat*/
9859 if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
9860 return FALSE;
9861 return TRUE;
9864 static gboolean
9865 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
9867 GSList *tmp;
9868 if (accessing == accessed)
9869 return TRUE;
9870 if (!accessed || !accessing)
9871 return FALSE;
9873 /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
9874 * anywhere so untrusted friends are not safe to access platform's code internals */
9875 if (mono_security_core_clr_enabled ()) {
9876 if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
9877 return FALSE;
9880 mono_assembly_load_friends (accessed);
9881 for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
9882 MonoAssemblyName *friend = tmp->data;
9883 /* Be conservative with checks */
9884 if (!friend->name)
9885 continue;
9886 if (strcmp (accessing->aname.name, friend->name))
9887 continue;
9888 if (friend->public_key_token [0]) {
9889 if (!accessing->aname.public_key_token [0])
9890 continue;
9891 if (!mono_public_tokens_are_equal (friend->public_key_token, accessing->aname.public_key_token))
9892 continue;
9894 return TRUE;
9896 return FALSE;
9900 * If klass is a generic type or if it is derived from a generic type, return the
9901 * MonoClass of the generic definition
9902 * Returns NULL if not found
9904 static MonoClass*
9905 get_generic_definition_class (MonoClass *klass)
9907 while (klass) {
9908 if (klass->generic_class && klass->generic_class->container_class)
9909 return klass->generic_class->container_class;
9910 klass = klass->parent;
9912 return NULL;
9915 static gboolean
9916 can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
9918 int i;
9919 for (i = 0; i < ginst->type_argc; ++i) {
9920 MonoType *type = ginst->type_argv[i];
9921 switch (type->type) {
9922 case MONO_TYPE_SZARRAY:
9923 if (!can_access_type (access_klass, type->data.klass))
9924 return FALSE;
9925 break;
9926 case MONO_TYPE_ARRAY:
9927 if (!can_access_type (access_klass, type->data.array->eklass))
9928 return FALSE;
9929 break;
9930 case MONO_TYPE_PTR:
9931 if (!can_access_type (access_klass, mono_class_from_mono_type (type->data.type)))
9932 return FALSE;
9933 break;
9934 case MONO_TYPE_CLASS:
9935 case MONO_TYPE_VALUETYPE:
9936 case MONO_TYPE_GENERICINST:
9937 if (!can_access_type (access_klass, mono_class_from_mono_type (type)))
9938 return FALSE;
9941 return TRUE;
9944 static gboolean
9945 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
9947 int access_level;
9949 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
9950 return TRUE;
9952 if (access_klass->element_class && !access_klass->enumtype)
9953 access_klass = access_klass->element_class;
9955 if (member_klass->element_class && !member_klass->enumtype)
9956 member_klass = member_klass->element_class;
9958 access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
9960 if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
9961 return TRUE;
9963 if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst))
9964 return FALSE;
9966 if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
9967 return TRUE;
9969 if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
9970 return FALSE;
9972 /*Non nested type with nested visibility. We just fail it.*/
9973 if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL)
9974 return FALSE;
9976 switch (access_level) {
9977 case TYPE_ATTRIBUTE_NOT_PUBLIC:
9978 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
9980 case TYPE_ATTRIBUTE_PUBLIC:
9981 return TRUE;
9983 case TYPE_ATTRIBUTE_NESTED_PUBLIC:
9984 return TRUE;
9986 case TYPE_ATTRIBUTE_NESTED_PRIVATE:
9987 return is_nesting_type (member_klass, access_klass);
9989 case TYPE_ATTRIBUTE_NESTED_FAMILY:
9990 return mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
9992 case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
9993 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
9995 case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
9996 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) &&
9997 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
9999 case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
10000 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) ||
10001 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10003 return FALSE;
10006 /* FIXME: check visibility of type, too */
10007 static gboolean
10008 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
10010 MonoClass *member_generic_def;
10011 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
10012 return TRUE;
10014 if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
10015 access_klass->generic_container) &&
10016 (member_generic_def = get_generic_definition_class (member_klass))) {
10017 MonoClass *access_container;
10019 if (access_klass->generic_container)
10020 access_container = access_klass;
10021 else
10022 access_container = access_klass->generic_class->container_class;
10024 if (can_access_member (access_container, member_generic_def, context_klass, access_level))
10025 return TRUE;
10028 /* Partition I 8.5.3.2 */
10029 /* the access level values are the same for fields and methods */
10030 switch (access_level) {
10031 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
10032 /* same compilation unit */
10033 return access_klass->image == member_klass->image;
10034 case FIELD_ATTRIBUTE_PRIVATE:
10035 return access_klass == member_klass;
10036 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
10037 if (is_valid_family_access (access_klass, member_klass, context_klass) &&
10038 can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
10039 return TRUE;
10040 return FALSE;
10041 case FIELD_ATTRIBUTE_ASSEMBLY:
10042 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10043 case FIELD_ATTRIBUTE_FAMILY:
10044 if (is_valid_family_access (access_klass, member_klass, context_klass))
10045 return TRUE;
10046 return FALSE;
10047 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
10048 if (is_valid_family_access (access_klass, member_klass, context_klass))
10049 return TRUE;
10050 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10051 case FIELD_ATTRIBUTE_PUBLIC:
10052 return TRUE;
10054 return FALSE;
10057 gboolean
10058 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
10060 /* FIXME: check all overlapping fields */
10061 int can = can_access_member (method->klass, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10062 if (!can) {
10063 MonoClass *nested = method->klass->nested_in;
10064 while (nested) {
10065 can = can_access_member (nested, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10066 if (can)
10067 return TRUE;
10068 nested = nested->nested_in;
10071 return can;
10074 gboolean
10075 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
10077 int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10078 if (!can) {
10079 MonoClass *nested = method->klass->nested_in;
10080 while (nested) {
10081 can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10082 if (can)
10083 return TRUE;
10084 nested = nested->nested_in;
10088 * FIXME:
10089 * with generics calls to explicit interface implementations can be expressed
10090 * directly: the method is private, but we must allow it. This may be opening
10091 * a hole or the generics code should handle this differently.
10092 * Maybe just ensure the interface type is public.
10094 if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
10095 return TRUE;
10096 return can;
10100 * mono_method_can_access_method_full:
10101 * @method: The caller method
10102 * @called: The called method
10103 * @context_klass: The static type on stack of the owner @called object used
10105 * This function must be used with instance calls, as they have more strict family accessibility.
10106 * It can be used with static methods, but context_klass should be NULL.
10108 * Returns: TRUE if caller have proper visibility and acessibility to @called
10110 gboolean
10111 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
10113 MonoClass *access_class = method->klass;
10114 MonoClass *member_class = called->klass;
10115 int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10116 if (!can) {
10117 MonoClass *nested = access_class->nested_in;
10118 while (nested) {
10119 can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10120 if (can)
10121 break;
10122 nested = nested->nested_in;
10126 if (!can)
10127 return FALSE;
10129 can = can_access_type (access_class, member_class);
10130 if (!can) {
10131 MonoClass *nested = access_class->nested_in;
10132 while (nested) {
10133 can = can_access_type (nested, member_class);
10134 if (can)
10135 break;
10136 nested = nested->nested_in;
10140 if (!can)
10141 return FALSE;
10143 if (called->is_inflated) {
10144 MonoMethodInflated * infl = (MonoMethodInflated*)called;
10145 if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
10146 return FALSE;
10149 return TRUE;
10154 * mono_method_can_access_field_full:
10155 * @method: The caller method
10156 * @field: The accessed field
10157 * @context_klass: The static type on stack of the owner @field object used
10159 * This function must be used with instance fields, as they have more strict family accessibility.
10160 * It can be used with static fields, but context_klass should be NULL.
10162 * Returns: TRUE if caller have proper visibility and acessibility to @field
10164 gboolean
10165 mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
10167 MonoClass *access_class = method->klass;
10168 MonoClass *member_class = field->parent;
10169 /* FIXME: check all overlapping fields */
10170 int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10171 if (!can) {
10172 MonoClass *nested = access_class->nested_in;
10173 while (nested) {
10174 can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10175 if (can)
10176 break;
10177 nested = nested->nested_in;
10181 if (!can)
10182 return FALSE;
10184 can = can_access_type (access_class, member_class);
10185 if (!can) {
10186 MonoClass *nested = access_class->nested_in;
10187 while (nested) {
10188 can = can_access_type (nested, member_class);
10189 if (can)
10190 break;
10191 nested = nested->nested_in;
10195 if (!can)
10196 return FALSE;
10197 return TRUE;
10201 * mono_class_can_access_class:
10202 * @source_class: The source class
10203 * @target_class: The accessed class
10205 * This function returns is @target_class is visible to @source_class
10207 * Returns: TRUE if source have proper visibility and acessibility to target
10209 gboolean
10210 mono_class_can_access_class (MonoClass *source_class, MonoClass *target_class)
10212 return can_access_type (source_class, target_class);
10216 * mono_type_is_valid_enum_basetype:
10217 * @type: The MonoType to check
10219 * Returns: TRUE if the type can be used as the basetype of an enum
10221 gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
10222 switch (type->type) {
10223 case MONO_TYPE_I1:
10224 case MONO_TYPE_U1:
10225 case MONO_TYPE_BOOLEAN:
10226 case MONO_TYPE_I2:
10227 case MONO_TYPE_U2:
10228 case MONO_TYPE_CHAR:
10229 case MONO_TYPE_I4:
10230 case MONO_TYPE_U4:
10231 case MONO_TYPE_I8:
10232 case MONO_TYPE_U8:
10233 case MONO_TYPE_I:
10234 case MONO_TYPE_U:
10235 return TRUE;
10237 return FALSE;
10241 * mono_class_is_valid_enum:
10242 * @klass: An enum class to be validated
10244 * This method verify the required properties an enum should have.
10246 * Returns: TRUE if the informed enum class is valid
10248 * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
10249 * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
10250 * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
10252 gboolean mono_class_is_valid_enum (MonoClass *klass) {
10253 MonoClassField * field;
10254 gpointer iter = NULL;
10255 gboolean found_base_field = FALSE;
10257 g_assert (klass->enumtype);
10258 /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
10259 if (!klass->parent || strcmp (klass->parent->name, "Enum") || strcmp (klass->parent->name_space, "System") ) {
10260 return FALSE;
10263 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)
10264 return FALSE;
10266 while ((field = mono_class_get_fields (klass, &iter))) {
10267 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
10268 if (found_base_field)
10269 return FALSE;
10270 found_base_field = TRUE;
10271 if (!mono_type_is_valid_enum_basetype (field->type))
10272 return FALSE;
10276 if (!found_base_field)
10277 return FALSE;
10279 if (klass->method.count > 0)
10280 return FALSE;
10282 return TRUE;
10285 gboolean
10286 mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
10288 return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
10292 * mono_class_setup_interface_id:
10294 * Initializes MonoClass::interface_id if required.
10296 * LOCKING: Acquires the loader lock.
10298 void
10299 mono_class_setup_interface_id (MonoClass *class)
10301 mono_loader_lock ();
10302 if (MONO_CLASS_IS_INTERFACE (class) && !class->interface_id)
10303 class->interface_id = mono_get_unique_iid (class);
10304 mono_loader_unlock ();
10308 * mono_class_alloc_ext:
10310 * Allocate klass->ext if not already done.
10312 void
10313 mono_class_alloc_ext (MonoClass *klass)
10315 MonoClassExt *ext;
10317 if (klass->ext)
10318 return;
10320 ext = mono_class_alloc0 (klass, sizeof (MonoClassExt));
10321 mono_image_lock (klass->image);
10322 mono_memory_barrier ();
10323 if (!klass->ext)
10324 klass->ext = ext;
10325 class_ext_size += sizeof (MonoClassExt);
10326 mono_image_unlock (klass->image);
10330 * mono_class_setup_interfaces:
10332 * Initialize class->interfaces/interfaces_count.
10333 * LOCKING: Acquires the loader lock.
10334 * This function can fail the type.
10336 void
10337 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
10339 int i, interface_count;
10340 MonoClass **interfaces;
10342 mono_error_init (error);
10344 if (klass->interfaces_inited)
10345 return;
10347 if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY) {
10348 MonoType *args [1];
10350 /* generic IList, ICollection, IEnumerable */
10351 interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
10352 interfaces = mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
10354 args [0] = &klass->element_class->byval_arg;
10355 interfaces [0] = mono_class_bind_generic_parameters (
10356 mono_defaults.generic_ilist_class, 1, args, FALSE);
10357 if (interface_count > 1)
10358 interfaces [1] = mono_class_bind_generic_parameters (
10359 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
10360 } else if (klass->generic_class) {
10361 MonoClass *gklass = klass->generic_class->container_class;
10363 mono_class_setup_interfaces (gklass, error);
10364 if (!mono_error_ok (error)) {
10365 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
10366 return;
10369 interface_count = gklass->interface_count;
10370 interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
10371 for (i = 0; i < interface_count; i++) {
10372 interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error);
10373 if (!mono_error_ok (error)) {
10374 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
10375 return;
10378 } else {
10379 interface_count = 0;
10380 interfaces = NULL;
10383 mono_image_lock (klass->image);
10385 if (!klass->interfaces_inited) {
10386 klass->interface_count = interface_count;
10387 klass->interfaces = interfaces;
10389 mono_memory_barrier ();
10391 klass->interfaces_inited = TRUE;
10394 mono_image_unlock (klass->image);
10397 static void
10398 mono_field_resolve_type (MonoClassField *field, MonoError *error)
10400 MonoClass *class = field->parent;
10401 MonoImage *image = class->image;
10402 MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
10403 int field_idx = field - class->fields;
10405 mono_error_init (error);
10407 if (gtd) {
10408 MonoClassField *gfield = &gtd->fields [field_idx];
10409 MonoType *gtype = mono_field_get_type_checked (gfield, error);
10410 if (!mono_error_ok (error)) {
10411 char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
10412 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
10413 g_free (err_msg);
10416 field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (class), error);
10417 if (!mono_error_ok (error)) {
10418 char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
10419 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
10420 g_free (err_msg);
10422 } else {
10423 const char *sig;
10424 guint32 cols [MONO_FIELD_SIZE];
10425 MonoGenericContainer *container = NULL;
10426 int idx = class->field.first + field_idx;
10428 /*FIXME, in theory we do not lazy load SRE fields*/
10429 g_assert (!image_is_dynamic (image));
10431 if (class->generic_container) {
10432 container = class->generic_container;
10433 } else if (gtd) {
10434 container = gtd->generic_container;
10435 g_assert (container);
10438 /* class->field.first and idx points into the fieldptr table */
10439 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
10441 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) {
10442 mono_error_set_type_load_class (error, class, "Could not verify field %s signature", field->name);
10443 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
10444 return;
10447 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
10449 mono_metadata_decode_value (sig, &sig);
10450 /* FIELD signature == 0x06 */
10451 g_assert (*sig == 0x06);
10452 field->type = mono_metadata_parse_type_full (image, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
10453 if (!field->type)
10454 mono_class_set_failure_from_loader_error (class, error, g_strdup_printf ("Could not load field %s type", field->name));
10458 static guint32
10459 mono_field_resolve_flags (MonoClassField *field)
10461 MonoClass *class = field->parent;
10462 MonoImage *image = class->image;
10463 MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
10464 int field_idx = field - class->fields;
10467 if (gtd) {
10468 MonoClassField *gfield = &gtd->fields [field_idx];
10469 return mono_field_get_flags (gfield);
10470 } else {
10471 int idx = class->field.first + field_idx;
10473 /*FIXME, in theory we do not lazy load SRE fields*/
10474 g_assert (!image_is_dynamic (image));
10476 return mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_FLAGS);
10481 * mono_class_setup_basic_field_info:
10482 * @class: The class to initialize
10484 * Initializes the class->fields array of fields.
10485 * Aquires the loader lock.
10487 static void
10488 mono_class_setup_basic_field_info_locking (MonoClass *class)
10490 mono_loader_lock ();
10491 mono_class_setup_basic_field_info (class);
10492 mono_loader_unlock ();
10496 * mono_class_get_fields_lazy:
10497 * @klass: the MonoClass to act on
10499 * This routine is an iterator routine for retrieving the fields in a class.
10500 * Only minimal information about fields are loaded. Accessors must be used
10501 * for all MonoClassField returned.
10503 * You must pass a gpointer that points to zero and is treated as an opaque handle to
10504 * iterate over all of the elements. When no more values are
10505 * available, the return value is NULL.
10507 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
10509 MonoClassField*
10510 mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
10512 MonoClassField* field;
10513 if (!iter)
10514 return NULL;
10515 if (!*iter) {
10516 mono_class_setup_basic_field_info_locking (klass);
10517 if (!klass->fields)
10518 return NULL;
10519 /* start from the first */
10520 if (klass->field.count) {
10521 return *iter = &klass->fields [0];
10522 } else {
10523 /* no fields */
10524 return NULL;
10527 field = *iter;
10528 field++;
10529 if (field < &klass->fields [klass->field.count]) {
10530 return *iter = field;
10532 return NULL;
10535 char*
10536 mono_class_full_name (MonoClass *klass)
10538 return mono_type_full_name (&klass->byval_arg);