[amd64] Remove the callee saved registers from MonoLMF, save/restore them normally...
[mono-project.git] / mono / metadata / class.c
blob2a0b76e97dd170699e318dc54da0a740ef83f1ae
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 /* Function supplied by the runtime to find classes by name using information from the AOT file */
56 static MonoGetClassFromName get_class_from_name = NULL;
58 static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error);
59 static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res);
60 static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
61 static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
62 static int generic_array_methods (MonoClass *class);
63 static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos);
65 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
66 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
67 static void mono_field_resolve_type (MonoClassField *field, MonoError *error);
68 static guint32 mono_field_resolve_flags (MonoClassField *field);
69 static void mono_class_setup_vtable_full (MonoClass *class, GList *in_setup);
70 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
73 void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
77 We use gclass recording to allow recursive system f types to be referenced by a parent.
79 Given the following type hierarchy:
81 class TextBox : TextBoxBase<TextBox> {}
82 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
83 class TextInput<T> : Input<T> where T: TextInput<T> {}
84 class Input<T> {}
86 The runtime tries to load TextBoxBase<>.
87 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
88 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
89 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
91 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
92 at this point, iow, both are registered in the type map and both and a NULL parent. This means
93 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
95 To fix that what we do is to record all generic instantes created while resolving the parent of
96 any generic type definition and, after resolved, correct the parent field if needed.
99 static int record_gclass_instantiation;
100 static GSList *gclass_recorded_list;
101 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
104 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
106 static void
107 enable_gclass_recording (void)
109 ++record_gclass_instantiation;
113 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
115 static void
116 disable_gclass_recording (gclass_record_func func, void *user_data)
118 GSList **head = &gclass_recorded_list;
120 g_assert (record_gclass_instantiation > 0);
121 --record_gclass_instantiation;
123 while (*head) {
124 GSList *node = *head;
125 if (func ((MonoClass*)node->data, user_data)) {
126 *head = node->next;
127 g_slist_free_1 (node);
128 } else {
129 head = &node->next;
133 /* We automatically discard all recorded gclasses when disabled. */
134 if (!record_gclass_instantiation && gclass_recorded_list) {
135 g_slist_free (gclass_recorded_list);
136 gclass_recorded_list = NULL;
141 * mono_class_from_typeref:
142 * @image: a MonoImage
143 * @type_token: a TypeRef token
145 * Creates the MonoClass* structure representing the type defined by
146 * the typeref token valid inside @image.
147 * Returns: the MonoClass* representing the typeref token, NULL ifcould
148 * not be loaded.
150 MonoClass *
151 mono_class_from_typeref (MonoImage *image, guint32 type_token)
153 MonoError error;
154 guint32 cols [MONO_TYPEREF_SIZE];
155 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
156 guint32 idx;
157 const char *name, *nspace;
158 MonoClass *res;
159 MonoImage *module;
161 if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, &error)) {
162 mono_trace_warning (MONO_TRACE_TYPE, "Failed to resolve typeref from %s due to '%s'", image->name, mono_error_get_message (&error));
163 return NULL;
166 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
168 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
169 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
171 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLTION_SCOPE_BITS;
172 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLTION_SCOPE_MASK) {
173 case MONO_RESOLTION_SCOPE_MODULE:
175 LAMESPEC The spec says that a null module resolution scope should go through the exported type table.
176 This is not the observed behavior of existing implementations.
177 The defacto behavior is that it's just a typedef in disguise.
179 /* a typedef in disguise */
180 return mono_class_from_name (image, nspace, name);
181 case MONO_RESOLTION_SCOPE_MODULEREF:
182 module = mono_image_load_module (image, idx);
183 if (module)
184 return mono_class_from_name (module, nspace, name);
185 else {
186 char *msg = g_strdup_printf ("%s%s%s", nspace, nspace [0] ? "." : "", name);
187 char *human_name;
189 human_name = mono_stringify_assembly_name (&image->assembly->aname);
190 mono_loader_set_error_type_load (msg, human_name);
191 g_free (msg);
192 g_free (human_name);
194 return NULL;
196 case MONO_RESOLTION_SCOPE_TYPEREF: {
197 MonoClass *enclosing;
198 GList *tmp;
200 if (idx == mono_metadata_token_index (type_token)) {
201 mono_loader_set_error_bad_image (g_strdup_printf ("Image %s with self-referencing typeref token %08x.", image->name, type_token));
202 return NULL;
205 enclosing = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | idx);
206 if (!enclosing)
207 return NULL;
209 if (enclosing->nested_classes_inited && enclosing->ext) {
210 /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
211 for (tmp = enclosing->ext->nested_classes; tmp; tmp = tmp->next) {
212 res = tmp->data;
213 if (strcmp (res->name, name) == 0)
214 return res;
216 } else {
217 /* Don't call mono_class_init as we might've been called by it recursively */
218 int i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, 1);
219 while (i) {
220 guint32 class_nested = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, MONO_NESTED_CLASS_NESTED);
221 guint32 string_offset = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
222 const char *nname = mono_metadata_string_heap (enclosing->image, string_offset);
224 if (strcmp (nname, name) == 0) {
225 MonoClass *res = mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, &error);
226 if (!mono_error_ok (&error)) {
227 mono_loader_set_error_from_mono_error (&error);
228 mono_error_cleanup (&error); /*FIXME don't swallow error message.*/
229 return NULL;
231 return res;
234 i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1);
237 g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
238 return NULL;
240 case MONO_RESOLTION_SCOPE_ASSEMBLYREF:
241 break;
244 if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
245 mono_loader_set_error_bad_image (g_strdup_printf ("Image %s with invalid assemblyref token %08x.", image->name, idx));
246 return NULL;
249 if (!image->references || !image->references [idx - 1])
250 mono_assembly_load_reference (image, idx - 1);
251 g_assert (image->references [idx - 1]);
253 /* If the assembly did not load, register this as a type load exception */
254 if (image->references [idx - 1] == REFERENCE_MISSING){
255 MonoAssemblyName aname;
256 char *human_name;
258 mono_assembly_get_assemblyref (image, idx - 1, &aname);
259 human_name = mono_stringify_assembly_name (&aname);
260 mono_loader_set_error_assembly_load (human_name, image->assembly ? image->assembly->ref_only : FALSE);
261 g_free (human_name);
263 return NULL;
266 return mono_class_from_name (image->references [idx - 1]->image, nspace, name);
270 static void *
271 mono_image_memdup (MonoImage *image, void *data, guint size)
273 void *res = mono_image_alloc (image, size);
274 memcpy (res, data, size);
275 return res;
278 /* Copy everything mono_metadata_free_array free. */
279 MonoArrayType *
280 mono_dup_array_type (MonoImage *image, MonoArrayType *a)
282 if (image) {
283 a = mono_image_memdup (image, a, sizeof (MonoArrayType));
284 if (a->sizes)
285 a->sizes = mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
286 if (a->lobounds)
287 a->lobounds = mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
288 } else {
289 a = g_memdup (a, sizeof (MonoArrayType));
290 if (a->sizes)
291 a->sizes = g_memdup (a->sizes, a->numsizes * sizeof (int));
292 if (a->lobounds)
293 a->lobounds = g_memdup (a->lobounds, a->numlobounds * sizeof (int));
295 return a;
298 /* Copy everything mono_metadata_free_method_signature free. */
299 MonoMethodSignature*
300 mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
302 int i;
304 sig = mono_metadata_signature_dup_full (image, sig);
306 sig->ret = mono_metadata_type_dup (image, sig->ret);
307 for (i = 0; i < sig->param_count; ++i)
308 sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
310 return sig;
313 static void
314 _mono_type_get_assembly_name (MonoClass *klass, GString *str)
316 MonoAssembly *ta = klass->image->assembly;
317 char *name;
319 name = mono_stringify_assembly_name (&ta->aname);
320 g_string_append_printf (str, ", %s", name);
321 g_free (name);
324 static inline void
325 mono_type_name_check_byref (MonoType *type, GString *str)
327 if (type->byref)
328 g_string_append_c (str, '&');
331 static void
332 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
333 MonoTypeNameFormat format)
335 MonoClass *klass;
337 switch (type->type) {
338 case MONO_TYPE_ARRAY: {
339 int i, rank = type->data.array->rank;
340 MonoTypeNameFormat nested_format;
342 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
343 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
345 mono_type_get_name_recurse (
346 &type->data.array->eklass->byval_arg, str, FALSE, nested_format);
347 g_string_append_c (str, '[');
348 if (rank == 1)
349 g_string_append_c (str, '*');
350 for (i = 1; i < rank; i++)
351 g_string_append_c (str, ',');
352 g_string_append_c (str, ']');
354 mono_type_name_check_byref (type, str);
356 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
357 _mono_type_get_assembly_name (type->data.array->eklass, str);
358 break;
360 case MONO_TYPE_SZARRAY: {
361 MonoTypeNameFormat nested_format;
363 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
364 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
366 mono_type_get_name_recurse (
367 &type->data.klass->byval_arg, str, FALSE, nested_format);
368 g_string_append (str, "[]");
370 mono_type_name_check_byref (type, str);
372 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
373 _mono_type_get_assembly_name (type->data.klass, str);
374 break;
376 case MONO_TYPE_PTR: {
377 MonoTypeNameFormat nested_format;
379 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
380 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
382 mono_type_get_name_recurse (
383 type->data.type, str, FALSE, nested_format);
384 g_string_append_c (str, '*');
386 mono_type_name_check_byref (type, str);
388 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
389 _mono_type_get_assembly_name (mono_class_from_mono_type (type->data.type), str);
390 break;
392 case MONO_TYPE_VAR:
393 case MONO_TYPE_MVAR:
394 if (!mono_generic_param_info (type->data.generic_param))
395 g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
396 else
397 g_string_append (str, mono_generic_param_info (type->data.generic_param)->name);
399 mono_type_name_check_byref (type, str);
401 break;
402 default:
403 klass = mono_class_from_mono_type (type);
404 if (klass->nested_in) {
405 mono_type_get_name_recurse (
406 &klass->nested_in->byval_arg, str, TRUE, format);
407 if (format == MONO_TYPE_NAME_FORMAT_IL)
408 g_string_append_c (str, '.');
409 else
410 g_string_append_c (str, '+');
411 } else if (*klass->name_space) {
412 g_string_append (str, klass->name_space);
413 g_string_append_c (str, '.');
415 if (format == MONO_TYPE_NAME_FORMAT_IL) {
416 char *s = strchr (klass->name, '`');
417 int len = s ? s - klass->name : strlen (klass->name);
419 g_string_append_len (str, klass->name, len);
420 } else
421 g_string_append (str, klass->name);
422 if (is_recursed)
423 break;
424 if (klass->generic_class) {
425 MonoGenericClass *gclass = klass->generic_class;
426 MonoGenericInst *inst = gclass->context.class_inst;
427 MonoTypeNameFormat nested_format;
428 int i;
430 nested_format = format == MONO_TYPE_NAME_FORMAT_FULL_NAME ?
431 MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format;
433 if (format == MONO_TYPE_NAME_FORMAT_IL)
434 g_string_append_c (str, '<');
435 else
436 g_string_append_c (str, '[');
437 for (i = 0; i < inst->type_argc; i++) {
438 MonoType *t = inst->type_argv [i];
440 if (i)
441 g_string_append_c (str, ',');
442 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
443 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
444 g_string_append_c (str, '[');
445 mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
446 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
447 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
448 g_string_append_c (str, ']');
450 if (format == MONO_TYPE_NAME_FORMAT_IL)
451 g_string_append_c (str, '>');
452 else
453 g_string_append_c (str, ']');
454 } else if (klass->generic_container &&
455 (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
456 (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
457 int i;
459 if (format == MONO_TYPE_NAME_FORMAT_IL)
460 g_string_append_c (str, '<');
461 else
462 g_string_append_c (str, '[');
463 for (i = 0; i < klass->generic_container->type_argc; i++) {
464 if (i)
465 g_string_append_c (str, ',');
466 g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name);
468 if (format == MONO_TYPE_NAME_FORMAT_IL)
469 g_string_append_c (str, '>');
470 else
471 g_string_append_c (str, ']');
474 mono_type_name_check_byref (type, str);
476 if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
477 (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
478 _mono_type_get_assembly_name (klass, str);
479 break;
484 * mono_type_get_name_full:
485 * @type: a type
486 * @format: the format for the return string.
489 * Returns: the string representation in a number of formats:
491 * if format is MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
492 * returned in the formatrequired by System.Reflection, this is the
493 * inverse of mono_reflection_parse_type ().
495 * if format is MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
496 * be used by the IL assembler.
498 * if format is MONO_TYPE_NAME_FORMAT_FULL_NAME
500 * if format is MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
502 char*
503 mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
505 GString* result;
507 result = g_string_new ("");
509 mono_type_get_name_recurse (type, result, FALSE, format);
511 return g_string_free (result, FALSE);
515 * mono_type_get_full_name:
516 * @class: a class
518 * Returns: the string representation for type as required by System.Reflection.
519 * The inverse of mono_reflection_parse_type ().
521 char *
522 mono_type_get_full_name (MonoClass *class)
524 return mono_type_get_name_full (mono_class_get_type (class), MONO_TYPE_NAME_FORMAT_REFLECTION);
528 * mono_type_get_name:
529 * @type: a type
531 * Returns: the string representation for type as it would be represented in IL code.
533 char*
534 mono_type_get_name (MonoType *type)
536 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
540 * mono_type_get_underlying_type:
541 * @type: a type
543 * Returns: the MonoType for the underlying integer type if @type
544 * is an enum and byref is false, otherwise the type itself.
546 MonoType*
547 mono_type_get_underlying_type (MonoType *type)
549 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype && !type->byref)
550 return mono_class_enum_basetype (type->data.klass);
551 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype && !type->byref)
552 return mono_class_enum_basetype (type->data.generic_class->container_class);
553 return type;
557 * mono_class_is_open_constructed_type:
558 * @type: a type
560 * Returns TRUE if type represents a generics open constructed type.
561 * IOW, not all type parameters required for the instantiation have
562 * been provided or it's a generic type definition.
564 * An open constructed type means it's a non realizable type. Not to
565 * be mixed up with an abstract type - we can't cast or dispatch to
566 * an open type, for example.
568 gboolean
569 mono_class_is_open_constructed_type (MonoType *t)
571 switch (t->type) {
572 case MONO_TYPE_VAR:
573 case MONO_TYPE_MVAR:
574 return TRUE;
575 case MONO_TYPE_SZARRAY:
576 return mono_class_is_open_constructed_type (&t->data.klass->byval_arg);
577 case MONO_TYPE_ARRAY:
578 return mono_class_is_open_constructed_type (&t->data.array->eklass->byval_arg);
579 case MONO_TYPE_PTR:
580 return mono_class_is_open_constructed_type (t->data.type);
581 case MONO_TYPE_GENERICINST:
582 return t->data.generic_class->context.class_inst->is_open;
583 case MONO_TYPE_CLASS:
584 case MONO_TYPE_VALUETYPE:
585 return t->data.klass->generic_container != NULL;
586 default:
587 return FALSE;
592 This is a simple function to catch the most common bad instances of generic types.
593 Specially those that might lead to further failures in the runtime.
595 static gboolean
596 is_valid_generic_argument (MonoType *type)
598 switch (type->type) {
599 case MONO_TYPE_VOID:
600 //case MONO_TYPE_TYPEDBYREF:
601 return FALSE;
603 return TRUE;
606 static MonoType*
607 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
609 mono_error_init (error);
611 switch (type->type) {
612 case MONO_TYPE_MVAR: {
613 MonoType *nt;
614 int num = mono_type_get_generic_param_num (type);
615 MonoGenericInst *inst = context->method_inst;
616 if (!inst || !inst->type_argv)
617 return NULL;
618 if (num >= inst->type_argc) {
619 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
620 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
621 num, info ? info->name : "", inst->type_argc);
622 return NULL;
625 if (!is_valid_generic_argument (inst->type_argv [num])) {
626 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
627 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
628 num, info ? info->name : "", inst->type_argv [num]->type);
629 return NULL;
632 * Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
633 * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
634 * ->byref and ->attrs from @type are propagated to the returned type.
636 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
637 nt->byref = type->byref;
638 nt->attrs = type->attrs;
639 return nt;
641 case MONO_TYPE_VAR: {
642 MonoType *nt;
643 int num = mono_type_get_generic_param_num (type);
644 MonoGenericInst *inst = context->class_inst;
645 if (!inst)
646 return NULL;
647 if (num >= inst->type_argc) {
648 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
649 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
650 num, info ? info->name : "", inst->type_argc);
651 return NULL;
653 if (!is_valid_generic_argument (inst->type_argv [num])) {
654 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
655 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
656 num, info ? info->name : "", inst->type_argv [num]->type);
657 return NULL;
659 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
660 nt->byref = type->byref;
661 nt->attrs = type->attrs;
662 return nt;
664 case MONO_TYPE_SZARRAY: {
665 MonoClass *eclass = type->data.klass;
666 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
667 if (!inflated || !mono_error_ok (error))
668 return NULL;
669 nt = mono_metadata_type_dup (image, type);
670 nt->data.klass = mono_class_from_mono_type (inflated);
671 mono_metadata_free_type (inflated);
672 return nt;
674 case MONO_TYPE_ARRAY: {
675 MonoClass *eclass = type->data.array->eklass;
676 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
677 if (!inflated || !mono_error_ok (error))
678 return NULL;
679 nt = mono_metadata_type_dup (image, type);
680 nt->data.array->eklass = mono_class_from_mono_type (inflated);
681 mono_metadata_free_type (inflated);
682 return nt;
684 case MONO_TYPE_GENERICINST: {
685 MonoGenericClass *gclass = type->data.generic_class;
686 MonoGenericInst *inst;
687 MonoType *nt;
688 if (!gclass->context.class_inst->is_open)
689 return NULL;
691 inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
692 if (!mono_error_ok (error))
693 return NULL;
694 if (inst != gclass->context.class_inst)
695 gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
697 if (gclass == type->data.generic_class)
698 return NULL;
700 nt = mono_metadata_type_dup (image, type);
701 nt->data.generic_class = gclass;
702 return nt;
704 case MONO_TYPE_CLASS:
705 case MONO_TYPE_VALUETYPE: {
706 MonoClass *klass = type->data.klass;
707 MonoGenericContainer *container = klass->generic_container;
708 MonoGenericInst *inst;
709 MonoGenericClass *gclass = NULL;
710 MonoType *nt;
712 if (!container)
713 return NULL;
715 /* We can't use context->class_inst directly, since it can have more elements */
716 inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
717 if (!mono_error_ok (error))
718 return NULL;
719 if (inst == container->context.class_inst)
720 return NULL;
722 gclass = mono_metadata_lookup_generic_class (klass, inst, klass->image->dynamic);
724 nt = mono_metadata_type_dup (image, type);
725 nt->type = MONO_TYPE_GENERICINST;
726 nt->data.generic_class = gclass;
727 return nt;
729 default:
730 return NULL;
732 return NULL;
735 MonoGenericContext *
736 mono_generic_class_get_context (MonoGenericClass *gclass)
738 return &gclass->context;
741 MonoGenericContext *
742 mono_class_get_context (MonoClass *class)
744 return class->generic_class ? mono_generic_class_get_context (class->generic_class) : NULL;
748 * mono_class_get_generic_container:
750 * Return the generic container of KLASS which should be a generic type definition.
752 MonoGenericContainer*
753 mono_class_get_generic_container (MonoClass *klass)
755 g_assert (klass->is_generic);
757 return klass->generic_container;
761 * mono_class_get_generic_class:
763 * Return the MonoGenericClass of KLASS, which should be a generic instance.
765 MonoGenericClass*
766 mono_class_get_generic_class (MonoClass *klass)
768 g_assert (klass->is_inflated);
770 return klass->generic_class;
774 * mono_class_inflate_generic_type_with_mempool:
775 * @mempool: a mempool
776 * @type: a type
777 * @context: a generics context
778 * @error: error context
780 * The same as mono_class_inflate_generic_type, but allocates the MonoType
781 * from mempool if it is non-NULL. If it is NULL, the MonoType is
782 * allocated on the heap and is owned by the caller.
783 * The returned type can potentially be the same as TYPE, so it should not be
784 * modified by the caller, and it should be freed using mono_metadata_free_type ().
786 MonoType*
787 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
789 MonoType *inflated = NULL;
790 mono_error_init (error);
792 if (context)
793 inflated = inflate_generic_type (image, type, context, error);
794 if (!mono_error_ok (error))
795 return NULL;
797 if (!inflated) {
798 MonoType *shared = mono_metadata_get_shared_type (type);
800 if (shared) {
801 return shared;
802 } else {
803 return mono_metadata_type_dup (image, type);
807 mono_stats.inflated_type_count++;
808 return inflated;
812 * mono_class_inflate_generic_type:
813 * @type: a type
814 * @context: a generics context
816 * If @type is a generic type and @context is not NULL, instantiate it using the
817 * generics context @context.
819 * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
820 * on the heap and is owned by the caller. Returns NULL on error.
822 * @deprecated Please use mono_class_inflate_generic_type_checked instead
824 MonoType*
825 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
827 MonoError error;
828 MonoType *result;
829 result = mono_class_inflate_generic_type_checked (type, context, &error);
831 if (!mono_error_ok (&error)) {
832 mono_error_cleanup (&error);
833 return NULL;
835 return result;
839 * mono_class_inflate_generic_type:
840 * @type: a type
841 * @context: a generics context
842 * @error: error context to use
844 * If @type is a generic type and @context is not NULL, instantiate it using the
845 * generics context @context.
847 * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
848 * on the heap and is owned by the caller.
850 MonoType*
851 mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
853 return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
857 * mono_class_inflate_generic_type_no_copy:
859 * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
860 * was done.
862 static MonoType*
863 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
865 MonoType *inflated = NULL;
867 mono_error_init (error);
868 if (context) {
869 inflated = inflate_generic_type (image, type, context, error);
870 if (!mono_error_ok (error))
871 return NULL;
874 if (!inflated)
875 return type;
877 mono_stats.inflated_type_count++;
878 return inflated;
881 static MonoClass*
882 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
884 MonoClass *res;
885 MonoType *inflated;
887 inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, error);
888 if (!mono_error_ok (error))
889 return NULL;
891 res = mono_class_from_mono_type (inflated);
892 mono_metadata_free_type (inflated);
894 return res;
897 * mono_class_inflate_generic_class:
899 * Inflate the class GKLASS with CONTEXT.
901 MonoClass*
902 mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context)
904 MonoError error;
905 MonoClass *res;
907 res = mono_class_inflate_generic_class_checked (gklass, context, &error);
908 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
910 return res;
915 static MonoGenericContext
916 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
918 MonoGenericInst *class_inst = NULL;
919 MonoGenericInst *method_inst = NULL;
920 MonoGenericContext res = { NULL, NULL };
922 mono_error_init (error);
924 if (context->class_inst) {
925 class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
926 if (!mono_error_ok (error))
927 goto fail;
930 if (context->method_inst) {
931 method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with, error);
932 if (!mono_error_ok (error))
933 goto fail;
936 res.class_inst = class_inst;
937 res.method_inst = method_inst;
938 fail:
939 return res;
943 * mono_class_inflate_generic_method:
944 * @method: a generic method
945 * @context: a generics context
947 * Instantiate the generic method @method using the generics context @context.
949 * Returns: the new instantiated method
951 MonoMethod *
952 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
954 return mono_class_inflate_generic_method_full (method, NULL, context);
958 * mono_class_inflate_generic_method_full:
960 * Instantiate method @method with the generic context @context.
961 * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
962 * Use mono_method_signature () and mono_method_get_header () to get the correct values.
964 MonoMethod*
965 mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context)
967 MonoError error;
968 MonoMethod *res = mono_class_inflate_generic_method_full_checked (method, klass_hint, context, &error);
969 if (!mono_error_ok (&error))
970 /*FIXME do proper error handling - on this case, kill this function. */
971 g_error ("Could not inflate generic method due to %s", mono_error_get_message (&error));
973 return res;
977 * mono_class_inflate_generic_method_full_checked:
978 * Same as mono_class_inflate_generic_method_full but return failure using @error.
980 MonoMethod*
981 mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error)
983 MonoMethod *result;
984 MonoMethodInflated *iresult, *cached;
985 MonoMethodSignature *sig;
986 MonoGenericContext tmp_context;
987 gboolean is_mb_open = FALSE;
989 mono_error_init (error);
991 /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
992 while (method->is_inflated) {
993 MonoGenericContext *method_context = mono_method_get_context (method);
994 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
996 tmp_context = inflate_generic_context (method_context, context, error);
997 if (!mono_error_ok (error))
998 return NULL;
999 context = &tmp_context;
1001 if (mono_metadata_generic_context_equal (method_context, context))
1002 return method;
1004 method = imethod->declaring;
1008 * A method only needs to be inflated if the context has argument for which it is
1009 * parametric. Eg:
1011 * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
1012 * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
1015 if (!((method->is_generic && context->method_inst) ||
1016 (method->klass->generic_container && context->class_inst)))
1017 return method;
1020 * The reason for this hack is to fix the behavior of inflating generic methods that come from a MethodBuilder.
1021 * What happens is that instantiating a generic MethodBuilder with its own arguments should create a diferent object.
1022 * This is opposite to the way non-SRE MethodInfos behave.
1024 * This happens, for example, when we want to emit a recursive generic method. Given the following C# code:
1026 * void Example<T> () {
1027 * Example<T> ();
1030 * In Example, the method token must be encoded as: "void Example<!!0>()"
1032 * The reference to the first generic argument, "!!0", must be explicit otherwise it won't be inflated
1033 * properly. To get that we need to inflate the MethodBuilder with its own arguments.
1035 * On the other hand, inflating a non-SRE generic method with its own arguments should
1036 * return itself. For example:
1038 * MethodInfo m = ... //m is a generic method definition
1039 * MethodInfo res = m.MakeGenericMethod (m.GetGenericArguments ());
1040 * res == m
1042 * To allow such scenarios we must allow inflation of MethodBuilder to happen in a diferent way than
1043 * what happens with regular methods.
1045 * There is one last touch to this madness, once a TypeBuilder is finished, IOW CreateType() is called,
1046 * everything should behave like a regular type or method.
1049 is_mb_open = method->is_generic &&
1050 method->klass->image->dynamic && !method->klass->wastypebuilder && /* that is a MethodBuilder from an unfinished TypeBuilder */
1051 context->method_inst == mono_method_get_generic_container (method)->context.method_inst; /* and it's been instantiated with its own arguments. */
1053 iresult = g_new0 (MonoMethodInflated, 1);
1054 iresult->context = *context;
1055 iresult->declaring = method;
1056 iresult->method.method.is_mb_open = is_mb_open;
1058 if (!context->method_inst && method->is_generic)
1059 iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
1061 if (!context->class_inst) {
1062 g_assert (!iresult->declaring->klass->generic_class);
1063 if (iresult->declaring->klass->generic_container)
1064 iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst;
1065 else if (iresult->declaring->klass->generic_class)
1066 iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst;
1069 mono_loader_lock ();
1070 cached = mono_method_inflated_lookup (iresult, FALSE);
1071 if (cached) {
1072 mono_loader_unlock ();
1073 g_free (iresult);
1074 return (MonoMethod*)cached;
1077 mono_stats.inflated_method_count++;
1079 inflated_methods_size += sizeof (MonoMethodInflated);
1081 sig = mono_method_signature (method);
1082 if (!sig) {
1083 char *name = mono_type_get_full_name (method->klass);
1084 mono_error_set_bad_image (error, method->klass->image, "Could not resolve signature of method %s:%s", name, method->name);
1085 g_free (name);
1086 goto fail;
1089 if (sig->pinvoke) {
1090 memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
1091 } else {
1092 memcpy (&iresult->method.method, method, sizeof (MonoMethod));
1095 result = (MonoMethod *) iresult;
1096 result->is_inflated = TRUE;
1097 result->is_generic = FALSE;
1098 result->sre_method = FALSE;
1099 result->signature = NULL;
1100 result->is_mb_open = is_mb_open;
1102 if (!context->method_inst) {
1103 /* Set the generic_container of the result to the generic_container of method */
1104 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
1106 if (generic_container) {
1107 result->is_generic = 1;
1108 mono_method_set_generic_container (result, generic_container);
1112 if (!klass_hint || !klass_hint->generic_class ||
1113 klass_hint->generic_class->container_class != method->klass ||
1114 klass_hint->generic_class->context.class_inst != context->class_inst)
1115 klass_hint = NULL;
1117 if (method->klass->generic_container)
1118 result->klass = klass_hint;
1120 if (!result->klass) {
1121 MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context, error);
1122 if (!mono_error_ok (error))
1123 goto fail;
1125 result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
1126 if (inflated)
1127 mono_metadata_free_type (inflated);
1131 * FIXME: This should hold, but it doesn't:
1133 * if (result->is_inflated && mono_method_get_context (result)->method_inst &&
1134 * mono_method_get_context (result)->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)result)->declaring)->context.method_inst) {
1135 * g_assert (result->is_generic);
1138 * Fixing this here causes other things to break, hence a very
1139 * ugly hack in mini-trampolines.c - see
1140 * is_generic_method_definition().
1143 mono_method_inflated_lookup (iresult, TRUE);
1144 mono_loader_unlock ();
1145 return result;
1147 fail:
1148 mono_loader_unlock ();
1149 g_free (iresult);
1150 return NULL;
1154 * mono_get_inflated_method:
1156 * Obsolete. We keep it around since it's mentioned in the public API.
1158 MonoMethod*
1159 mono_get_inflated_method (MonoMethod *method)
1161 return method;
1165 * mono_method_get_context_general:
1166 * @method: a method
1167 * @uninflated: handle uninflated methods?
1169 * Returns the generic context of a method or NULL if it doesn't have
1170 * one. For an inflated method that's the context stored in the
1171 * method. Otherwise it's in the method's generic container or in the
1172 * generic container of the method's class.
1174 MonoGenericContext*
1175 mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
1177 if (method->is_inflated) {
1178 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1179 return &imethod->context;
1181 if (!uninflated)
1182 return NULL;
1183 if (method->is_generic)
1184 return &(mono_method_get_generic_container (method)->context);
1185 if (method->klass->generic_container)
1186 return &method->klass->generic_container->context;
1187 return NULL;
1191 * mono_method_get_context:
1192 * @method: a method
1194 * Returns the generic context for method if it's inflated, otherwise
1195 * NULL.
1197 MonoGenericContext*
1198 mono_method_get_context (MonoMethod *method)
1200 return mono_method_get_context_general (method, FALSE);
1204 * mono_method_get_generic_container:
1206 * Returns the generic container of METHOD, which should be a generic method definition.
1207 * Returns NULL if METHOD is not a generic method definition.
1208 * LOCKING: Acquires the loader lock.
1210 MonoGenericContainer*
1211 mono_method_get_generic_container (MonoMethod *method)
1213 MonoGenericContainer *container;
1215 if (!method->is_generic)
1216 return NULL;
1218 container = mono_image_property_lookup (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER);
1219 g_assert (container);
1221 return container;
1225 * mono_method_set_generic_container:
1227 * Sets the generic container of METHOD to CONTAINER.
1228 * LOCKING: Acquires the loader lock.
1230 void
1231 mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
1233 g_assert (method->is_generic);
1235 mono_image_property_insert (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
1238 /**
1239 * mono_class_find_enum_basetype:
1240 * @class: The enum class
1242 * Determine the basetype of an enum by iterating through its fields. We do this
1243 * in a separate function since it is cheaper than calling mono_class_setup_fields.
1245 static MonoType*
1246 mono_class_find_enum_basetype (MonoClass *class)
1248 MonoGenericContainer *container = NULL;
1249 MonoImage *m = class->image;
1250 const int top = class->field.count;
1251 int i;
1253 g_assert (class->enumtype);
1255 if (class->generic_container)
1256 container = class->generic_container;
1257 else if (class->generic_class) {
1258 MonoClass *gklass = class->generic_class->container_class;
1260 container = gklass->generic_container;
1261 g_assert (container);
1265 * Fetch all the field information.
1267 for (i = 0; i < top; i++){
1268 const char *sig;
1269 guint32 cols [MONO_FIELD_SIZE];
1270 int idx = class->field.first + i;
1271 MonoType *ftype;
1273 /* class->field.first and idx points into the fieldptr table */
1274 mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
1276 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
1277 continue;
1279 if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL))
1280 return NULL;
1282 sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
1283 mono_metadata_decode_value (sig, &sig);
1284 /* FIELD signature == 0x06 */
1285 if (*sig != 0x06)
1286 return NULL;
1288 ftype = mono_metadata_parse_type_full (m, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
1289 if (!ftype)
1290 return NULL;
1291 if (class->generic_class) {
1292 //FIXME do we leak here?
1293 ftype = mono_class_inflate_generic_type (ftype, mono_class_get_context (class));
1294 ftype->attrs = cols [MONO_FIELD_FLAGS];
1297 return ftype;
1300 return NULL;
1304 * Checks for MonoClass::exception_type without resolving all MonoType's into MonoClass'es
1306 static gboolean
1307 mono_type_has_exceptions (MonoType *type)
1309 switch (type->type) {
1310 case MONO_TYPE_CLASS:
1311 case MONO_TYPE_VALUETYPE:
1312 case MONO_TYPE_SZARRAY:
1313 return type->data.klass->exception_type;
1314 case MONO_TYPE_ARRAY:
1315 return type->data.array->eklass->exception_type;
1316 case MONO_TYPE_GENERICINST:
1317 return mono_generic_class_get_class (type->data.generic_class)->exception_type;
1319 return FALSE;
1323 * mono_class_alloc:
1325 * Allocate memory for some data belonging to CLASS, either from its image's mempool,
1326 * or from the heap.
1328 static gpointer
1329 mono_class_alloc (MonoClass *class, int size)
1331 if (class->generic_class)
1332 return mono_image_set_alloc (class->generic_class->owner, size);
1333 else
1334 return mono_image_alloc (class->image, size);
1337 static gpointer
1338 mono_class_alloc0 (MonoClass *class, int size)
1340 gpointer res;
1342 res = mono_class_alloc (class, size);
1343 memset (res, 0, size);
1344 return res;
1347 #define mono_class_new0(class,struct_type, n_structs) \
1348 ((struct_type *) mono_class_alloc0 ((class), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
1351 * mono_class_setup_basic_field_info:
1352 * @class: The class to initialize
1354 * Initializes the class->fields.
1355 * LOCKING: Assumes the loader lock is held.
1357 static void
1358 mono_class_setup_basic_field_info (MonoClass *class)
1360 MonoClassField *field;
1361 MonoClass *gtd;
1362 MonoImage *image;
1363 int i, top;
1365 if (class->fields)
1366 return;
1368 gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
1369 image = class->image;
1370 top = class->field.count;
1372 if (class->generic_class && class->generic_class->container_class->image->dynamic && !class->generic_class->container_class->wastypebuilder) {
1374 * This happens when a generic instance of an unfinished generic typebuilder
1375 * is used as an element type for creating an array type. We can't initialize
1376 * the fields of this class using the fields of gklass, since gklass is not
1377 * finished yet, fields could be added to it later.
1379 return;
1382 if (gtd) {
1383 mono_class_setup_basic_field_info (gtd);
1385 top = gtd->field.count;
1386 class->field.first = gtd->field.first;
1387 class->field.count = gtd->field.count;
1390 class->fields = mono_class_alloc0 (class, sizeof (MonoClassField) * top);
1393 * Fetch all the field information.
1395 for (i = 0; i < top; i++){
1396 field = &class->fields [i];
1397 field->parent = class;
1399 if (gtd) {
1400 field->name = mono_field_get_name (&gtd->fields [i]);
1401 } else {
1402 int idx = class->field.first + i;
1403 /* class->field.first and idx points into the fieldptr table */
1404 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
1405 /* The name is needed for fieldrefs */
1406 field->name = mono_metadata_string_heap (image, name_idx);
1411 /**
1412 * mono_class_setup_fields:
1413 * @class: The class to initialize
1415 * Initializes the class->fields.
1416 * LOCKING: Assumes the loader lock is held.
1418 static void
1419 mono_class_setup_fields (MonoClass *class)
1421 MonoError error;
1422 MonoImage *m = class->image;
1423 int top;
1424 guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
1425 int i, blittable = TRUE;
1426 guint32 real_size = 0;
1427 guint32 packing_size = 0;
1428 gboolean explicit_size;
1429 MonoClassField *field;
1430 MonoGenericContainer *container = NULL;
1431 MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
1434 * FIXME: We have a race condition here. It's possible that this function returns
1435 * to its caller with `instance_size` set to `0` instead of the actual size. This
1436 * is not a problem when the function is called recursively on the same class,
1437 * because the size will be initialized by the outer invocation. What follows is a
1438 * description of how it can occur in other cases, too. There it is a problem,
1439 * because it can lead to the GC being asked to allocate an object of size `0`,
1440 * which SGen chokes on. The race condition is triggered infrequently by
1441 * `tests/sgen-suspend.cs`.
1443 * This function is called for a class whenever one of its subclasses is inited.
1444 * For example, it's called for every subclass of Object. What it does is this:
1446 * if (class->setup_fields_called)
1447 * return;
1448 * ...
1449 * class->instance_size = 0;
1450 * ...
1451 * class->setup_fields_called = 1;
1452 * ... critical point
1453 * class->instance_size = actual_instance_size;
1455 * The last two steps are sometimes reversed, but that only changes the way in which
1456 * the race condition works.
1458 * Assume thread A goes through this function and makes it to the critical point.
1459 * Now thread B runs the function and, since `setup_fields_called` is set, returns
1460 * immediately, but `instance_size` is incorrect.
1462 * The other case looks like this:
1464 * if (class->setup_fields_called)
1465 * return;
1466 * ... critical point X
1467 * class->instance_size = 0;
1468 * ... critical point Y
1469 * class->instance_size = actual_instance_size;
1470 * ...
1471 * class->setup_fields_called = 1;
1473 * Assume thread A goes through the function and makes it to critical point X. Now
1474 * thread B runs through the whole of the function, returning, assuming
1475 * `instance_size` is set. At that point thread A gets to run and makes it to
1476 * critical point Y, at which time `instance_size` is `0` again, invalidating thread
1477 * B's assumption.
1479 if (class->setup_fields_called)
1480 return;
1482 if (class->generic_class && class->generic_class->container_class->image->dynamic && !class->generic_class->container_class->wastypebuilder) {
1484 * This happens when a generic instance of an unfinished generic typebuilder
1485 * is used as an element type for creating an array type. We can't initialize
1486 * the fields of this class using the fields of gklass, since gklass is not
1487 * finished yet, fields could be added to it later.
1489 return;
1492 mono_class_setup_basic_field_info (class);
1493 top = class->field.count;
1495 if (gtd) {
1496 mono_class_setup_fields (gtd);
1497 if (gtd->exception_type) {
1498 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1499 return;
1503 class->instance_size = 0;
1504 if (!class->rank)
1505 class->sizes.class_size = 0;
1507 if (class->parent) {
1508 /* For generic instances, class->parent might not have been initialized */
1509 mono_class_init (class->parent);
1510 if (!class->parent->size_inited) {
1511 mono_class_setup_fields (class->parent);
1512 if (class->parent->exception_type) {
1513 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1514 return;
1517 class->instance_size += class->parent->instance_size;
1518 class->min_align = class->parent->min_align;
1519 /* we use |= since it may have been set already */
1520 class->has_references |= class->parent->has_references;
1521 blittable = class->parent->blittable;
1522 } else {
1523 class->instance_size = sizeof (MonoObject);
1524 class->min_align = 1;
1527 /* We can't really enable 16 bytes alignment until the GC supports it.
1528 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
1529 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
1530 Bug #506144 is an example of this issue.
1532 if (class->simd_type)
1533 class->min_align = 16;
1535 /* Get the real size */
1536 explicit_size = mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &real_size);
1538 if (explicit_size) {
1539 if ((packing_size & 0xfffffff0) != 0) {
1540 char *err_msg = g_strdup_printf ("Could not load struct '%s' with packing size %d >= 16", class->name, packing_size);
1541 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
1542 return;
1544 class->packing_size = packing_size;
1545 real_size += class->instance_size;
1548 if (!top) {
1549 if (explicit_size && real_size) {
1550 class->instance_size = MAX (real_size, class->instance_size);
1552 class->blittable = blittable;
1553 mono_memory_barrier ();
1554 class->size_inited = 1;
1555 class->fields_inited = 1;
1556 class->setup_fields_called = 1;
1557 return;
1560 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT)
1561 blittable = FALSE;
1563 /* Prevent infinite loops if the class references itself */
1564 class->setup_fields_called = 1;
1566 if (class->generic_container) {
1567 container = class->generic_container;
1568 } else if (gtd) {
1569 container = gtd->generic_container;
1570 g_assert (container);
1574 * Fetch all the field information.
1576 for (i = 0; i < top; i++){
1577 int idx = class->field.first + i;
1578 field = &class->fields [i];
1580 field->parent = class;
1582 if (!field->type) {
1583 mono_field_resolve_type (field, &error);
1584 if (!mono_error_ok (&error)) {
1585 /*mono_field_resolve_type already failed class*/
1586 mono_error_cleanup (&error);
1587 return;
1589 if (!field->type)
1590 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(class), field->name);
1591 g_assert (field->type);
1594 if (mono_field_is_deleted (field))
1595 continue;
1596 if (gtd) {
1597 MonoClassField *gfield = &gtd->fields [i];
1598 field->offset = gfield->offset;
1599 } else {
1600 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
1601 guint32 offset;
1602 mono_metadata_field_info (m, idx, &offset, NULL, NULL);
1603 field->offset = offset;
1605 if (field->offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1606 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Missing field layout info for %s", field->name));
1607 break;
1609 if (field->offset < -1) { /*-1 is used to encode special static fields */
1610 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Invalid negative field offset %d for %s", field->offset, field->name));
1611 break;
1616 /* Only do these checks if we still think this type is blittable */
1617 if (blittable && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1618 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
1619 blittable = FALSE;
1620 } else {
1621 MonoClass *field_class = mono_class_from_mono_type (field->type);
1622 if (field_class) {
1623 mono_class_setup_fields (field_class);
1624 if (field_class->exception_type) {
1625 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1626 break;
1629 if (!field_class || !field_class->blittable)
1630 blittable = FALSE;
1634 if (class->enumtype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1635 class->cast_class = class->element_class = mono_class_from_mono_type (field->type);
1636 blittable = class->element_class->blittable;
1639 if (mono_type_has_exceptions (field->type)) {
1640 char *class_name = mono_type_get_full_name (class);
1641 char *type_name = mono_type_full_name (field->type);
1643 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1644 g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
1645 g_free (class_name);
1646 g_free (type_name);
1647 break;
1649 /* The def_value of fields is compute lazily during vtable creation */
1652 if (class == mono_defaults.string_class)
1653 blittable = FALSE;
1655 class->blittable = blittable;
1657 if (class->enumtype && !mono_class_enum_basetype (class)) {
1658 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1659 return;
1661 if (explicit_size && real_size) {
1662 class->instance_size = MAX (real_size, class->instance_size);
1665 if (class->exception_type)
1666 return;
1667 mono_class_layout_fields (class);
1669 /*valuetypes can't be neither bigger than 1Mb or empty. */
1670 if (class->valuetype && (class->instance_size <= 0 || class->instance_size > (0x100000 + sizeof (MonoObject))))
1671 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1673 mono_memory_barrier ();
1674 class->fields_inited = 1;
1677 /**
1678 * mono_class_setup_fields_locking:
1679 * @class: The class to initialize
1681 * Initializes the class->fields array of fields.
1682 * Aquires the loader lock.
1684 void
1685 mono_class_setup_fields_locking (MonoClass *class)
1687 /* This can be checked without locks */
1688 if (class->fields_inited)
1689 return;
1690 mono_loader_lock ();
1691 mono_class_setup_fields (class);
1692 mono_loader_unlock ();
1696 * mono_class_has_references:
1698 * Returns whenever @klass->has_references is set, initializing it if needed.
1699 * Aquires the loader lock.
1701 static gboolean
1702 mono_class_has_references (MonoClass *klass)
1704 if (klass->init_pending) {
1705 /* Be conservative */
1706 return TRUE;
1707 } else {
1708 mono_class_init (klass);
1710 return klass->has_references;
1715 * mono_type_get_basic_type_from_generic:
1716 * @type: a type
1718 * Returns a closed type corresponding to the possibly open type
1719 * passed to it.
1721 MonoType*
1722 mono_type_get_basic_type_from_generic (MonoType *type)
1724 /* When we do generic sharing we let type variables stand for reference types. */
1725 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1726 return &mono_defaults.object_class->byval_arg;
1727 return type;
1731 * mono_class_layout_fields:
1732 * @class: a class
1734 * Compute the placement of fields inside an object or struct, according to
1735 * the layout rules and set the following fields in @class:
1736 * - has_references (if the class contains instance references firled or structs that contain references)
1737 * - has_static_refs (same, but for static fields)
1738 * - instance_size (size of the object in memory)
1739 * - class_size (size needed for the static fields)
1740 * - size_inited (flag set when the instance_size is set)
1742 * LOCKING: this is supposed to be called with the loader lock held.
1744 void
1745 mono_class_layout_fields (MonoClass *class)
1747 int i;
1748 const int top = class->field.count;
1749 guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
1750 guint32 pass, passes, real_size;
1751 gboolean gc_aware_layout = FALSE;
1752 gboolean has_static_fields = FALSE;
1753 MonoClassField *field;
1756 * When we do generic sharing we need to have layout
1757 * information for open generic classes (either with a generic
1758 * context containing type variables or with a generic
1759 * container), so we don't return in that case anymore.
1763 * Enable GC aware auto layout: in this mode, reference
1764 * fields are grouped together inside objects, increasing collector
1765 * performance.
1766 * Requires that all classes whose layout is known to native code be annotated
1767 * with [StructLayout (LayoutKind.Sequential)]
1768 * Value types have gc_aware_layout disabled by default, as per
1769 * what the default is for other runtimes.
1771 /* corlib is missing [StructLayout] directives in many places */
1772 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
1773 if (!class->valuetype)
1774 gc_aware_layout = TRUE;
1777 /* Compute klass->has_references */
1779 * Process non-static fields first, since static fields might recursively
1780 * refer to the class itself.
1782 for (i = 0; i < top; i++) {
1783 MonoType *ftype;
1785 field = &class->fields [i];
1787 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1788 ftype = mono_type_get_underlying_type (field->type);
1789 ftype = mono_type_get_basic_type_from_generic (ftype);
1790 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
1791 class->has_references = TRUE;
1795 for (i = 0; i < top; i++) {
1796 MonoType *ftype;
1798 field = &class->fields [i];
1800 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1801 ftype = mono_type_get_underlying_type (field->type);
1802 ftype = mono_type_get_basic_type_from_generic (ftype);
1803 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
1804 class->has_static_refs = TRUE;
1808 for (i = 0; i < top; i++) {
1809 MonoType *ftype;
1811 field = &class->fields [i];
1813 ftype = mono_type_get_underlying_type (field->type);
1814 ftype = mono_type_get_basic_type_from_generic (ftype);
1815 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
1816 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1817 class->has_static_refs = TRUE;
1818 else
1819 class->has_references = TRUE;
1824 * Compute field layout and total size (not considering static fields)
1827 switch (layout) {
1828 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
1829 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
1831 if (gc_aware_layout)
1832 passes = 2;
1833 else
1834 passes = 1;
1836 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
1837 passes = 1;
1839 if (class->parent) {
1840 mono_class_setup_fields (class->parent);
1841 if (class->parent->exception_type) {
1842 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1843 return;
1845 real_size = class->parent->instance_size;
1846 } else {
1847 real_size = sizeof (MonoObject);
1850 for (pass = 0; pass < passes; ++pass) {
1851 for (i = 0; i < top; i++){
1852 gint32 align;
1853 guint32 size;
1854 MonoType *ftype;
1856 field = &class->fields [i];
1858 if (mono_field_is_deleted (field))
1859 continue;
1860 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1861 continue;
1863 ftype = mono_type_get_underlying_type (field->type);
1864 ftype = mono_type_get_basic_type_from_generic (ftype);
1865 if (gc_aware_layout) {
1866 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
1867 if (pass == 1)
1868 continue;
1869 } else {
1870 if (pass == 0)
1871 continue;
1875 if ((top == 1) && (class->instance_size == sizeof (MonoObject)) &&
1876 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
1877 /* This field is a hack inserted by MCS to empty structures */
1878 continue;
1881 size = mono_type_size (field->type, &align);
1883 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
1884 align = class->packing_size ? MIN (class->packing_size, align): align;
1885 /* if the field has managed references, we need to force-align it
1886 * see bug #77788
1888 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
1889 align = MAX (align, sizeof (gpointer));
1891 class->min_align = MAX (align, class->min_align);
1892 field->offset = real_size;
1893 if (align) {
1894 field->offset += align - 1;
1895 field->offset &= ~(align - 1);
1897 /*TypeBuilders produce all sort of weird things*/
1898 g_assert (class->image->dynamic || field->offset > 0);
1899 real_size = field->offset + size;
1902 class->instance_size = MAX (real_size, class->instance_size);
1904 if (class->instance_size & (class->min_align - 1)) {
1905 class->instance_size += class->min_align - 1;
1906 class->instance_size &= ~(class->min_align - 1);
1909 break;
1910 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
1911 real_size = 0;
1912 for (i = 0; i < top; i++) {
1913 gint32 align;
1914 guint32 size;
1915 MonoType *ftype;
1917 field = &class->fields [i];
1920 * There must be info about all the fields in a type if it
1921 * uses explicit layout.
1924 if (mono_field_is_deleted (field))
1925 continue;
1926 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1927 continue;
1929 size = mono_type_size (field->type, &align);
1930 align = class->packing_size ? MIN (class->packing_size, align): align;
1931 class->min_align = MAX (align, class->min_align);
1934 * When we get here, field->offset is already set by the
1935 * loader (for either runtime fields or fields loaded from metadata).
1936 * The offset is from the start of the object: this works for both
1937 * classes and valuetypes.
1939 field->offset += sizeof (MonoObject);
1940 ftype = mono_type_get_underlying_type (field->type);
1941 ftype = mono_type_get_basic_type_from_generic (ftype);
1942 if (MONO_TYPE_IS_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
1943 if (field->offset % sizeof (gpointer)) {
1944 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1949 * Calc max size.
1951 real_size = MAX (real_size, size + field->offset);
1953 class->instance_size = MAX (real_size, class->instance_size);
1954 if (class->instance_size & (class->min_align - 1)) {
1955 class->instance_size += class->min_align - 1;
1956 class->instance_size &= ~(class->min_align - 1);
1958 break;
1961 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
1963 * For small structs, set min_align to at least the struct size to improve
1964 * performance, and since the JIT memset/memcpy code assumes this and generates
1965 * unaligned accesses otherwise. See #78990 for a testcase.
1967 if (class->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
1968 class->min_align = MAX (class->min_align, class->instance_size - sizeof (MonoObject));
1971 mono_memory_barrier ();
1972 class->size_inited = 1;
1975 * Compute static field layout and size
1977 for (i = 0; i < top; i++){
1978 gint32 align;
1979 guint32 size;
1981 field = &class->fields [i];
1983 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
1984 continue;
1985 if (mono_field_is_deleted (field))
1986 continue;
1988 if (mono_type_has_exceptions (field->type)) {
1989 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1990 break;
1993 has_static_fields = TRUE;
1995 size = mono_type_size (field->type, &align);
1996 field->offset = class->sizes.class_size;
1997 /*align is always non-zero here*/
1998 field->offset += align - 1;
1999 field->offset &= ~(align - 1);
2000 class->sizes.class_size = field->offset + size;
2003 if (has_static_fields && class->sizes.class_size == 0)
2004 /* Simplify code which depends on class_size != 0 if the class has static fields */
2005 class->sizes.class_size = 8;
2008 static MonoMethod*
2009 create_array_method (MonoClass *class, const char *name, MonoMethodSignature *sig)
2011 MonoMethod *method;
2013 method = (MonoMethod *) mono_image_alloc0 (class->image, sizeof (MonoMethodPInvoke));
2014 method->klass = class;
2015 method->flags = METHOD_ATTRIBUTE_PUBLIC;
2016 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
2017 method->signature = sig;
2018 method->name = name;
2019 method->slot = -1;
2020 /* .ctor */
2021 if (name [0] == '.') {
2022 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
2023 } else {
2024 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
2026 return method;
2030 * mono_class_setup_methods:
2031 * @class: a class
2033 * Initializes the 'methods' array in the klass.
2034 * Calling this method should be avoided if possible since it allocates a lot
2035 * of long-living MonoMethod structures.
2036 * Methods belonging to an interface are assigned a sequential slot starting
2037 * from 0.
2039 * On failure this function sets class->exception_type
2041 void
2042 mono_class_setup_methods (MonoClass *class)
2044 int i;
2045 MonoMethod **methods;
2047 if (class->methods)
2048 return;
2050 mono_loader_lock ();
2052 if (class->methods) {
2053 mono_loader_unlock ();
2054 return;
2057 if (class->generic_class) {
2058 MonoError error;
2059 MonoClass *gklass = class->generic_class->container_class;
2061 mono_class_init (gklass);
2062 if (!gklass->exception_type)
2063 mono_class_setup_methods (gklass);
2064 if (gklass->exception_type) {
2065 /*FIXME make exception_data less opaque so it's possible to dup it here*/
2066 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2067 mono_loader_unlock ();
2068 return;
2071 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
2072 class->method.count = gklass->method.count;
2073 methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * (class->method.count + 1));
2075 for (i = 0; i < class->method.count; i++) {
2076 methods [i] = mono_class_inflate_generic_method_full_checked (
2077 gklass->methods [i], class, mono_class_get_context (class), &error);
2078 if (!mono_error_ok (&error)) {
2079 char *method = mono_method_full_name (gklass->methods [i], TRUE);
2080 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)));
2082 g_free (method);
2083 mono_error_cleanup (&error);
2084 mono_loader_unlock ();
2085 return;
2088 } else if (class->rank) {
2089 MonoError error;
2090 MonoMethod *amethod;
2091 MonoMethodSignature *sig;
2092 int count_generic = 0, first_generic = 0;
2093 int method_num = 0;
2095 class->method.count = 3 + (class->rank > 1? 2: 1);
2097 mono_class_setup_interfaces (class, &error);
2098 g_assert (mono_error_ok (&error)); /*FIXME can this fail for array types?*/
2100 if (class->interface_count) {
2101 count_generic = generic_array_methods (class);
2102 first_generic = class->method.count;
2103 class->method.count += class->interface_count * count_generic;
2106 methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * class->method.count);
2108 sig = mono_metadata_signature_alloc (class->image, class->rank);
2109 sig->ret = &mono_defaults.void_class->byval_arg;
2110 sig->pinvoke = TRUE;
2111 sig->hasthis = TRUE;
2112 for (i = 0; i < class->rank; ++i)
2113 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2115 amethod = create_array_method (class, ".ctor", sig);
2116 methods [method_num++] = amethod;
2117 if (class->rank > 1) {
2118 sig = mono_metadata_signature_alloc (class->image, class->rank * 2);
2119 sig->ret = &mono_defaults.void_class->byval_arg;
2120 sig->pinvoke = TRUE;
2121 sig->hasthis = TRUE;
2122 for (i = 0; i < class->rank * 2; ++i)
2123 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2125 amethod = create_array_method (class, ".ctor", sig);
2126 methods [method_num++] = amethod;
2128 /* element Get (idx11, [idx2, ...]) */
2129 sig = mono_metadata_signature_alloc (class->image, class->rank);
2130 sig->ret = &class->element_class->byval_arg;
2131 sig->pinvoke = TRUE;
2132 sig->hasthis = TRUE;
2133 for (i = 0; i < class->rank; ++i)
2134 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2135 amethod = create_array_method (class, "Get", sig);
2136 methods [method_num++] = amethod;
2137 /* element& Address (idx11, [idx2, ...]) */
2138 sig = mono_metadata_signature_alloc (class->image, class->rank);
2139 sig->ret = &class->element_class->this_arg;
2140 sig->pinvoke = TRUE;
2141 sig->hasthis = TRUE;
2142 for (i = 0; i < class->rank; ++i)
2143 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2144 amethod = create_array_method (class, "Address", sig);
2145 methods [method_num++] = amethod;
2146 /* void Set (idx11, [idx2, ...], element) */
2147 sig = mono_metadata_signature_alloc (class->image, class->rank + 1);
2148 sig->ret = &mono_defaults.void_class->byval_arg;
2149 sig->pinvoke = TRUE;
2150 sig->hasthis = TRUE;
2151 for (i = 0; i < class->rank; ++i)
2152 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2153 sig->params [i] = &class->element_class->byval_arg;
2154 amethod = create_array_method (class, "Set", sig);
2155 methods [method_num++] = amethod;
2157 for (i = 0; i < class->interface_count; i++)
2158 setup_generic_array_ifaces (class, class->interfaces [i], methods, first_generic + i * count_generic);
2159 } else {
2160 methods = mono_class_alloc (class, sizeof (MonoMethod*) * class->method.count);
2161 for (i = 0; i < class->method.count; ++i) {
2162 int idx = mono_metadata_translate_token_index (class->image, MONO_TABLE_METHOD, class->method.first + i + 1);
2163 methods [i] = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | idx, class);
2167 if (MONO_CLASS_IS_INTERFACE (class)) {
2168 int slot = 0;
2169 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
2170 for (i = 0; i < class->method.count; ++i) {
2171 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
2172 methods [i]->slot = slot++;
2176 /* Needed because of the double-checking locking pattern */
2177 mono_memory_barrier ();
2179 class->methods = methods;
2181 mono_loader_unlock ();
2185 * mono_class_get_method_by_index:
2187 * Returns class->methods [index], initializing class->methods if neccesary.
2189 * LOCKING: Acquires the loader lock.
2191 MonoMethod*
2192 mono_class_get_method_by_index (MonoClass *class, int index)
2194 /* Avoid calling setup_methods () if possible */
2195 if (class->generic_class && !class->methods) {
2196 MonoClass *gklass = class->generic_class->container_class;
2197 MonoMethod *m;
2199 m = mono_class_inflate_generic_method_full (
2200 gklass->methods [index], class, mono_class_get_context (class));
2202 * If setup_methods () is called later for this class, no duplicates are created,
2203 * since inflate_generic_method guarantees that only one instance of a method
2204 * is created for each context.
2207 mono_class_setup_methods (class);
2208 g_assert (m == class->methods [index]);
2210 return m;
2211 } else {
2212 mono_class_setup_methods (class);
2213 if (class->exception_type) /*FIXME do proper error handling*/
2214 return NULL;
2215 g_assert (index >= 0 && index < class->method.count);
2216 return class->methods [index];
2221 * mono_class_get_inflated_method:
2223 * Given an inflated class CLASS and a method METHOD which should be a method of
2224 * CLASS's generic definition, return the inflated method corresponding to METHOD.
2226 MonoMethod*
2227 mono_class_get_inflated_method (MonoClass *class, MonoMethod *method)
2229 MonoClass *gklass = class->generic_class->container_class;
2230 int i;
2232 g_assert (method->klass == gklass);
2234 mono_class_setup_methods (gklass);
2235 g_assert (!gklass->exception_type); /*FIXME do proper error handling*/
2237 for (i = 0; i < gklass->method.count; ++i) {
2238 if (gklass->methods [i] == method) {
2239 if (class->methods)
2240 return class->methods [i];
2241 else
2242 return mono_class_inflate_generic_method_full (gklass->methods [i], class, mono_class_get_context (class));
2246 return NULL;
2250 * mono_class_get_vtable_entry:
2252 * Returns class->vtable [offset], computing it if neccesary. Returns NULL on failure.
2253 * LOCKING: Acquires the loader lock.
2255 MonoMethod*
2256 mono_class_get_vtable_entry (MonoClass *class, int offset)
2258 MonoMethod *m;
2260 if (class->rank == 1) {
2262 * szarrays do not overwrite any methods of Array, so we can avoid
2263 * initializing their vtables in some cases.
2265 mono_class_setup_vtable (class->parent);
2266 if (offset < class->parent->vtable_size)
2267 return class->parent->vtable [offset];
2270 if (class->generic_class) {
2271 MonoClass *gklass = class->generic_class->container_class;
2272 mono_class_setup_vtable (gklass);
2273 m = gklass->vtable [offset];
2275 m = mono_class_inflate_generic_method_full (m, class, mono_class_get_context (class));
2276 } else {
2277 mono_class_setup_vtable (class);
2278 if (class->exception_type)
2279 return NULL;
2280 m = class->vtable [offset];
2283 return m;
2287 * mono_class_get_vtable_size:
2289 * Return the vtable size for KLASS.
2292 mono_class_get_vtable_size (MonoClass *klass)
2294 mono_class_setup_vtable (klass);
2296 return klass->vtable_size;
2299 /*This method can fail the class.*/
2300 static void
2301 mono_class_setup_properties (MonoClass *class)
2303 guint startm, endm, i, j;
2304 guint32 cols [MONO_PROPERTY_SIZE];
2305 MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS];
2306 MonoProperty *properties;
2307 guint32 last;
2309 if (class->ext && class->ext->properties)
2310 return;
2312 mono_loader_lock ();
2314 if (class->ext && class->ext->properties) {
2315 mono_loader_unlock ();
2316 return;
2319 mono_class_alloc_ext (class);
2321 if (class->generic_class) {
2322 MonoClass *gklass = class->generic_class->container_class;
2324 mono_class_init (gklass);
2325 mono_class_setup_properties (gklass);
2326 if (gklass->exception_type) {
2327 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2328 mono_loader_unlock ();
2329 return;
2332 class->ext->property = gklass->ext->property;
2334 properties = mono_class_new0 (class, MonoProperty, class->ext->property.count + 1);
2336 for (i = 0; i < class->ext->property.count; i++) {
2337 MonoProperty *prop = &properties [i];
2339 *prop = gklass->ext->properties [i];
2341 if (prop->get)
2342 prop->get = mono_class_inflate_generic_method_full (
2343 prop->get, class, mono_class_get_context (class));
2344 if (prop->set)
2345 prop->set = mono_class_inflate_generic_method_full (
2346 prop->set, class, mono_class_get_context (class));
2348 prop->parent = class;
2350 } else {
2351 int first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
2352 int count = last - first;
2354 if (count) {
2355 mono_class_setup_methods (class);
2356 if (class->exception_type) {
2357 mono_loader_unlock ();
2358 return;
2362 class->ext->property.first = first;
2363 class->ext->property.count = count;
2364 properties = mono_class_alloc0 (class, sizeof (MonoProperty) * count);
2365 for (i = first; i < last; ++i) {
2366 mono_metadata_decode_table_row (class->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
2367 properties [i - first].parent = class;
2368 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
2369 properties [i - first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]);
2371 startm = mono_metadata_methods_from_property (class->image, i, &endm);
2372 for (j = startm; j < endm; ++j) {
2373 MonoMethod *method;
2375 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2377 if (class->image->uncompressed_metadata)
2378 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2379 method = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class);
2380 else
2381 method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
2383 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2384 case METHOD_SEMANTIC_SETTER:
2385 properties [i - first].set = method;
2386 break;
2387 case METHOD_SEMANTIC_GETTER:
2388 properties [i - first].get = method;
2389 break;
2390 default:
2391 break;
2396 /*Flush any pending writes as we do double checked locking on class->properties */
2397 mono_memory_barrier ();
2399 /* Leave this assignment as the last op in the function */
2400 class->ext->properties = properties;
2402 mono_loader_unlock ();
2405 static MonoMethod**
2406 inflate_method_listz (MonoMethod **methods, MonoClass *class, MonoGenericContext *context)
2408 MonoMethod **om, **retval;
2409 int count;
2411 for (om = methods, count = 0; *om; ++om, ++count)
2414 retval = g_new0 (MonoMethod*, count + 1);
2415 count = 0;
2416 for (om = methods, count = 0; *om; ++om, ++count)
2417 retval [count] = mono_class_inflate_generic_method_full (*om, class, context);
2419 return retval;
2422 /*This method can fail the class.*/
2423 static void
2424 mono_class_setup_events (MonoClass *class)
2426 int first, count;
2427 guint startm, endm, i, j;
2428 guint32 cols [MONO_EVENT_SIZE];
2429 MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS];
2430 guint32 last;
2431 MonoEvent *events;
2433 if (class->ext && class->ext->events)
2434 return;
2436 mono_loader_lock ();
2438 if (class->ext && class->ext->events) {
2439 mono_loader_unlock ();
2440 return;
2443 mono_class_alloc_ext (class);
2445 if (class->generic_class) {
2446 MonoClass *gklass = class->generic_class->container_class;
2447 MonoGenericContext *context;
2449 mono_class_setup_events (gklass);
2450 if (gklass->exception_type) {
2451 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2452 mono_loader_unlock ();
2453 return;
2456 class->ext->event = gklass->ext->event;
2457 class->ext->events = mono_class_new0 (class, MonoEvent, class->ext->event.count);
2459 if (class->ext->event.count)
2460 context = mono_class_get_context (class);
2462 for (i = 0; i < class->ext->event.count; i++) {
2463 MonoEvent *event = &class->ext->events [i];
2464 MonoEvent *gevent = &gklass->ext->events [i];
2466 event->parent = class;
2467 event->name = gevent->name;
2468 event->add = gevent->add ? mono_class_inflate_generic_method_full (gevent->add, class, context) : NULL;
2469 event->remove = gevent->remove ? mono_class_inflate_generic_method_full (gevent->remove, class, context) : NULL;
2470 event->raise = gevent->raise ? mono_class_inflate_generic_method_full (gevent->raise, class, context) : NULL;
2471 #ifndef MONO_SMALL_CONFIG
2472 event->other = gevent->other ? inflate_method_listz (gevent->other, class, context) : NULL;
2473 #endif
2474 event->attrs = gevent->attrs;
2477 mono_loader_unlock ();
2478 return;
2481 first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
2482 count = last - first;
2484 if (count) {
2485 mono_class_setup_methods (class);
2486 if (class->exception_type) {
2487 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2488 mono_loader_unlock ();
2489 return;
2492 class->ext->event.first = first;
2493 class->ext->event.count = count;
2494 events = mono_class_alloc0 (class, sizeof (MonoEvent) * class->ext->event.count);
2495 for (i = first; i < last; ++i) {
2496 MonoEvent *event = &events [i - first];
2498 mono_metadata_decode_table_row (class->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
2499 event->parent = class;
2500 event->attrs = cols [MONO_EVENT_FLAGS];
2501 event->name = mono_metadata_string_heap (class->image, cols [MONO_EVENT_NAME]);
2503 startm = mono_metadata_methods_from_event (class->image, i, &endm);
2504 for (j = startm; j < endm; ++j) {
2505 MonoMethod *method;
2507 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2509 if (class->image->uncompressed_metadata)
2510 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2511 method = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class);
2512 else
2513 method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
2515 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2516 case METHOD_SEMANTIC_ADD_ON:
2517 event->add = method;
2518 break;
2519 case METHOD_SEMANTIC_REMOVE_ON:
2520 event->remove = method;
2521 break;
2522 case METHOD_SEMANTIC_FIRE:
2523 event->raise = method;
2524 break;
2525 case METHOD_SEMANTIC_OTHER: {
2526 #ifndef MONO_SMALL_CONFIG
2527 int n = 0;
2529 if (event->other == NULL) {
2530 event->other = g_new0 (MonoMethod*, 2);
2531 } else {
2532 while (event->other [n])
2533 n++;
2534 event->other = g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
2536 event->other [n] = method;
2537 /* NULL terminated */
2538 event->other [n + 1] = NULL;
2539 #endif
2540 break;
2542 default:
2543 break;
2547 /*Flush any pending writes as we do double checked locking on class->properties */
2548 mono_memory_barrier ();
2550 /* Leave this assignment as the last op in the function */
2551 class->ext->events = events;
2553 mono_loader_unlock ();
2557 * Global pool of interface IDs, represented as a bitset.
2558 * LOCKING: this is supposed to be accessed with the loader lock held.
2560 static MonoBitSet *global_interface_bitset = NULL;
2563 * mono_unload_interface_ids:
2564 * @bitset: bit set of interface IDs
2566 * When an image is unloaded, the interface IDs associated with
2567 * the image are put back in the global pool of IDs so the numbers
2568 * can be reused.
2570 void
2571 mono_unload_interface_ids (MonoBitSet *bitset)
2573 mono_loader_lock ();
2574 mono_bitset_sub (global_interface_bitset, bitset);
2575 mono_loader_unlock ();
2578 void
2579 mono_unload_interface_id (MonoClass *class)
2581 if (global_interface_bitset && class->interface_id) {
2582 mono_loader_lock ();
2583 mono_bitset_clear (global_interface_bitset, class->interface_id);
2584 mono_loader_unlock ();
2589 * mono_get_unique_iid:
2590 * @class: interface
2592 * Assign a unique integer ID to the interface represented by @class.
2593 * The ID will positive and as small as possible.
2594 * LOCKING: this is supposed to be called with the loader lock held.
2595 * Returns: the new ID.
2597 static guint
2598 mono_get_unique_iid (MonoClass *class)
2600 int iid;
2602 g_assert (MONO_CLASS_IS_INTERFACE (class));
2604 if (!global_interface_bitset) {
2605 global_interface_bitset = mono_bitset_new (128, 0);
2608 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
2609 if (iid < 0) {
2610 int old_size = mono_bitset_size (global_interface_bitset);
2611 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
2612 mono_bitset_free (global_interface_bitset);
2613 global_interface_bitset = new_set;
2614 iid = old_size;
2616 mono_bitset_set (global_interface_bitset, iid);
2617 /* set the bit also in the per-image set */
2618 if (!class->generic_class) {
2619 if (class->image->interface_bitset) {
2620 if (iid >= mono_bitset_size (class->image->interface_bitset)) {
2621 MonoBitSet *new_set = mono_bitset_clone (class->image->interface_bitset, iid + 1);
2622 mono_bitset_free (class->image->interface_bitset);
2623 class->image->interface_bitset = new_set;
2625 } else {
2626 class->image->interface_bitset = mono_bitset_new (iid + 1, 0);
2628 mono_bitset_set (class->image->interface_bitset, iid);
2631 #ifndef MONO_SMALL_CONFIG
2632 if (mono_print_vtable) {
2633 int generic_id;
2634 char *type_name = mono_type_full_name (&class->byval_arg);
2635 if (class->generic_class && !class->generic_class->context.class_inst->is_open) {
2636 generic_id = class->generic_class->context.class_inst->id;
2637 g_assert (generic_id != 0);
2638 } else {
2639 generic_id = 0;
2641 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, class->image->name, type_name, generic_id);
2642 g_free (type_name);
2644 #endif
2646 g_assert (iid <= 65535);
2647 return iid;
2650 static void
2651 collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, MonoError *error)
2653 int i;
2654 MonoClass *ic;
2656 mono_class_setup_interfaces (klass, error);
2657 if (!mono_error_ok (error))
2658 return;
2660 for (i = 0; i < klass->interface_count; i++) {
2661 ic = klass->interfaces [i];
2663 if (*res == NULL)
2664 *res = g_ptr_array_new ();
2665 g_ptr_array_add (*res, ic);
2666 mono_class_init (ic);
2667 if (ic->exception_type) {
2668 mono_error_set_type_load_class (error, ic, "Error Loading class");
2669 return;
2672 collect_implemented_interfaces_aux (ic, res, error);
2673 if (!mono_error_ok (error))
2674 return;
2678 GPtrArray*
2679 mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error)
2681 GPtrArray *res = NULL;
2683 collect_implemented_interfaces_aux (klass, &res, error);
2684 if (!mono_error_ok (error)) {
2685 if (res)
2686 g_ptr_array_free (res, TRUE);
2687 return NULL;
2689 return res;
2692 static int
2693 compare_interface_ids (const void *p_key, const void *p_element) {
2694 const MonoClass *key = p_key;
2695 const MonoClass *element = *(MonoClass**) p_element;
2697 return (key->interface_id - element->interface_id);
2700 /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/
2702 mono_class_interface_offset (MonoClass *klass, MonoClass *itf) {
2703 MonoClass **result = mono_binary_search (
2704 itf,
2705 klass->interfaces_packed,
2706 klass->interface_offsets_count,
2707 sizeof (MonoClass *),
2708 compare_interface_ids);
2709 if (result) {
2710 return klass->interface_offsets_packed [result - (klass->interfaces_packed)];
2711 } else {
2712 return -1;
2717 * mono_class_interface_offset_with_variance:
2719 * Return the interface offset of @itf in @klass. Sets @non_exact_match to TRUE if the match required variance check
2720 * If @itf is an interface with generic variant arguments, try to find the compatible one.
2722 * Note that this function is responsible for resolving ambiguities. Right now we use whatever ordering interfaces_packed gives us.
2724 * FIXME figure out MS disambiguation rules and fix this function.
2727 mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match) {
2728 int i = mono_class_interface_offset (klass, itf);
2729 *non_exact_match = FALSE;
2730 if (i >= 0)
2731 return i;
2733 if (!mono_class_has_variant_generic_params (itf))
2734 return -1;
2736 for (i = 0; i < klass->interface_offsets_count; i++) {
2737 if (mono_class_is_variant_compatible (itf, klass->interfaces_packed [i], FALSE)) {
2738 *non_exact_match = TRUE;
2739 return klass->interface_offsets_packed [i];
2743 return -1;
2746 static void
2747 print_implemented_interfaces (MonoClass *klass) {
2748 char *name;
2749 MonoError error;
2750 GPtrArray *ifaces = NULL;
2751 int i;
2752 int ancestor_level = 0;
2754 name = mono_type_get_full_name (klass);
2755 printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
2756 g_free (name);
2758 for (i = 0; i < klass->interface_offsets_count; i++)
2759 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
2760 klass->interfaces_packed [i]->interface_id,
2761 klass->interface_offsets_packed [i],
2762 klass->interfaces_packed [i]->method.count,
2763 klass->interfaces_packed [i]->name_space,
2764 klass->interfaces_packed [i]->name );
2765 printf ("Interface flags: ");
2766 for (i = 0; i <= klass->max_interface_id; i++)
2767 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
2768 printf ("(%d,T)", i);
2769 else
2770 printf ("(%d,F)", i);
2771 printf ("\n");
2772 printf ("Dump interface flags:");
2773 #ifdef COMPRESSED_INTERFACE_BITMAP
2775 const uint8_t* p = klass->interface_bitmap;
2776 i = klass->max_interface_id;
2777 while (i > 0) {
2778 printf (" %d x 00 %02X", p [0], p [1]);
2779 i -= p [0] * 8;
2780 i -= 8;
2783 #else
2784 for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
2785 printf (" %02X", klass->interface_bitmap [i]);
2786 #endif
2787 printf ("\n");
2788 while (klass != NULL) {
2789 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
2790 ifaces = mono_class_get_implemented_interfaces (klass, &error);
2791 if (!mono_error_ok (&error)) {
2792 printf (" Type failed due to %s\n", mono_error_get_message (&error));
2793 mono_error_cleanup (&error);
2794 } else if (ifaces) {
2795 for (i = 0; i < ifaces->len; i++) {
2796 MonoClass *ic = g_ptr_array_index (ifaces, i);
2797 printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
2798 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
2799 ic->interface_id,
2800 mono_class_interface_offset (klass, ic),
2801 ic->method.count,
2802 ic->name_space,
2803 ic->name );
2805 g_ptr_array_free (ifaces, TRUE);
2807 ancestor_level ++;
2808 klass = klass->parent;
2812 static MonoClass*
2813 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
2815 MonoType *args [1];
2816 args [0] = &arg0->byval_arg;
2818 return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
2821 static MonoClass*
2822 array_class_get_if_rank (MonoClass *class, guint rank)
2824 return rank ? mono_array_class_get (class, rank) : class;
2827 static void
2828 fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *eclass, int rank)
2830 valuetype_types [0] = eclass;
2831 if (eclass == mono_defaults.int16_class)
2832 valuetype_types [1] = mono_defaults.uint16_class;
2833 else if (eclass == mono_defaults.uint16_class)
2834 valuetype_types [1] = mono_defaults.int16_class;
2835 else if (eclass == mono_defaults.int32_class)
2836 valuetype_types [1] = mono_defaults.uint32_class;
2837 else if (eclass == mono_defaults.uint32_class)
2838 valuetype_types [1] = mono_defaults.int32_class;
2839 else if (eclass == mono_defaults.int64_class)
2840 valuetype_types [1] = mono_defaults.uint64_class;
2841 else if (eclass == mono_defaults.uint64_class)
2842 valuetype_types [1] = mono_defaults.int64_class;
2843 else if (eclass == mono_defaults.byte_class)
2844 valuetype_types [1] = mono_defaults.sbyte_class;
2845 else if (eclass == mono_defaults.sbyte_class)
2846 valuetype_types [1] = mono_defaults.byte_class;
2847 else if (eclass->enumtype && mono_class_enum_basetype (eclass))
2848 valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass));
2851 /* this won't be needed once bug #325495 is completely fixed
2852 * though we'll need something similar to know which interfaces to allow
2853 * in arrays when they'll be lazyly created
2855 * FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
2856 * MS returns diferrent types based on which instance is called. For example:
2857 * object obj = new byte[10][];
2858 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
2859 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
2860 * a != b ==> true
2862 * Fixing this should kill quite some code, save some bits and improve compatibility.
2864 static MonoClass**
2865 get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enumerator)
2867 MonoClass *eclass = class->element_class;
2868 static MonoClass* generic_icollection_class = NULL;
2869 static MonoClass* generic_ienumerable_class = NULL;
2870 static MonoClass* generic_ienumerator_class = NULL;
2871 static MonoClass* generic_ireadonlylist_class = NULL;
2872 static MonoClass* generic_ireadonlycollection_class = NULL;
2873 MonoClass *valuetype_types[2] = { NULL, NULL };
2874 MonoClass **interfaces = NULL;
2875 int i, nifaces, interface_count, real_count, original_rank;
2876 int all_interfaces;
2877 gboolean internal_enumerator;
2878 gboolean eclass_is_valuetype;
2880 if (!mono_defaults.generic_ilist_class) {
2881 *num = 0;
2882 return NULL;
2884 internal_enumerator = FALSE;
2885 eclass_is_valuetype = FALSE;
2886 original_rank = eclass->rank;
2887 if (class->byval_arg.type != MONO_TYPE_SZARRAY) {
2888 if (class->generic_class && class->nested_in == mono_defaults.array_class && strcmp (class->name, "InternalEnumerator`1") == 0) {
2890 * For a Enumerator<T[]> we need to get the list of interfaces for T.
2892 eclass = mono_class_from_mono_type (class->generic_class->context.class_inst->type_argv [0]);
2893 original_rank = eclass->rank;
2894 if (!eclass->rank)
2895 eclass = eclass->element_class;
2896 internal_enumerator = TRUE;
2897 *is_enumerator = TRUE;
2898 } else {
2899 *num = 0;
2900 return NULL;
2905 * with this non-lazy impl we can't implement all the interfaces so we do just the minimal stuff
2906 * for deep levels of arrays of arrays (string[][] has all the interfaces, string[][][] doesn't)
2908 all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
2910 if (!generic_icollection_class) {
2911 generic_icollection_class = mono_class_from_name (mono_defaults.corlib,
2912 "System.Collections.Generic", "ICollection`1");
2913 generic_ienumerable_class = mono_class_from_name (mono_defaults.corlib,
2914 "System.Collections.Generic", "IEnumerable`1");
2915 generic_ienumerator_class = mono_class_from_name (mono_defaults.corlib,
2916 "System.Collections.Generic", "IEnumerator`1");
2917 generic_ireadonlylist_class = mono_class_from_name (mono_defaults.corlib,
2918 "System.Collections.Generic", "IReadOnlyList`1");
2919 generic_ireadonlycollection_class = mono_class_from_name (mono_defaults.corlib,
2920 "System.Collections.Generic", "IReadOnlyCollection`1");
2923 mono_class_init (eclass);
2926 * Arrays in 2.0 need to implement a number of generic interfaces
2927 * (IList`1, ICollection`1, IEnumerable`1 for a number of types depending
2928 * on the element class). For net 4.5, we also need to implement IReadOnlyList`1/IReadOnlyCollection`1.
2929 * We collect the types needed to build the
2930 * instantiations in interfaces at intervals of 3/5, because 3/5 are
2931 * the generic interfaces needed to implement.
2933 * On 4.5, as an optimization, we don't expand ref classes for the variant generic interfaces
2934 * (IEnumerator, IReadOnlyList and IReadOnlyColleciton). The regular dispatch code can handle those cases.
2936 if (eclass->valuetype) {
2937 nifaces = generic_ireadonlylist_class ? 5 : 3;
2938 fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank);
2940 /* IList, ICollection, IEnumerable, IReadOnlyList`1 */
2941 real_count = interface_count = valuetype_types [1] ? (nifaces * 2) : nifaces;
2942 if (internal_enumerator) {
2943 ++real_count;
2944 if (valuetype_types [1])
2945 ++real_count;
2948 interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
2949 interfaces [0] = valuetype_types [0];
2950 if (valuetype_types [1])
2951 interfaces [nifaces] = valuetype_types [1];
2953 eclass_is_valuetype = TRUE;
2954 } else {
2955 int j;
2956 int idepth = eclass->idepth;
2957 if (!internal_enumerator)
2958 idepth--;
2959 nifaces = generic_ireadonlylist_class ? 2 : 3;
2961 // FIXME: This doesn't seem to work/required for generic params
2962 if (!(eclass->this_arg.type == MONO_TYPE_VAR || eclass->this_arg.type == MONO_TYPE_MVAR || (eclass->image->dynamic && !eclass->wastypebuilder)))
2963 mono_class_setup_interface_offsets (eclass);
2965 interface_count = all_interfaces? eclass->interface_offsets_count: eclass->interface_count;
2966 /* we add object for interfaces and the supertypes for the other
2967 * types. The last of the supertypes is the element class itself which we
2968 * already created the explicit interfaces for (so we include it for IEnumerator
2969 * and exclude it for arrays).
2971 if (MONO_CLASS_IS_INTERFACE (eclass))
2972 interface_count++;
2973 else
2974 interface_count += idepth;
2975 if (eclass->rank && eclass->element_class->valuetype) {
2976 fill_valuetype_array_derived_types (valuetype_types, eclass->element_class, original_rank);
2977 if (valuetype_types [1])
2978 ++interface_count;
2980 /* IList, ICollection, IEnumerable, IReadOnlyList */
2981 interface_count *= nifaces;
2982 real_count = interface_count;
2983 if (internal_enumerator) {
2984 real_count += (MONO_CLASS_IS_INTERFACE (eclass) ? 1 : idepth) + eclass->interface_offsets_count;
2985 if (valuetype_types [1])
2986 ++real_count;
2988 interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
2989 if (MONO_CLASS_IS_INTERFACE (eclass)) {
2990 interfaces [0] = mono_defaults.object_class;
2991 j = nifaces;
2992 } else {
2993 j = 0;
2994 for (i = 0; i < idepth; i++) {
2995 mono_class_init (eclass->supertypes [i]);
2996 interfaces [j] = eclass->supertypes [i];
2997 j += nifaces;
3000 if (all_interfaces) {
3001 for (i = 0; i < eclass->interface_offsets_count; i++) {
3002 interfaces [j] = eclass->interfaces_packed [i];
3003 j += nifaces;
3005 } else {
3006 for (i = 0; i < eclass->interface_count; i++) {
3007 interfaces [j] = eclass->interfaces [i];
3008 j += nifaces;
3011 if (valuetype_types [1]) {
3012 interfaces [j] = array_class_get_if_rank (valuetype_types [1], original_rank);
3013 j += nifaces;
3017 /* instantiate the generic interfaces */
3018 for (i = 0; i < interface_count; i += nifaces) {
3019 MonoClass *iface = interfaces [i];
3021 interfaces [i + 0] = inflate_class_one_arg (mono_defaults.generic_ilist_class, iface);
3022 interfaces [i + 1] = inflate_class_one_arg (generic_icollection_class, iface);
3024 if (eclass->valuetype) {
3025 interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
3026 if (generic_ireadonlylist_class) {
3027 interfaces [i + 3] = inflate_class_one_arg (generic_ireadonlylist_class, iface);
3028 interfaces [i + 4] = inflate_class_one_arg (generic_ireadonlycollection_class, iface);
3030 } else {
3031 if (!generic_ireadonlylist_class)
3032 interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
3035 if (internal_enumerator) {
3036 int j;
3037 /* instantiate IEnumerator<iface> */
3038 for (i = 0; i < interface_count; i++) {
3039 interfaces [i] = inflate_class_one_arg (generic_ienumerator_class, interfaces [i]);
3041 j = interface_count;
3042 if (!eclass_is_valuetype) {
3043 if (MONO_CLASS_IS_INTERFACE (eclass)) {
3044 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, mono_defaults.object_class);
3045 j ++;
3046 } else {
3047 for (i = 0; i < eclass->idepth; i++) {
3048 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->supertypes [i]);
3049 j ++;
3052 for (i = 0; i < eclass->interface_offsets_count; i++) {
3053 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->interfaces_packed [i]);
3054 j ++;
3056 } else {
3057 interfaces [j++] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [0], original_rank));
3059 if (valuetype_types [1])
3060 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [1], original_rank));
3062 #if 0
3064 char *type_name = mono_type_get_name_full (&class->byval_arg, 0);
3065 for (i = 0; i < real_count; ++i) {
3066 char *name = mono_type_get_name_full (&interfaces [i]->byval_arg, 0);
3067 g_print ("%s implements %s\n", type_name, name);
3068 g_free (name);
3070 g_free (type_name);
3072 #endif
3073 *num = real_count;
3074 return interfaces;
3077 static int
3078 find_array_interface (MonoClass *klass, const char *name)
3080 int i;
3081 for (i = 0; i < klass->interface_count; ++i) {
3082 if (strcmp (klass->interfaces [i]->name, name) == 0)
3083 return i;
3085 return -1;
3089 * Return the number of virtual methods.
3090 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
3091 * Return -1 on failure.
3092 * FIXME It would be nice if this information could be cached somewhere.
3094 static int
3095 count_virtual_methods (MonoClass *class)
3097 int i, count = 0;
3098 guint32 flags;
3099 class = mono_class_get_generic_type_definition (class); /*We can find this information by looking at the GTD*/
3101 if (class->methods || !MONO_CLASS_HAS_STATIC_METADATA (class)) {
3102 mono_class_setup_methods (class);
3103 if (class->exception_type)
3104 return -1;
3106 for (i = 0; i < class->method.count; ++i) {
3107 flags = class->methods [i]->flags;
3108 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3109 ++count;
3111 } else {
3112 for (i = 0; i < class->method.count; ++i) {
3113 flags = mono_metadata_decode_table_row_col (class->image, MONO_TABLE_METHOD, class->method.first + i, MONO_METHOD_FLAGS);
3115 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3116 ++count;
3119 return count;
3122 static int
3123 find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic)
3125 int m, l = 0;
3126 if (!num_ifaces)
3127 return -1;
3128 while (1) {
3129 if (l > num_ifaces)
3130 return -1;
3131 m = (l + num_ifaces) / 2;
3132 if (interfaces_full [m] == ic)
3133 return m;
3134 if (l == num_ifaces)
3135 return -1;
3136 if (!interfaces_full [m] || interfaces_full [m]->interface_id > ic->interface_id) {
3137 num_ifaces = m - 1;
3138 } else {
3139 l = m + 1;
3144 static int
3145 find_interface_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic)
3147 int i = find_interface (num_ifaces, interfaces_full, ic);
3148 if (ic >= 0)
3149 return interface_offsets_full [i];
3150 return -1;
3153 static mono_bool
3154 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
3156 int i = find_interface (num_ifaces, interfaces_full, ic);
3157 if (i >= 0) {
3158 if (!force_set)
3159 return TRUE;
3160 interface_offsets_full [i] = offset;
3161 return FALSE;
3163 for (i = 0; i < num_ifaces; ++i) {
3164 if (interfaces_full [i]) {
3165 int end;
3166 if (interfaces_full [i]->interface_id < ic->interface_id)
3167 continue;
3168 end = i + 1;
3169 while (end < num_ifaces && interfaces_full [end]) end++;
3170 memmove (interfaces_full + i + 1, interfaces_full + i, sizeof (MonoClass*) * (end - i));
3171 memmove (interface_offsets_full + i + 1, interface_offsets_full + i, sizeof (int) * (end - i));
3173 interfaces_full [i] = ic;
3174 interface_offsets_full [i] = offset;
3175 break;
3177 return FALSE;
3180 #ifdef COMPRESSED_INTERFACE_BITMAP
3183 * Compressed interface bitmap design.
3185 * Interface bitmaps take a large amount of memory, because their size is
3186 * linear with the maximum interface id assigned in the process (each interface
3187 * is assigned a unique id as it is loaded). The number of interface classes
3188 * is high because of the many implicit interfaces implemented by arrays (we'll
3189 * need to lazy-load them in the future).
3190 * Most classes implement a very small number of interfaces, so the bitmap is
3191 * sparse. This bitmap needs to be checked by interface casts, so access to the
3192 * needed bit must be fast and doable with few jit instructions.
3194 * The current compression format is as follows:
3195 * *) it is a sequence of one or more two-byte elements
3196 * *) the first byte in the element is the count of empty bitmap bytes
3197 * at the current bitmap position
3198 * *) the second byte in the element is an actual bitmap byte at the current
3199 * bitmap position
3201 * As an example, the following compressed bitmap bytes:
3202 * 0x07 0x01 0x00 0x7
3203 * correspond to the following bitmap:
3204 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
3206 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
3207 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
3208 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
3212 * mono_compress_bitmap:
3213 * @dest: destination buffer
3214 * @bitmap: bitmap buffer
3215 * @size: size of @bitmap in bytes
3217 * This is a mono internal function.
3218 * The @bitmap data is compressed into a format that is small but
3219 * still searchable in few instructions by the JIT and runtime.
3220 * The compressed data is stored in the buffer pointed to by the
3221 * @dest array. Passing a #NULL value for @dest allows to just compute
3222 * the size of the buffer.
3223 * This compression algorithm assumes the bits set in the bitmap are
3224 * few and far between, like in interface bitmaps.
3225 * Returns: the size of the compressed bitmap in bytes.
3228 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
3230 int numz = 0;
3231 int res = 0;
3232 const uint8_t *end = bitmap + size;
3233 while (bitmap < end) {
3234 if (*bitmap || numz == 255) {
3235 if (dest) {
3236 *dest++ = numz;
3237 *dest++ = *bitmap;
3239 res += 2;
3240 numz = 0;
3241 bitmap++;
3242 continue;
3244 bitmap++;
3245 numz++;
3247 if (numz) {
3248 res += 2;
3249 if (dest) {
3250 *dest++ = numz;
3251 *dest++ = 0;
3254 return res;
3258 * mono_class_interface_match:
3259 * @bitmap: a compressed bitmap buffer
3260 * @id: the index to check in the bitmap
3262 * This is a mono internal function.
3263 * Checks if a bit is set in a compressed interface bitmap. @id must
3264 * be already checked for being smaller than the maximum id encoded in the
3265 * bitmap.
3267 * Returns: a non-zero value if bit @id is set in the bitmap @bitmap,
3268 * #FALSE otherwise.
3271 mono_class_interface_match (const uint8_t *bitmap, int id)
3273 while (TRUE) {
3274 id -= bitmap [0] * 8;
3275 if (id < 8) {
3276 if (id < 0)
3277 return 0;
3278 return bitmap [1] & (1 << id);
3280 bitmap += 2;
3281 id -= 8;
3284 #endif
3287 * LOCKING: this is supposed to be called with the loader lock held.
3288 * Return -1 on failure and set exception_type
3290 static int
3291 setup_interface_offsets (MonoClass *class, int cur_slot, gboolean overwrite)
3293 MonoError error;
3294 MonoClass *k, *ic;
3295 int i, j, max_iid, num_ifaces;
3296 MonoClass **interfaces_full = NULL;
3297 int *interface_offsets_full = NULL;
3298 GPtrArray *ifaces;
3299 GPtrArray **ifaces_array = NULL;
3300 int interface_offsets_count;
3301 MonoClass **array_interfaces = NULL;
3302 int num_array_interfaces;
3303 int is_enumerator = FALSE;
3305 mono_class_setup_supertypes (class);
3307 * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator<T>
3308 * implicit interfaces have the property that they are assigned the same slot in the
3309 * vtables for compatible interfaces
3311 array_interfaces = get_implicit_generic_array_interfaces (class, &num_array_interfaces, &is_enumerator);
3313 /* compute maximum number of slots and maximum interface id */
3314 max_iid = 0;
3315 num_ifaces = num_array_interfaces; /* this can include duplicated ones */
3316 ifaces_array = g_new0 (GPtrArray *, class->idepth);
3317 for (j = 0; j < class->idepth; j++) {
3318 k = class->supertypes [j];
3319 num_ifaces += k->interface_count;
3320 for (i = 0; i < k->interface_count; i++) {
3321 ic = k->interfaces [i];
3323 if (!ic->inited)
3324 mono_class_init (ic);
3326 if (max_iid < ic->interface_id)
3327 max_iid = ic->interface_id;
3329 ifaces = mono_class_get_implemented_interfaces (k, &error);
3330 if (!mono_error_ok (&error)) {
3331 char *name = mono_type_get_full_name (k);
3332 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)));
3333 g_free (name);
3334 mono_error_cleanup (&error);
3335 cur_slot = -1;
3336 goto end;
3338 if (ifaces) {
3339 num_ifaces += ifaces->len;
3340 for (i = 0; i < ifaces->len; ++i) {
3341 ic = g_ptr_array_index (ifaces, i);
3342 if (max_iid < ic->interface_id)
3343 max_iid = ic->interface_id;
3345 ifaces_array [j] = ifaces;
3349 for (i = 0; i < num_array_interfaces; ++i) {
3350 ic = array_interfaces [i];
3351 mono_class_init (ic);
3352 if (max_iid < ic->interface_id)
3353 max_iid = ic->interface_id;
3356 if (MONO_CLASS_IS_INTERFACE (class)) {
3357 num_ifaces++;
3358 if (max_iid < class->interface_id)
3359 max_iid = class->interface_id;
3361 class->max_interface_id = max_iid;
3362 /* compute vtable offset for interfaces */
3363 interfaces_full = g_malloc0 (sizeof (MonoClass*) * num_ifaces);
3364 interface_offsets_full = g_malloc (sizeof (int) * num_ifaces);
3366 for (i = 0; i < num_ifaces; i++) {
3367 interface_offsets_full [i] = -1;
3370 /* skip the current class */
3371 for (j = 0; j < class->idepth - 1; j++) {
3372 k = class->supertypes [j];
3373 ifaces = ifaces_array [j];
3375 if (ifaces) {
3376 for (i = 0; i < ifaces->len; ++i) {
3377 int io;
3378 ic = g_ptr_array_index (ifaces, i);
3380 /*Force the sharing of interface offsets between parent and subtypes.*/
3381 io = mono_class_interface_offset (k, ic);
3382 g_assert (io >= 0);
3383 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
3388 g_assert (class == class->supertypes [class->idepth - 1]);
3389 ifaces = ifaces_array [class->idepth - 1];
3390 if (ifaces) {
3391 for (i = 0; i < ifaces->len; ++i) {
3392 int count;
3393 ic = g_ptr_array_index (ifaces, i);
3394 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
3395 continue;
3396 count = count_virtual_methods (ic);
3397 if (count == -1) {
3398 char *name = mono_type_get_full_name (ic);
3399 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error calculating interface offset of %s", name));
3400 g_free (name);
3401 cur_slot = -1;
3402 goto end;
3404 cur_slot += count;
3408 if (MONO_CLASS_IS_INTERFACE (class))
3409 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, class, cur_slot, TRUE);
3411 if (num_array_interfaces) {
3412 if (is_enumerator) {
3413 int ienumerator_idx = find_array_interface (class, "IEnumerator`1");
3414 int ienumerator_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, class->interfaces [ienumerator_idx]);
3415 g_assert (ienumerator_offset >= 0);
3416 for (i = 0; i < num_array_interfaces; ++i) {
3417 ic = array_interfaces [i];
3418 if (strcmp (ic->name, "IEnumerator`1") == 0)
3419 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, ienumerator_offset, TRUE);
3420 else
3421 g_assert_not_reached ();
3422 /*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);*/
3424 } else {
3425 int ilist_offset, icollection_offset, ienumerable_offset, ireadonlylist_offset, ireadonlycollection_offset;
3426 int ilist_iface_idx = find_array_interface (class, "IList`1");
3427 MonoClass* ilist_class = class->interfaces [ilist_iface_idx];
3428 int ireadonlylist_iface_idx = find_array_interface (class, "IReadOnlyList`1");
3429 MonoClass* ireadonlylist_class = ireadonlylist_iface_idx != -1 ? class->interfaces [ireadonlylist_iface_idx] : NULL;
3430 int icollection_iface_idx = find_array_interface (ilist_class, "ICollection`1");
3431 int ienumerable_iface_idx = find_array_interface (ilist_class, "IEnumerable`1");
3432 int ireadonlycollection_iface_idx = ireadonlylist_iface_idx != -1 ? find_array_interface (ireadonlylist_class, "IReadOnlyCollection`1") : -1;
3433 ilist_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, class->interfaces [ilist_iface_idx]);
3434 icollection_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [icollection_iface_idx]);
3435 ienumerable_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [ienumerable_iface_idx]);
3436 ireadonlylist_offset = ireadonlylist_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, class->interfaces [ireadonlylist_iface_idx]) : -1;
3437 ireadonlycollection_offset = ireadonlycollection_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ireadonlylist_class->interfaces [ireadonlycollection_iface_idx]) : -1;
3438 g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0);
3439 for (i = 0; i < num_array_interfaces; ++i) {
3440 int offset;
3441 ic = array_interfaces [i];
3442 if (ic->generic_class->container_class == mono_defaults.generic_ilist_class)
3443 offset = ilist_offset;
3444 else if (strcmp (ic->name, "ICollection`1") == 0)
3445 offset = icollection_offset;
3446 else if (strcmp (ic->name, "IEnumerable`1") == 0)
3447 offset = ienumerable_offset;
3448 else if (strcmp (ic->name, "IReadOnlyList`1") == 0)
3449 offset = ireadonlylist_offset;
3450 else if (strcmp (ic->name, "IReadOnlyCollection`1") == 0)
3451 offset = ireadonlycollection_offset;
3452 else
3453 g_assert_not_reached ();
3454 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, offset, TRUE);
3455 /*g_print ("type %s has %s offset at %d (%s)\n", class->name, ic->name, offset, class->interfaces [0]->name);*/
3460 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
3461 if (interface_offsets_full [i] != -1) {
3462 interface_offsets_count ++;
3467 * We might get called multiple times:
3468 * - mono_class_init ()
3469 * - mono_class_setup_vtable ().
3470 * - mono_class_setup_interface_offsets ().
3471 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
3472 * means we have to overwrite those when called from other places (#4440).
3474 if (class->interfaces_packed && !overwrite) {
3475 g_assert (class->interface_offsets_count == interface_offsets_count);
3476 } else {
3477 uint8_t *bitmap;
3478 int bsize;
3479 class->interface_offsets_count = interface_offsets_count;
3480 class->interfaces_packed = mono_class_alloc (class, sizeof (MonoClass*) * interface_offsets_count);
3481 class->interface_offsets_packed = mono_class_alloc (class, sizeof (guint16) * interface_offsets_count);
3482 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
3483 #ifdef COMPRESSED_INTERFACE_BITMAP
3484 bitmap = g_malloc0 (bsize);
3485 #else
3486 bitmap = mono_class_alloc0 (class, bsize);
3487 #endif
3488 for (i = 0; i < interface_offsets_count; i++) {
3489 int id = interfaces_full [i]->interface_id;
3490 bitmap [id >> 3] |= (1 << (id & 7));
3491 class->interfaces_packed [i] = interfaces_full [i];
3492 class->interface_offsets_packed [i] = interface_offsets_full [i];
3493 /*if (num_array_interfaces)
3494 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]);*/
3496 #ifdef COMPRESSED_INTERFACE_BITMAP
3497 i = mono_compress_bitmap (NULL, bitmap, bsize);
3498 class->interface_bitmap = mono_class_alloc0 (class, i);
3499 mono_compress_bitmap (class->interface_bitmap, bitmap, bsize);
3500 g_free (bitmap);
3501 #else
3502 class->interface_bitmap = bitmap;
3503 #endif
3506 end:
3507 g_free (interfaces_full);
3508 g_free (interface_offsets_full);
3509 g_free (array_interfaces);
3510 for (i = 0; i < class->idepth; i++) {
3511 ifaces = ifaces_array [i];
3512 if (ifaces)
3513 g_ptr_array_free (ifaces, TRUE);
3515 g_free (ifaces_array);
3517 //printf ("JUST DONE: ");
3518 //print_implemented_interfaces (class);
3520 return cur_slot;
3524 * Setup interface offsets for interfaces.
3525 * Initializes:
3526 * - class->max_interface_id
3527 * - class->interface_offsets_count
3528 * - class->interfaces_packed
3529 * - class->interface_offsets_packed
3530 * - class->interface_bitmap
3532 * This function can fail @class.
3534 void
3535 mono_class_setup_interface_offsets (MonoClass *class)
3537 mono_loader_lock ();
3539 setup_interface_offsets (class, 0, FALSE);
3541 mono_loader_unlock ();
3544 /*Checks if @klass has @parent as one of it's parents type gtd
3546 * For example:
3547 * Foo<T>
3548 * Bar<T> : Foo<Bar<Bar<T>>>
3551 static gboolean
3552 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
3554 klass = mono_class_get_generic_type_definition (klass);
3555 parent = mono_class_get_generic_type_definition (parent);
3556 mono_class_setup_supertypes (klass);
3557 mono_class_setup_supertypes (parent);
3559 return klass->idepth >= parent->idepth &&
3560 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
3563 gboolean
3564 mono_class_check_vtable_constraints (MonoClass *class, GList *in_setup)
3566 MonoGenericInst *ginst;
3567 int i;
3568 if (!class->generic_class) {
3569 mono_class_setup_vtable_full (class, in_setup);
3570 return class->exception_type == 0;
3573 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (class), in_setup);
3574 if (class->generic_class->container_class->exception_type) {
3575 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to load generic definition vtable"));
3576 return FALSE;
3579 ginst = class->generic_class->context.class_inst;
3580 for (i = 0; i < ginst->type_argc; ++i) {
3581 MonoClass *arg;
3582 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
3583 continue;
3584 arg = mono_class_from_mono_type (ginst->type_argv [i]);
3585 /*Those 2 will be checked by mono_class_setup_vtable itself*/
3586 if (mono_class_has_gtd_parent (class, arg) || mono_class_has_gtd_parent (arg, class))
3587 continue;
3588 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
3589 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Failed to load generic parameter %d", i));
3590 return FALSE;
3593 return TRUE;
3597 * mono_class_setup_vtable:
3599 * Creates the generic vtable of CLASS.
3600 * Initializes the following fields in MonoClass:
3601 * - vtable
3602 * - vtable_size
3603 * Plus all the fields initialized by setup_interface_offsets ().
3604 * If there is an error during vtable construction, class->exception_type is set.
3606 * LOCKING: Acquires the loader lock.
3608 void
3609 mono_class_setup_vtable (MonoClass *class)
3611 mono_class_setup_vtable_full (class, NULL);
3614 static void
3615 mono_class_setup_vtable_full (MonoClass *class, GList *in_setup)
3617 MonoMethod **overrides;
3618 MonoGenericContext *context;
3619 guint32 type_token;
3620 int onum = 0;
3621 gboolean ok = TRUE;
3623 if (class->vtable)
3624 return;
3626 if (MONO_CLASS_IS_INTERFACE (class)) {
3627 /* This sets method->slot for all methods if this is an interface */
3628 mono_class_setup_methods (class);
3629 return;
3632 if (class->exception_type)
3633 return;
3635 if (g_list_find (in_setup, class))
3636 return;
3638 mono_loader_lock ();
3640 if (class->vtable) {
3641 mono_loader_unlock ();
3642 return;
3645 mono_stats.generic_vtable_count ++;
3646 in_setup = g_list_prepend (in_setup, class);
3648 if (class->generic_class) {
3649 if (!mono_class_check_vtable_constraints (class, in_setup)) {
3650 mono_loader_unlock ();
3651 g_list_remove (in_setup, class);
3652 return;
3655 context = mono_class_get_context (class);
3656 type_token = class->generic_class->container_class->type_token;
3657 } else {
3658 context = (MonoGenericContext *) class->generic_container;
3659 type_token = class->type_token;
3662 if (class->image->dynamic) {
3663 /* Generic instances can have zero method overrides without causing any harm.
3664 * This is true since we don't do layout all over again for them, we simply inflate
3665 * the layout of the parent.
3667 mono_reflection_get_dynamic_overrides (class, &overrides, &onum);
3668 } else {
3669 /* The following call fails if there are missing methods in the type */
3670 /* FIXME it's probably a good idea to avoid this for generic instances. */
3671 ok = mono_class_get_overrides_full (class->image, type_token, &overrides, &onum, context);
3674 if (ok)
3675 mono_class_setup_vtable_general (class, overrides, onum, in_setup);
3676 else
3677 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not load list of method overrides"));
3679 g_free (overrides);
3681 mono_loader_unlock ();
3682 g_list_remove (in_setup, class);
3684 return;
3687 #define DEBUG_INTERFACE_VTABLE_CODE 0
3688 #define TRACE_INTERFACE_VTABLE_CODE 0
3689 #define VERIFY_INTERFACE_VTABLE_CODE 0
3690 #define VTABLE_SELECTOR (1)
3692 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3693 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
3694 if (!(VTABLE_SELECTOR)) break; \
3695 stmt;\
3696 } while (0)
3697 #else
3698 #define DEBUG_INTERFACE_VTABLE(stmt)
3699 #endif
3701 #if TRACE_INTERFACE_VTABLE_CODE
3702 #define TRACE_INTERFACE_VTABLE(stmt) do {\
3703 if (!(VTABLE_SELECTOR)) break; \
3704 stmt;\
3705 } while (0)
3706 #else
3707 #define TRACE_INTERFACE_VTABLE(stmt)
3708 #endif
3710 #if VERIFY_INTERFACE_VTABLE_CODE
3711 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
3712 if (!(VTABLE_SELECTOR)) break; \
3713 stmt;\
3714 } while (0)
3715 #else
3716 #define VERIFY_INTERFACE_VTABLE(stmt)
3717 #endif
3720 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3721 static char*
3722 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
3724 int i;
3725 char *result;
3726 GString *res = g_string_new ("");
3728 g_string_append_c (res, '(');
3729 for (i = 0; i < sig->param_count; ++i) {
3730 if (i > 0)
3731 g_string_append_c (res, ',');
3732 mono_type_get_desc (res, sig->params [i], include_namespace);
3734 g_string_append (res, ")=>");
3735 if (sig->ret != NULL) {
3736 mono_type_get_desc (res, sig->ret, include_namespace);
3737 } else {
3738 g_string_append (res, "NULL");
3740 result = res->str;
3741 g_string_free (res, FALSE);
3742 return result;
3744 static void
3745 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
3746 char *im_sig = mono_signature_get_full_desc (mono_method_signature (im), TRUE);
3747 char *cm_sig = mono_signature_get_full_desc (mono_method_signature (cm), TRUE);
3748 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
3749 g_free (im_sig);
3750 g_free (cm_sig);
3754 #endif
3755 static gboolean
3756 is_wcf_hack_disabled (void)
3758 static gboolean disabled;
3759 static gboolean inited = FALSE;
3760 if (!inited) {
3761 disabled = g_getenv ("MONO_DISABLE_WCF_HACK") != NULL;
3762 inited = TRUE;
3764 return disabled;
3767 static gboolean
3768 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) {
3769 MonoMethodSignature *cmsig, *imsig;
3770 if (strcmp (im->name, cm->name) == 0) {
3771 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
3772 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
3773 return FALSE;
3775 if (! slot_is_empty) {
3776 if (require_newslot) {
3777 if (! interface_is_explicitly_implemented_by_class) {
3778 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
3779 return FALSE;
3781 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
3782 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
3783 return FALSE;
3785 } else {
3786 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
3789 cmsig = mono_method_signature (cm);
3790 imsig = mono_method_signature (im);
3791 if (!cmsig || !imsig) {
3792 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
3793 return FALSE;
3796 if (! mono_metadata_signature_equal (cmsig, imsig)) {
3797 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
3798 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
3799 TRACE_INTERFACE_VTABLE (printf ("]"));
3800 return FALSE;
3802 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
3803 /* CAS - SecurityAction.InheritanceDemand on interface */
3804 if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
3805 mono_secman_inheritancedemand_method (cm, im);
3808 if (mono_security_core_clr_enabled ())
3809 mono_security_core_clr_check_override (class, cm, im);
3811 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
3812 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
3813 char *body_name = mono_method_full_name (cm, TRUE);
3814 char *decl_name = mono_method_full_name (im, TRUE);
3815 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));
3816 g_free (body_name);
3817 g_free (decl_name);
3818 return FALSE;
3821 return TRUE;
3822 } else {
3823 MonoClass *ic = im->klass;
3824 const char *ic_name_space = ic->name_space;
3825 const char *ic_name = ic->name;
3826 char *subname;
3828 if (! require_newslot) {
3829 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
3830 return FALSE;
3832 if (cm->klass->rank == 0) {
3833 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
3834 return FALSE;
3836 cmsig = mono_method_signature (cm);
3837 imsig = mono_method_signature (im);
3838 if (!cmsig || !imsig) {
3839 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
3840 return FALSE;
3843 if (! mono_metadata_signature_equal (cmsig, imsig)) {
3844 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
3845 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
3846 TRACE_INTERFACE_VTABLE (printf ("]"));
3847 return FALSE;
3849 if (mono_class_get_image (ic) != mono_defaults.corlib) {
3850 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
3851 return FALSE;
3853 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
3854 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
3855 return FALSE;
3857 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))) {
3858 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
3859 return FALSE;
3862 subname = strstr (cm->name, ic_name_space);
3863 if (subname != cm->name) {
3864 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
3865 return FALSE;
3867 subname += strlen (ic_name_space);
3868 if (subname [0] != '.') {
3869 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
3870 return FALSE;
3872 subname ++;
3873 if (strstr (subname, ic_name) != subname) {
3874 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
3875 return FALSE;
3877 subname += strlen (ic_name);
3878 if (subname [0] != '.') {
3879 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
3880 return FALSE;
3882 subname ++;
3883 if (strcmp (subname, im->name) != 0) {
3884 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
3885 return FALSE;
3888 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
3889 /* CAS - SecurityAction.InheritanceDemand on interface */
3890 if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
3891 mono_secman_inheritancedemand_method (cm, im);
3894 if (mono_security_core_clr_enabled ())
3895 mono_security_core_clr_check_override (class, cm, im);
3897 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
3898 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
3899 char *body_name = mono_method_full_name (cm, TRUE);
3900 char *decl_name = mono_method_full_name (im, TRUE);
3901 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));
3902 g_free (body_name);
3903 g_free (decl_name);
3904 return FALSE;
3907 return TRUE;
3911 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3912 static void
3913 foreach_override (gpointer key, gpointer value, gpointer user_data) {
3914 MonoMethod *method = key;
3915 MonoMethod *override = value;
3916 MonoClass *method_class = mono_method_get_class (method);
3917 MonoClass *override_class = mono_method_get_class (override);
3919 printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
3920 mono_class_get_namespace (method_class), mono_class_get_name (method_class), mono_method_get_name (method),
3921 mono_class_get_namespace (override_class), mono_class_get_name (override_class), mono_method_get_name (override));
3923 static void
3924 print_overrides (GHashTable *override_map, const char *message) {
3925 if (override_map) {
3926 printf ("Override map \"%s\" START:\n", message);
3927 g_hash_table_foreach (override_map, foreach_override, NULL);
3928 printf ("Override map \"%s\" END.\n", message);
3929 } else {
3930 printf ("Override map \"%s\" EMPTY.\n", message);
3933 static void
3934 print_vtable_full (MonoClass *class, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
3935 char *full_name = mono_type_full_name (&class->byval_arg);
3936 int i;
3937 int parent_size;
3939 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
3941 if (print_interfaces) {
3942 print_implemented_interfaces (class);
3943 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
3946 if (class->parent) {
3947 parent_size = class->parent->vtable_size;
3948 } else {
3949 parent_size = 0;
3951 for (i = 0; i < size; ++i) {
3952 MonoMethod *cm = vtable [i];
3953 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
3954 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
3956 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
3957 g_free (cm_name);
3960 g_free (full_name);
3962 #endif
3964 #if VERIFY_INTERFACE_VTABLE_CODE
3965 static int
3966 mono_method_try_get_vtable_index (MonoMethod *method)
3968 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
3969 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
3970 if (imethod->declaring->is_generic)
3971 return imethod->declaring->slot;
3973 return method->slot;
3976 static void
3977 mono_class_verify_vtable (MonoClass *class)
3979 int i;
3980 char *full_name = mono_type_full_name (&class->byval_arg);
3982 printf ("*** Verifying VTable of class '%s' \n", full_name);
3983 g_free (full_name);
3984 full_name = NULL;
3986 if (!class->methods)
3987 return;
3989 for (i = 0; i < class->method.count; ++i) {
3990 MonoMethod *cm = class->methods [i];
3991 int slot;
3993 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
3994 continue;
3996 g_free (full_name);
3997 full_name = mono_method_full_name (cm, TRUE);
3999 slot = mono_method_try_get_vtable_index (cm);
4000 if (slot >= 0) {
4001 if (slot >= class->vtable_size) {
4002 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, class->vtable_size);
4003 continue;
4006 if (slot >= 0 && class->vtable [slot] != cm && (class->vtable [slot])) {
4007 char *other_name = class->vtable [slot] ? mono_method_full_name (class->vtable [slot], TRUE) : g_strdup ("[null value]");
4008 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
4009 g_free (other_name);
4011 } else
4012 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
4014 g_free (full_name);
4016 #endif
4018 static void
4019 print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) {
4020 int index;
4021 char *method_signature;
4022 char *type_name;
4024 for (index = 0; index < onum; ++index) {
4025 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name,
4026 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
4028 method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
4029 type_name = mono_type_full_name (&class->byval_arg);
4030 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s\n",
4031 mono_type_get_name (&ic->byval_arg), im->name, method_signature, type_name);
4032 g_free (method_signature);
4033 g_free (type_name);
4034 mono_class_setup_methods (class);
4035 if (class->exception_type) {
4036 char *name = mono_type_get_full_name (class);
4037 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods\n", name);
4038 g_free (name);
4039 return;
4041 for (index = 0; index < class->method.count; ++index) {
4042 MonoMethod *cm = class->methods [index];
4043 method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
4045 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)\n", cm->name, method_signature);
4046 g_free (method_signature);
4050 static MonoMethod*
4051 mono_method_get_method_definition (MonoMethod *method)
4053 while (method->is_inflated)
4054 method = ((MonoMethodInflated*)method)->declaring;
4055 return method;
4058 static gboolean
4059 verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum)
4061 int i;
4063 for (i = 0; i < onum; ++i) {
4064 MonoMethod *decl = overrides [i * 2];
4065 MonoMethod *body = overrides [i * 2 + 1];
4067 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (class)) {
4068 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method belongs to a different class than the declared one"));
4069 return FALSE;
4072 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
4073 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4074 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must not be static to override a base type"));
4075 else
4076 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must be virtual to override a base type"));
4077 return FALSE;
4080 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
4081 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4082 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type"));
4083 else
4084 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type"));
4085 return FALSE;
4088 if (!mono_class_is_assignable_from_slow (decl->klass, class)) {
4089 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that extended or implemented by this type"));
4090 return FALSE;
4093 body = mono_method_get_method_definition (body);
4094 decl = mono_method_get_method_definition (decl);
4096 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
4097 char *body_name = mono_method_full_name (body, TRUE);
4098 char *decl_name = mono_method_full_name (decl, TRUE);
4099 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));
4100 g_free (body_name);
4101 g_free (decl_name);
4102 return FALSE;
4105 return TRUE;
4108 static gboolean
4109 mono_class_need_stelemref_method (MonoClass *class)
4111 return class->rank == 1 && MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg);
4115 * LOCKING: this is supposed to be called with the loader lock held.
4117 void
4118 mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int onum, GList *in_setup)
4120 MonoError error;
4121 MonoClass *k, *ic;
4122 MonoMethod **vtable;
4123 int i, max_vtsize = 0, max_iid, cur_slot = 0;
4124 GPtrArray *ifaces = NULL;
4125 GHashTable *override_map = NULL;
4126 gboolean security_enabled = mono_security_enabled ();
4127 MonoMethod *cm;
4128 gpointer class_iter;
4129 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
4130 int first_non_interface_slot;
4131 #endif
4132 GSList *virt_methods = NULL, *l;
4133 int stelemref_slot = 0;
4135 if (class->vtable)
4136 return;
4138 if (overrides && !verify_class_overrides (class, overrides, onum))
4139 return;
4141 ifaces = mono_class_get_implemented_interfaces (class, &error);
4142 if (!mono_error_ok (&error)) {
4143 char *name = mono_type_get_full_name (class);
4144 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)));
4145 g_free (name);
4146 mono_error_cleanup (&error);
4147 return;
4148 } else if (ifaces) {
4149 for (i = 0; i < ifaces->len; i++) {
4150 MonoClass *ic = g_ptr_array_index (ifaces, i);
4151 max_vtsize += ic->method.count;
4153 g_ptr_array_free (ifaces, TRUE);
4154 ifaces = NULL;
4157 if (class->parent) {
4158 mono_class_init (class->parent);
4159 mono_class_setup_vtable_full (class->parent, in_setup);
4161 if (class->parent->exception_type) {
4162 char *name = mono_type_get_full_name (class->parent);
4163 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Parent %s failed to load", name));
4164 g_free (name);
4165 return;
4168 max_vtsize += class->parent->vtable_size;
4169 cur_slot = class->parent->vtable_size;
4172 max_vtsize += class->method.count;
4174 /*Array have a slot for stelemref*/
4175 if (mono_class_need_stelemref_method (class)) {
4176 stelemref_slot = cur_slot;
4177 ++max_vtsize;
4178 ++cur_slot;
4181 vtable = alloca (sizeof (gpointer) * max_vtsize);
4182 memset (vtable, 0, sizeof (gpointer) * max_vtsize);
4184 /* printf ("METAINIT %s.%s\n", class->name_space, class->name); */
4186 cur_slot = setup_interface_offsets (class, cur_slot, TRUE);
4187 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
4188 return;
4190 max_iid = class->max_interface_id;
4191 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
4193 /* Optimized version for generic instances */
4194 if (class->generic_class) {
4195 MonoError error;
4196 MonoClass *gklass = class->generic_class->container_class;
4197 MonoMethod **tmp;
4199 mono_class_setup_vtable_full (gklass, in_setup);
4200 if (gklass->exception_type != MONO_EXCEPTION_NONE) {
4201 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
4202 return;
4205 tmp = mono_class_alloc0 (class, sizeof (gpointer) * gklass->vtable_size);
4206 class->vtable_size = gklass->vtable_size;
4207 for (i = 0; i < gklass->vtable_size; ++i)
4208 if (gklass->vtable [i]) {
4209 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], class, mono_class_get_context (class), &error);
4210 if (!mono_error_ok (&error)) {
4211 char *err_msg = g_strdup_printf ("Could not inflate method due to %s", mono_error_get_message (&error));
4212 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
4213 g_free (err_msg);
4214 mono_error_cleanup (&error);
4215 return;
4217 tmp [i] = inflated;
4218 tmp [i]->slot = gklass->vtable [i]->slot;
4220 mono_memory_barrier ();
4221 class->vtable = tmp;
4223 /* Have to set method->slot for abstract virtual methods */
4224 if (class->methods && gklass->methods) {
4225 for (i = 0; i < class->method.count; ++i)
4226 if (class->methods [i]->slot == -1)
4227 class->methods [i]->slot = gklass->methods [i]->slot;
4230 return;
4233 if (class->parent && class->parent->vtable_size) {
4234 MonoClass *parent = class->parent;
4235 int i;
4237 memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
4239 // Also inherit parent interface vtables, just as a starting point.
4240 // This is needed otherwise bug-77127.exe fails when the property methods
4241 // have different names in the iterface and the class, because for child
4242 // classes the ".override" information is not used anymore.
4243 for (i = 0; i < parent->interface_offsets_count; i++) {
4244 MonoClass *parent_interface = parent->interfaces_packed [i];
4245 int interface_offset = mono_class_interface_offset (class, parent_interface);
4246 /*FIXME this is now dead code as this condition will never hold true.
4247 Since interface offsets are inherited then the offset of an interface implemented
4248 by a parent will never be the out of it's vtable boundary.
4250 if (interface_offset >= parent->vtable_size) {
4251 int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
4252 int j;
4254 mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
4255 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
4256 for (j = 0; j < parent_interface->method.count && !class->exception_type; j++) {
4257 vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
4258 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
4259 parent_interface_offset + j, parent_interface_offset, j,
4260 interface_offset + j, interface_offset, j));
4267 /*Array have a slot for stelemref*/
4268 if (mono_class_need_stelemref_method (class)) {
4269 MonoMethod *method = mono_marshal_get_virtual_stelemref (class);
4270 if (!method->slot)
4271 method->slot = stelemref_slot;
4272 else
4273 g_assert (method->slot == stelemref_slot);
4275 vtable [stelemref_slot] = method;
4278 TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
4279 /* override interface methods */
4280 for (i = 0; i < onum; i++) {
4281 MonoMethod *decl = overrides [i*2];
4282 if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
4283 int dslot;
4284 dslot = mono_method_get_vtable_slot (decl);
4285 if (dslot == -1) {
4286 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
4287 return;
4290 dslot += mono_class_interface_offset (class, decl->klass);
4291 vtable [dslot] = overrides [i*2 + 1];
4292 vtable [dslot]->slot = dslot;
4293 if (!override_map)
4294 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4296 g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
4298 if (mono_security_core_clr_enabled ())
4299 mono_security_core_clr_check_override (class, vtable [dslot], decl);
4302 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
4303 TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
4306 * Create a list of virtual methods to avoid calling
4307 * mono_class_get_virtual_methods () which is slow because of the metadata
4308 * optimization.
4311 gpointer iter = NULL;
4312 MonoMethod *cm;
4314 virt_methods = NULL;
4315 while ((cm = mono_class_get_virtual_methods (class, &iter))) {
4316 virt_methods = g_slist_prepend (virt_methods, cm);
4318 if (class->exception_type)
4319 goto fail;
4322 // Loop on all implemented interfaces...
4323 for (i = 0; i < class->interface_offsets_count; i++) {
4324 MonoClass *parent = class->parent;
4325 int ic_offset;
4326 gboolean interface_is_explicitly_implemented_by_class;
4327 int im_index;
4329 ic = class->interfaces_packed [i];
4330 ic_offset = mono_class_interface_offset (class, ic);
4332 mono_class_setup_methods (ic);
4333 if (ic->exception_type)
4334 goto fail;
4336 // Check if this interface is explicitly implemented (instead of just inherited)
4337 if (parent != NULL) {
4338 int implemented_interfaces_index;
4339 interface_is_explicitly_implemented_by_class = FALSE;
4340 for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) {
4341 if (ic == class->interfaces [implemented_interfaces_index]) {
4342 interface_is_explicitly_implemented_by_class = TRUE;
4343 break;
4346 } else {
4347 interface_is_explicitly_implemented_by_class = TRUE;
4350 // Loop on all interface methods...
4351 for (im_index = 0; im_index < ic->method.count; im_index++) {
4352 MonoMethod *im = ic->methods [im_index];
4353 int im_slot = ic_offset + im->slot;
4354 MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL;
4356 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4357 continue;
4359 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
4361 // If there is an explicit implementation, just use it right away,
4362 // otherwise look for a matching method
4363 if (override_im == NULL) {
4364 int cm_index;
4365 gpointer iter;
4366 MonoMethod *cm;
4368 // First look for a suitable method among the class methods
4369 iter = NULL;
4370 for (l = virt_methods; l; l = l->next) {
4371 cm = l->data;
4372 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)));
4373 if (check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) {
4374 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
4375 vtable [im_slot] = cm;
4376 /* Why do we need this? */
4377 if (cm->slot < 0) {
4378 cm->slot = im_slot;
4381 TRACE_INTERFACE_VTABLE (printf ("\n"));
4382 if (class->exception_type) /*Might be set by check_interface_method_override*/
4383 goto fail;
4386 // If the slot is still empty, look in all the inherited virtual methods...
4387 if ((vtable [im_slot] == NULL) && class->parent != NULL) {
4388 MonoClass *parent = class->parent;
4389 // Reverse order, so that last added methods are preferred
4390 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
4391 MonoMethod *cm = parent->vtable [cm_index];
4393 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));
4394 if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) {
4395 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
4396 vtable [im_slot] = cm;
4397 /* Why do we need this? */
4398 if (cm->slot < 0) {
4399 cm->slot = im_slot;
4401 break;
4403 if (class->exception_type) /*Might be set by check_interface_method_override*/
4404 goto fail;
4405 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
4408 } else {
4409 g_assert (vtable [im_slot] == override_im);
4414 // If the class is not abstract, check that all its interface slots are full.
4415 // The check is done here and not directly at the end of the loop above because
4416 // it can happen (for injected generic array interfaces) that the same slot is
4417 // processed multiple times (those interfaces have overlapping slots), and it
4418 // will not always be the first pass the one that fills the slot.
4419 if (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
4420 for (i = 0; i < class->interface_offsets_count; i++) {
4421 int ic_offset;
4422 int im_index;
4424 ic = class->interfaces_packed [i];
4425 ic_offset = mono_class_interface_offset (class, ic);
4427 for (im_index = 0; im_index < ic->method.count; im_index++) {
4428 MonoMethod *im = ic->methods [im_index];
4429 int im_slot = ic_offset + im->slot;
4431 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4432 continue;
4434 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
4435 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
4436 if (vtable [im_slot] == NULL) {
4437 print_unimplemented_interface_method_info (class, ic, im, im_slot, overrides, onum);
4438 goto fail;
4444 TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
4445 class_iter = NULL;
4446 for (l = virt_methods; l; l = l->next) {
4447 cm = l->data;
4449 * If the method is REUSE_SLOT, we must check in the
4450 * base class for a method to override.
4452 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
4453 int slot = -1;
4454 for (k = class->parent; k ; k = k->parent) {
4455 gpointer k_iter;
4456 MonoMethod *m1;
4458 k_iter = NULL;
4459 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
4460 MonoMethodSignature *cmsig, *m1sig;
4462 cmsig = mono_method_signature (cm);
4463 m1sig = mono_method_signature (m1);
4465 if (!cmsig || !m1sig) {
4466 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
4467 return;
4470 if (!strcmp(cm->name, m1->name) &&
4471 mono_metadata_signature_equal (cmsig, m1sig)) {
4473 /* CAS - SecurityAction.InheritanceDemand */
4474 if (security_enabled && (m1->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
4475 mono_secman_inheritancedemand_method (cm, m1);
4478 if (mono_security_core_clr_enabled ())
4479 mono_security_core_clr_check_override (class, cm, m1);
4481 slot = mono_method_get_vtable_slot (m1);
4482 if (slot == -1)
4483 goto fail;
4485 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
4486 char *body_name = mono_method_full_name (cm, TRUE);
4487 char *decl_name = mono_method_full_name (m1, TRUE);
4488 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));
4489 g_free (body_name);
4490 g_free (decl_name);
4491 goto fail;
4494 g_assert (cm->slot < max_vtsize);
4495 if (!override_map)
4496 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4497 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
4498 mono_method_full_name (m1, 1), m1,
4499 mono_method_full_name (cm, 1), cm));
4500 g_hash_table_insert (override_map, m1, cm);
4501 break;
4504 if (k->exception_type)
4505 goto fail;
4507 if (slot >= 0)
4508 break;
4510 if (slot >= 0)
4511 cm->slot = slot;
4514 /*Non final newslot methods must be given a non-interface vtable slot*/
4515 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
4516 cm->slot = -1;
4518 if (cm->slot < 0)
4519 cm->slot = cur_slot++;
4521 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
4522 vtable [cm->slot] = cm;
4525 /* override non interface methods */
4526 for (i = 0; i < onum; i++) {
4527 MonoMethod *decl = overrides [i*2];
4528 if (!MONO_CLASS_IS_INTERFACE (decl->klass)) {
4529 g_assert (decl->slot != -1);
4530 vtable [decl->slot] = overrides [i*2 + 1];
4531 overrides [i * 2 + 1]->slot = decl->slot;
4532 if (!override_map)
4533 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4534 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
4535 mono_method_full_name (decl, 1), decl,
4536 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
4537 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
4539 if (mono_security_core_clr_enabled ())
4540 mono_security_core_clr_check_override (class, vtable [decl->slot], decl);
4545 * If a method occupies more than one place in the vtable, and it is
4546 * overriden, then change the other occurances too.
4548 if (override_map) {
4549 MonoMethod *cm;
4551 for (i = 0; i < max_vtsize; ++i)
4552 if (vtable [i]) {
4553 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
4555 cm = g_hash_table_lookup (override_map, vtable [i]);
4556 if (cm)
4557 vtable [i] = cm;
4560 g_hash_table_destroy (override_map);
4561 override_map = NULL;
4564 g_slist_free (virt_methods);
4565 virt_methods = NULL;
4567 /* Ensure that all vtable slots are filled with concrete instance methods */
4568 if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
4569 for (i = 0; i < cur_slot; ++i) {
4570 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
4571 char *type_name = mono_type_get_full_name (class);
4572 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
4573 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));
4574 g_free (type_name);
4575 g_free (method_name);
4576 return;
4581 if (class->generic_class) {
4582 MonoClass *gklass = class->generic_class->container_class;
4584 mono_class_init (gklass);
4586 class->vtable_size = MAX (gklass->vtable_size, cur_slot);
4587 } else {
4588 /* Check that the vtable_size value computed in mono_class_init () is correct */
4589 if (class->vtable_size)
4590 g_assert (cur_slot == class->vtable_size);
4591 class->vtable_size = cur_slot;
4594 /* Try to share the vtable with our parent. */
4595 if (class->parent && (class->parent->vtable_size == class->vtable_size) && (memcmp (class->parent->vtable, vtable, sizeof (gpointer) * class->vtable_size) == 0)) {
4596 mono_memory_barrier ();
4597 class->vtable = class->parent->vtable;
4598 } else {
4599 MonoMethod **tmp = mono_class_alloc0 (class, sizeof (gpointer) * class->vtable_size);
4600 memcpy (tmp, vtable, sizeof (gpointer) * class->vtable_size);
4601 mono_memory_barrier ();
4602 class->vtable = tmp;
4605 DEBUG_INTERFACE_VTABLE (print_vtable_full (class, class->vtable, class->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
4606 if (mono_print_vtable) {
4607 int icount = 0;
4609 print_implemented_interfaces (class);
4611 for (i = 0; i <= max_iid; i++)
4612 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, i))
4613 icount++;
4615 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&class->byval_arg),
4616 class->vtable_size, icount);
4618 for (i = 0; i < cur_slot; ++i) {
4619 MonoMethod *cm;
4621 cm = vtable [i];
4622 if (cm) {
4623 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
4624 mono_method_full_name (cm, TRUE));
4629 if (icount) {
4630 printf ("Interfaces %s.%s (max_iid = %d)\n", class->name_space,
4631 class->name, max_iid);
4633 for (i = 0; i < class->interface_count; i++) {
4634 ic = class->interfaces [i];
4635 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
4636 mono_class_interface_offset (class, ic),
4637 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4640 for (k = class->parent; k ; k = k->parent) {
4641 for (i = 0; i < k->interface_count; i++) {
4642 ic = k->interfaces [i];
4643 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
4644 mono_class_interface_offset (class, ic),
4645 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4651 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (class));
4652 return;
4654 fail:
4656 char *name = mono_type_get_full_name (class);
4657 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("VTable setup of type %s failed", name));
4658 g_free (name);
4659 if (override_map)
4660 g_hash_table_destroy (override_map);
4661 if (virt_methods)
4662 g_slist_free (virt_methods);
4667 * mono_method_get_vtable_slot:
4669 * Returns method->slot, computing it if neccesary. Return -1 on failure.
4670 * LOCKING: Acquires the loader lock.
4672 * FIXME Use proper MonoError machinery here.
4675 mono_method_get_vtable_slot (MonoMethod *method)
4677 if (method->slot == -1) {
4678 mono_class_setup_vtable (method->klass);
4679 if (method->klass->exception_type)
4680 return -1;
4681 if (method->slot == -1) {
4682 MonoClass *gklass;
4683 int i;
4685 /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
4686 g_assert (method->klass->generic_class);
4687 gklass = method->klass->generic_class->container_class;
4688 mono_class_setup_methods (method->klass);
4689 g_assert (method->klass->methods);
4690 for (i = 0; i < method->klass->method.count; ++i) {
4691 if (method->klass->methods [i] == method)
4692 break;
4694 g_assert (i < method->klass->method.count);
4695 g_assert (gklass->methods);
4696 method->slot = gklass->methods [i]->slot;
4698 g_assert (method->slot != -1);
4700 return method->slot;
4704 * mono_method_get_vtable_index:
4705 * @method: a method
4707 * Returns the index into the runtime vtable to access the method or,
4708 * in the case of a virtual generic method, the virtual generic method
4709 * thunk. Returns -1 on failure.
4711 * FIXME Use proper MonoError machinery here.
4714 mono_method_get_vtable_index (MonoMethod *method)
4716 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
4717 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
4718 if (imethod->declaring->is_generic)
4719 return mono_method_get_vtable_slot (imethod->declaring);
4721 return mono_method_get_vtable_slot (method);
4724 static MonoMethod *default_ghc = NULL;
4725 static MonoMethod *default_finalize = NULL;
4726 static int finalize_slot = -1;
4727 static int ghc_slot = -1;
4729 static void
4730 initialize_object_slots (MonoClass *class)
4732 int i;
4733 if (default_ghc)
4734 return;
4735 if (class == mono_defaults.object_class) {
4736 mono_class_setup_vtable (class);
4737 for (i = 0; i < class->vtable_size; ++i) {
4738 MonoMethod *cm = class->vtable [i];
4740 if (!strcmp (cm->name, "GetHashCode"))
4741 ghc_slot = i;
4742 else if (!strcmp (cm->name, "Finalize"))
4743 finalize_slot = i;
4746 g_assert (ghc_slot > 0);
4747 default_ghc = class->vtable [ghc_slot];
4749 g_assert (finalize_slot > 0);
4750 default_finalize = class->vtable [finalize_slot];
4754 typedef struct {
4755 MonoMethod *array_method;
4756 char *name;
4757 } GenericArrayMethodInfo;
4759 static int generic_array_method_num = 0;
4760 static GenericArrayMethodInfo *generic_array_method_info = NULL;
4762 static int
4763 generic_array_methods (MonoClass *class)
4765 int i, count_generic = 0;
4766 GList *list = NULL, *tmp;
4767 if (generic_array_method_num)
4768 return generic_array_method_num;
4769 mono_class_setup_methods (class->parent); /*This is setting up System.Array*/
4770 g_assert (!class->parent->exception_type); /*So hitting this assert is a huge problem*/
4771 for (i = 0; i < class->parent->method.count; i++) {
4772 MonoMethod *m = class->parent->methods [i];
4773 if (!strncmp (m->name, "InternalArray__", 15)) {
4774 count_generic++;
4775 list = g_list_prepend (list, m);
4778 list = g_list_reverse (list);
4779 generic_array_method_info = mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
4780 i = 0;
4781 for (tmp = list; tmp; tmp = tmp->next) {
4782 const char *mname, *iname;
4783 gchar *name;
4784 MonoMethod *m = tmp->data;
4785 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
4786 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
4788 generic_array_method_info [i].array_method = m;
4789 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
4790 iname = "System.Collections.Generic.ICollection`1.";
4791 mname = m->name + 27;
4792 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
4793 iname = "System.Collections.Generic.IEnumerable`1.";
4794 mname = m->name + 27;
4795 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
4796 iname = "System.Collections.Generic.IReadOnlyList`1.";
4797 mname = m->name + strlen (ireadonlylist_prefix);
4798 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
4799 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
4800 mname = m->name + strlen (ireadonlycollection_prefix);
4801 } else if (!strncmp (m->name, "InternalArray__", 15)) {
4802 iname = "System.Collections.Generic.IList`1.";
4803 mname = m->name + 15;
4804 } else {
4805 g_assert_not_reached ();
4808 name = mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
4809 strcpy (name, iname);
4810 strcpy (name + strlen (iname), mname);
4811 generic_array_method_info [i].name = name;
4812 i++;
4814 /*g_print ("array generic methods: %d\n", count_generic);*/
4816 generic_array_method_num = count_generic;
4817 g_list_free (list);
4818 return generic_array_method_num;
4821 static void
4822 setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos)
4824 MonoGenericContext tmp_context;
4825 int i;
4827 tmp_context.class_inst = NULL;
4828 tmp_context.method_inst = iface->generic_class->context.class_inst;
4829 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
4831 for (i = 0; i < generic_array_method_num; i++) {
4832 MonoMethod *m = generic_array_method_info [i].array_method;
4833 MonoMethod *inflated;
4835 inflated = mono_class_inflate_generic_method (m, &tmp_context);
4836 methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, generic_array_method_info [i].name, inflated);
4840 static char*
4841 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
4843 int null_length = strlen ("(null)");
4844 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
4845 char *s = mono_image_alloc (image, len);
4846 int result;
4848 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
4849 g_assert (result == len - 1);
4851 return s;
4854 static void
4855 set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error)
4857 gpointer exception_data = NULL;
4859 switch (error->exception_type) {
4860 case MONO_EXCEPTION_TYPE_LOAD:
4861 exception_data = concat_two_strings_with_zero (class->image, error->class_name, error->assembly_name);
4862 break;
4864 case MONO_EXCEPTION_MISSING_METHOD:
4865 exception_data = concat_two_strings_with_zero (class->image, error->class_name, error->member_name);
4866 break;
4868 case MONO_EXCEPTION_MISSING_FIELD: {
4869 const char *name_space = error->klass->name_space ? error->klass->name_space : NULL;
4870 const char *class_name;
4872 if (name_space)
4873 class_name = g_strdup_printf ("%s.%s", name_space, error->klass->name);
4874 else
4875 class_name = error->klass->name;
4877 exception_data = concat_two_strings_with_zero (class->image, class_name, error->member_name);
4879 if (name_space)
4880 g_free ((void*)class_name);
4881 break;
4884 case MONO_EXCEPTION_FILE_NOT_FOUND: {
4885 const char *msg;
4887 if (error->ref_only)
4888 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.";
4889 else
4890 msg = "Could not load file or assembly '%s' or one of its dependencies.";
4892 exception_data = concat_two_strings_with_zero (class->image, msg, error->assembly_name);
4893 break;
4896 case MONO_EXCEPTION_BAD_IMAGE:
4897 exception_data = error->msg;
4898 break;
4900 default :
4901 g_assert_not_reached ();
4904 mono_class_set_failure (class, error->exception_type, exception_data);
4908 * mono_class_init:
4909 * @class: the class to initialize
4911 * Compute the instance_size, class_size and other infos that cannot be
4912 * computed at mono_class_get() time. Also compute vtable_size if possible.
4913 * Returns TRUE on success or FALSE if there was a problem in loading
4914 * the type (incorrect assemblies, missing assemblies, methods, etc).
4916 * LOCKING: Acquires the loader lock.
4918 gboolean
4919 mono_class_init (MonoClass *class)
4921 int i;
4922 MonoCachedClassInfo cached_info;
4923 gboolean has_cached_info;
4925 g_assert (class);
4927 /* Double-checking locking pattern */
4928 if (class->inited || class->exception_type)
4929 return class->exception_type == MONO_EXCEPTION_NONE;
4931 /*g_print ("Init class %s\n", mono_type_get_full_name (class));*/
4933 /* We do everything inside the lock to prevent races */
4934 mono_loader_lock ();
4936 if (class->inited || class->exception_type) {
4937 mono_loader_unlock ();
4938 /* Somebody might have gotten in before us */
4939 return class->exception_type == MONO_EXCEPTION_NONE;
4942 if (class->init_pending) {
4943 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Recursive type definition detected"));
4944 goto leave;
4947 class->init_pending = 1;
4949 if (mono_verifier_is_enabled_for_class (class) && !mono_verifier_verify_class (class)) {
4950 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, concat_two_strings_with_zero (class->image, class->name, class->image->assembly_name));
4951 goto leave;
4955 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
4956 MonoClass *element_class = class->element_class;
4957 if (!element_class->inited)
4958 mono_class_init (element_class);
4959 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
4960 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
4961 goto leave;
4965 /* CAS - SecurityAction.InheritanceDemand */
4966 if (mono_security_enabled () && class->parent && (class->parent->flags & TYPE_ATTRIBUTE_HAS_SECURITY)) {
4967 mono_secman_inheritancedemand_class (class, class->parent);
4970 mono_stats.initialized_class_count++;
4972 if (class->generic_class && !class->generic_class->is_dynamic) {
4973 MonoClass *gklass = class->generic_class->container_class;
4975 mono_stats.generic_class_count++;
4977 class->method = gklass->method;
4978 class->field = gklass->field;
4980 mono_class_init (gklass);
4981 // FIXME: Why is this needed ?
4982 if (!gklass->exception_type)
4983 mono_class_setup_methods (gklass);
4984 if (gklass->exception_type) {
4985 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic Type Defintion failed to init"));
4986 goto leave;
4989 if (MONO_CLASS_IS_INTERFACE (class))
4990 class->interface_id = mono_get_unique_iid (class);
4993 if (class->parent && !class->parent->inited)
4994 mono_class_init (class->parent);
4996 has_cached_info = mono_class_get_cached_class_info (class, &cached_info);
4998 if (class->generic_class || class->image->dynamic || !class->type_token || (has_cached_info && !cached_info.has_nested_classes))
4999 class->nested_classes_inited = TRUE;
5002 * Computes the size used by the fields, and their locations
5004 if (has_cached_info) {
5005 class->instance_size = cached_info.instance_size;
5006 class->sizes.class_size = cached_info.class_size;
5007 class->packing_size = cached_info.packing_size;
5008 class->min_align = cached_info.min_align;
5009 class->blittable = cached_info.blittable;
5010 class->has_references = cached_info.has_references;
5011 class->has_static_refs = cached_info.has_static_refs;
5012 class->no_special_static_fields = cached_info.no_special_static_fields;
5014 else
5015 if (!class->size_inited){
5016 mono_class_setup_fields (class);
5017 if (class->exception_type || mono_loader_get_last_error ())
5018 goto leave;
5021 /* Initialize arrays */
5022 if (class->rank) {
5023 class->method.count = 3 + (class->rank > 1? 2: 1);
5025 if (class->interface_count) {
5026 int count_generic = generic_array_methods (class);
5027 class->method.count += class->interface_count * count_generic;
5031 mono_class_setup_supertypes (class);
5033 if (!default_ghc)
5034 initialize_object_slots (class);
5037 * Initialize the rest of the data without creating a generic vtable if possible.
5038 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
5039 * also avoid computing a generic vtable.
5041 if (has_cached_info) {
5042 /* AOT case */
5043 class->vtable_size = cached_info.vtable_size;
5044 class->has_finalize = cached_info.has_finalize;
5045 class->has_finalize_inited = TRUE;
5046 class->ghcimpl = cached_info.ghcimpl;
5047 class->has_cctor = cached_info.has_cctor;
5048 } else if (class->rank == 1 && class->byval_arg.type == MONO_TYPE_SZARRAY) {
5049 /* SZARRAY can have 2 vtable layouts, with and without the stelemref method.
5050 * The first slot if for array with.
5052 static int szarray_vtable_size[2] = { 0 };
5054 int slot = MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg) ? 0 : 1;
5056 /* SZARRAY case */
5057 if (!szarray_vtable_size [slot]) {
5058 mono_class_setup_vtable (class);
5059 szarray_vtable_size [slot] = class->vtable_size;
5060 } else {
5061 class->vtable_size = szarray_vtable_size[slot];
5063 class->has_finalize_inited = TRUE;
5064 } else if (class->generic_class && !MONO_CLASS_IS_INTERFACE (class)) {
5065 MonoClass *gklass = class->generic_class->container_class;
5067 /* Generic instance case */
5068 class->ghcimpl = gklass->ghcimpl;
5069 class->has_finalize = mono_class_has_finalizer (gklass);
5070 class->has_finalize_inited = TRUE;
5071 class->has_cctor = gklass->has_cctor;
5073 mono_class_setup_vtable (gklass);
5074 if (gklass->exception_type) {
5075 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5076 goto leave;
5079 class->vtable_size = gklass->vtable_size;
5080 } else {
5081 /* General case */
5083 /* ghcimpl is not currently used
5084 class->ghcimpl = 1;
5085 if (class->parent) {
5086 MonoMethod *cmethod = class->vtable [ghc_slot];
5087 if (cmethod->is_inflated)
5088 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5089 if (cmethod == default_ghc) {
5090 class->ghcimpl = 0;
5095 /* C# doesn't allow interfaces to have cctors */
5096 if (!MONO_CLASS_IS_INTERFACE (class) || class->image != mono_defaults.corlib) {
5097 MonoMethod *cmethod = NULL;
5099 if (class->type_token) {
5100 cmethod = find_method_in_metadata (class, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
5101 /* The find_method function ignores the 'flags' argument */
5102 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
5103 class->has_cctor = 1;
5104 } else {
5105 mono_class_setup_methods (class);
5106 if (class->exception_type)
5107 goto leave;
5109 for (i = 0; i < class->method.count; ++i) {
5110 MonoMethod *method = class->methods [i];
5111 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
5112 (strcmp (".cctor", method->name) == 0)) {
5113 class->has_cctor = 1;
5114 break;
5121 if (class->parent) {
5122 int first_iface_slot;
5123 /* This will compute class->parent->vtable_size for some classes */
5124 mono_class_init (class->parent);
5125 if (class->parent->exception_type) {
5126 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5127 goto leave;
5129 if (mono_loader_get_last_error ())
5130 goto leave;
5131 if (!class->parent->vtable_size) {
5132 /* FIXME: Get rid of this somehow */
5133 mono_class_setup_vtable (class->parent);
5134 if (class->parent->exception_type) {
5135 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5136 goto leave;
5138 if (mono_loader_get_last_error ())
5139 goto leave;
5141 first_iface_slot = class->parent->vtable_size;
5142 if (mono_class_need_stelemref_method (class))
5143 ++first_iface_slot;
5144 setup_interface_offsets (class, first_iface_slot, TRUE);
5145 } else {
5146 setup_interface_offsets (class, 0, TRUE);
5149 if (mono_security_core_clr_enabled ())
5150 mono_security_core_clr_check_inheritance (class);
5152 if (mono_loader_get_last_error ()) {
5153 if (class->exception_type == MONO_EXCEPTION_NONE) {
5154 set_failure_from_loader_error (class, mono_loader_get_last_error ());
5156 mono_loader_clear_error ();
5159 if (class->generic_class && !mono_verifier_class_is_valid_generic_instantiation (class))
5160 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Invalid generic instantiation"));
5162 goto leave;
5164 leave:
5165 /* Because of the double-checking locking pattern */
5166 mono_memory_barrier ();
5167 class->inited = 1;
5168 class->init_pending = 0;
5170 mono_loader_unlock ();
5172 if (mono_debugger_class_init_func)
5173 mono_debugger_class_init_func (class);
5175 return class->exception_type == MONO_EXCEPTION_NONE;
5179 * mono_class_has_finalizer:
5181 * Return whenever KLASS has a finalizer, initializing klass->has_finalizer in the
5182 * process.
5184 gboolean
5185 mono_class_has_finalizer (MonoClass *klass)
5187 if (!klass->has_finalize_inited) {
5188 MonoClass *class = klass;
5190 mono_loader_lock ();
5192 /* Interfaces and valuetypes are not supposed to have finalizers */
5193 if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) {
5194 MonoMethod *cmethod = NULL;
5196 if (class->parent && class->parent->has_finalize) {
5197 class->has_finalize = 1;
5198 } else {
5199 if (class->parent) {
5201 * Can't search in metadata for a method named Finalize, because that
5202 * ignores overrides.
5204 mono_class_setup_vtable (class);
5205 if (class->exception_type || mono_loader_get_last_error ())
5206 goto leave;
5207 cmethod = class->vtable [finalize_slot];
5210 if (cmethod) {
5211 g_assert (class->vtable_size > finalize_slot);
5213 class->has_finalize = 0;
5214 if (class->parent) {
5215 if (cmethod->is_inflated)
5216 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5217 if (cmethod != default_finalize) {
5218 class->has_finalize = 1;
5225 mono_memory_barrier ();
5226 klass->has_finalize_inited = TRUE;
5228 mono_loader_unlock ();
5231 return klass->has_finalize;
5233 leave:
5234 mono_loader_unlock ();
5235 return FALSE;
5238 gboolean
5239 mono_is_corlib_image (MonoImage *image)
5241 /* FIXME: allow the dynamic case for our compilers and with full trust */
5242 if (image->dynamic)
5243 return image->assembly && !strcmp (image->assembly->aname.name, "mscorlib");
5244 else
5245 return image == mono_defaults.corlib;
5249 * LOCKING: this assumes the loader lock is held
5251 void
5252 mono_class_setup_mono_type (MonoClass *class)
5254 const char *name = class->name;
5255 const char *nspace = class->name_space;
5256 gboolean is_corlib = mono_is_corlib_image (class->image);
5258 class->this_arg.byref = 1;
5259 class->this_arg.data.klass = class;
5260 class->this_arg.type = MONO_TYPE_CLASS;
5261 class->byval_arg.data.klass = class;
5262 class->byval_arg.type = MONO_TYPE_CLASS;
5264 if (is_corlib && !strcmp (nspace, "System")) {
5265 if (!strcmp (name, "ValueType")) {
5267 * do not set the valuetype bit for System.ValueType.
5268 * class->valuetype = 1;
5270 class->blittable = TRUE;
5271 } else if (!strcmp (name, "Enum")) {
5273 * do not set the valuetype bit for System.Enum.
5274 * class->valuetype = 1;
5276 class->valuetype = 0;
5277 class->enumtype = 0;
5278 } else if (!strcmp (name, "Object")) {
5279 class->this_arg.type = class->byval_arg.type = MONO_TYPE_OBJECT;
5280 } else if (!strcmp (name, "String")) {
5281 class->this_arg.type = class->byval_arg.type = MONO_TYPE_STRING;
5282 } else if (!strcmp (name, "TypedReference")) {
5283 class->this_arg.type = class->byval_arg.type = MONO_TYPE_TYPEDBYREF;
5287 if (class->valuetype) {
5288 int t = MONO_TYPE_VALUETYPE;
5290 if (is_corlib && !strcmp (nspace, "System")) {
5291 switch (*name) {
5292 case 'B':
5293 if (!strcmp (name, "Boolean")) {
5294 t = MONO_TYPE_BOOLEAN;
5295 } else if (!strcmp(name, "Byte")) {
5296 t = MONO_TYPE_U1;
5297 class->blittable = TRUE;
5299 break;
5300 case 'C':
5301 if (!strcmp (name, "Char")) {
5302 t = MONO_TYPE_CHAR;
5304 break;
5305 case 'D':
5306 if (!strcmp (name, "Double")) {
5307 t = MONO_TYPE_R8;
5308 class->blittable = TRUE;
5310 break;
5311 case 'I':
5312 if (!strcmp (name, "Int32")) {
5313 t = MONO_TYPE_I4;
5314 class->blittable = TRUE;
5315 } else if (!strcmp(name, "Int16")) {
5316 t = MONO_TYPE_I2;
5317 class->blittable = TRUE;
5318 } else if (!strcmp(name, "Int64")) {
5319 t = MONO_TYPE_I8;
5320 class->blittable = TRUE;
5321 } else if (!strcmp(name, "IntPtr")) {
5322 t = MONO_TYPE_I;
5323 class->blittable = TRUE;
5325 break;
5326 case 'S':
5327 if (!strcmp (name, "Single")) {
5328 t = MONO_TYPE_R4;
5329 class->blittable = TRUE;
5330 } else if (!strcmp(name, "SByte")) {
5331 t = MONO_TYPE_I1;
5332 class->blittable = TRUE;
5334 break;
5335 case 'U':
5336 if (!strcmp (name, "UInt32")) {
5337 t = MONO_TYPE_U4;
5338 class->blittable = TRUE;
5339 } else if (!strcmp(name, "UInt16")) {
5340 t = MONO_TYPE_U2;
5341 class->blittable = TRUE;
5342 } else if (!strcmp(name, "UInt64")) {
5343 t = MONO_TYPE_U8;
5344 class->blittable = TRUE;
5345 } else if (!strcmp(name, "UIntPtr")) {
5346 t = MONO_TYPE_U;
5347 class->blittable = TRUE;
5349 break;
5350 case 'T':
5351 if (!strcmp (name, "TypedReference")) {
5352 t = MONO_TYPE_TYPEDBYREF;
5353 class->blittable = TRUE;
5355 break;
5356 case 'V':
5357 if (!strcmp (name, "Void")) {
5358 t = MONO_TYPE_VOID;
5360 break;
5361 default:
5362 break;
5365 class->this_arg.type = class->byval_arg.type = t;
5368 if (MONO_CLASS_IS_INTERFACE (class))
5369 class->interface_id = mono_get_unique_iid (class);
5373 #ifndef DISABLE_COM
5375 * COM initialization is delayed until needed.
5376 * However when a [ComImport] attribute is present on a type it will trigger
5377 * the initialization. This is not a problem unless the BCL being executed
5378 * lacks the types that COM depends on (e.g. Variant on Silverlight).
5380 static void
5381 init_com_from_comimport (MonoClass *class)
5383 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
5384 if (mono_security_core_clr_enabled ()) {
5385 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
5386 if (!mono_security_core_clr_determine_platform_image (class->image)) {
5387 /* but it can not be made available for application (i.e. user code) since all COM calls
5388 * are considered native calls. In this case we fail with a TypeLoadException (just like
5389 * Silverlight 2 does */
5390 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5391 return;
5395 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
5397 #endif /*DISABLE_COM*/
5400 * LOCKING: this assumes the loader lock is held
5402 void
5403 mono_class_setup_parent (MonoClass *class, MonoClass *parent)
5405 gboolean system_namespace;
5406 gboolean is_corlib = mono_is_corlib_image (class->image);
5408 system_namespace = !strcmp (class->name_space, "System") && is_corlib;
5410 /* if root of the hierarchy */
5411 if (system_namespace && !strcmp (class->name, "Object")) {
5412 class->parent = NULL;
5413 class->instance_size = sizeof (MonoObject);
5414 return;
5416 if (!strcmp (class->name, "<Module>")) {
5417 class->parent = NULL;
5418 class->instance_size = 0;
5419 return;
5422 if (!MONO_CLASS_IS_INTERFACE (class)) {
5423 /* Imported COM Objects always derive from __ComObject. */
5424 #ifndef DISABLE_COM
5425 if (MONO_CLASS_IS_IMPORT (class)) {
5426 init_com_from_comimport (class);
5427 if (parent == mono_defaults.object_class)
5428 parent = mono_class_get_com_object_class ();
5430 #endif
5431 if (!parent) {
5432 /* set the parent to something useful and safe, but mark the type as broken */
5433 parent = mono_defaults.object_class;
5434 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5437 class->parent = parent;
5439 if (parent->generic_class && !parent->name) {
5441 * If the parent is a generic instance, we may get
5442 * called before it is fully initialized, especially
5443 * before it has its name.
5445 return;
5448 #ifndef DISABLE_REMOTING
5449 class->marshalbyref = parent->marshalbyref;
5450 class->contextbound = parent->contextbound;
5451 #endif
5453 class->delegate = parent->delegate;
5455 if (MONO_CLASS_IS_IMPORT (class) || mono_class_is_com_object (parent))
5456 mono_class_set_is_com_object (class);
5458 if (system_namespace) {
5459 #ifndef DISABLE_REMOTING
5460 if (*class->name == 'M' && !strcmp (class->name, "MarshalByRefObject"))
5461 class->marshalbyref = 1;
5463 if (*class->name == 'C' && !strcmp (class->name, "ContextBoundObject"))
5464 class->contextbound = 1;
5465 #endif
5466 if (*class->name == 'D' && !strcmp (class->name, "Delegate"))
5467 class->delegate = 1;
5470 if (class->parent->enumtype || (mono_is_corlib_image (class->parent->image) && (strcmp (class->parent->name, "ValueType") == 0) &&
5471 (strcmp (class->parent->name_space, "System") == 0)))
5472 class->valuetype = 1;
5473 if (mono_is_corlib_image (class->parent->image) && ((strcmp (class->parent->name, "Enum") == 0) && (strcmp (class->parent->name_space, "System") == 0))) {
5474 class->valuetype = class->enumtype = 1;
5476 /*class->enumtype = class->parent->enumtype; */
5477 } else {
5478 /* initialize com types if COM interfaces are present */
5479 #ifndef DISABLE_COM
5480 if (MONO_CLASS_IS_IMPORT (class))
5481 init_com_from_comimport (class);
5482 #endif
5483 class->parent = NULL;
5489 * mono_class_setup_supertypes:
5490 * @class: a class
5492 * Build the data structure needed to make fast type checks work.
5493 * This currently sets two fields in @class:
5494 * - idepth: distance between @class and System.Object in the type
5495 * hierarchy + 1
5496 * - supertypes: array of classes: each element has a class in the hierarchy
5497 * starting from @class up to System.Object
5499 * LOCKING: This function is atomic, in case of contention we waste memory.
5501 void
5502 mono_class_setup_supertypes (MonoClass *class)
5504 int ms;
5505 MonoClass **supertypes;
5507 mono_atomic_load_acquire (supertypes, void*, &class->supertypes);
5508 if (supertypes)
5509 return;
5511 if (class->parent && !class->parent->supertypes)
5512 mono_class_setup_supertypes (class->parent);
5513 if (class->parent)
5514 class->idepth = class->parent->idepth + 1;
5515 else
5516 class->idepth = 1;
5518 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, class->idepth);
5519 supertypes = mono_class_alloc0 (class, sizeof (MonoClass *) * ms);
5521 if (class->parent) {
5522 supertypes [class->idepth - 1] = class;
5523 memcpy (supertypes, class->parent->supertypes, class->parent->idepth * sizeof (gpointer));
5524 } else {
5525 supertypes [0] = class;
5528 mono_atomic_store_release (&class->supertypes, supertypes);
5531 static gboolean
5532 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
5534 MonoClass *gtd = (MonoClass*)user_data;
5535 /* Only try to fix generic instances of @gtd */
5536 if (gclass->generic_class->container_class != gtd)
5537 return FALSE;
5539 /* Check if the generic instance has no parent. */
5540 if (gtd->parent && !gclass->parent)
5541 mono_generic_class_setup_parent (gclass, gtd);
5543 return TRUE;
5546 static void
5547 mono_class_set_failure_and_error (MonoClass *class, MonoError *error, const char *msg)
5549 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (msg));
5550 mono_error_set_type_load_class (error, class, msg);
5553 static void
5554 mono_class_set_failure_from_loader_error (MonoClass *class, MonoError *error, char *msg)
5556 MonoLoaderError *lerror = mono_loader_get_last_error ();
5558 if (lerror) {
5559 set_failure_from_loader_error (class, lerror);
5560 mono_error_set_from_loader_error (error);
5561 if (msg)
5562 g_free (msg);
5563 } else {
5564 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, msg);
5565 mono_error_set_type_load_class (error, class, msg);
5570 * mono_class_create_from_typedef:
5571 * @image: image where the token is valid
5572 * @type_token: typedef token
5573 * @error: used to return any error found while creating the type
5575 * Create the MonoClass* representing the specified type token.
5576 * @type_token must be a TypeDef token.
5578 * FIXME: don't return NULL on failure, just the the caller figure it out.
5580 static MonoClass *
5581 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
5583 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
5584 MonoClass *class, *parent = NULL;
5585 guint32 cols [MONO_TYPEDEF_SIZE];
5586 guint32 cols_next [MONO_TYPEDEF_SIZE];
5587 guint tidx = mono_metadata_token_index (type_token);
5588 MonoGenericContext *context = NULL;
5589 const char *name, *nspace;
5590 guint icount = 0;
5591 MonoClass **interfaces;
5592 guint32 field_last, method_last;
5593 guint32 nesting_tokeen;
5595 mono_error_init (error);
5597 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
5598 mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
5599 g_assert (!mono_loader_get_last_error ());
5600 return NULL;
5603 mono_loader_lock ();
5605 if ((class = mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
5606 mono_loader_unlock ();
5607 g_assert (!mono_loader_get_last_error ());
5608 return class;
5611 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
5613 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
5614 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
5616 class = mono_image_alloc0 (image, sizeof (MonoClass));
5618 class->name = name;
5619 class->name_space = nspace;
5621 mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
5623 class->image = image;
5624 class->type_token = type_token;
5625 class->flags = cols [MONO_TYPEDEF_FLAGS];
5627 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), class);
5629 classes_size += sizeof (MonoClass);
5632 * Check whether we're a generic type definition.
5634 class->generic_container = mono_metadata_load_generic_params (image, class->type_token, NULL);
5635 if (class->generic_container) {
5636 class->is_generic = 1;
5637 class->generic_container->owner.klass = class;
5638 context = &class->generic_container->context;
5641 if (class->generic_container)
5642 enable_gclass_recording ();
5644 if (cols [MONO_TYPEDEF_EXTENDS]) {
5645 MonoClass *tmp;
5646 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
5648 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
5649 /*WARNING: this must satisfy mono_metadata_type_hash*/
5650 class->this_arg.byref = 1;
5651 class->this_arg.data.klass = class;
5652 class->this_arg.type = MONO_TYPE_CLASS;
5653 class->byval_arg.data.klass = class;
5654 class->byval_arg.type = MONO_TYPE_CLASS;
5656 parent = mono_class_get_full (image, parent_token, context);
5658 if (parent == NULL) {
5659 mono_class_set_failure_from_loader_error (class, error, g_strdup_printf ("Could not load parent, token is %x", parent_token));
5660 goto parent_failure;
5663 for (tmp = parent; tmp; tmp = tmp->parent) {
5664 if (tmp == class) {
5665 mono_class_set_failure_and_error (class, error, "Cycle found while resolving parent");
5666 goto parent_failure;
5668 if (class->generic_container && tmp->generic_class && tmp->generic_class->container_class == class) {
5669 mono_class_set_failure_and_error (class, error, "Parent extends generic instance of this type");
5670 goto parent_failure;
5675 mono_class_setup_parent (class, parent);
5677 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
5678 mono_class_setup_mono_type (class);
5680 if (class->generic_container)
5681 disable_gclass_recording (fix_gclass_incomplete_instantiation, class);
5684 * This might access class->byval_arg for recursion generated by generic constraints,
5685 * so it has to come after setup_mono_type ().
5687 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
5688 class->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
5689 if (!mono_error_ok (error)) {
5690 /*FIXME implement a mono_class_set_failure_from_mono_error */
5691 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
5692 mono_loader_unlock ();
5693 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5694 g_assert (!mono_loader_get_last_error ());
5695 return NULL;
5699 if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
5700 class->unicode = 1;
5702 #ifdef HOST_WIN32
5703 if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
5704 class->unicode = 1;
5705 #endif
5707 class->cast_class = class->element_class = class;
5709 if (!class->enumtype) {
5710 if (!mono_metadata_interfaces_from_typedef_full (
5711 image, type_token, &interfaces, &icount, FALSE, context)){
5712 mono_class_set_failure_from_loader_error (class, error, g_strdup ("Could not load interfaces"));
5713 mono_loader_unlock ();
5714 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5715 return NULL;
5718 class->interfaces = interfaces;
5719 class->interface_count = icount;
5720 class->interfaces_inited = 1;
5723 /*g_print ("Load class %s\n", name);*/
5726 * Compute the field and method lists
5728 class->field.first = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
5729 class->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
5731 if (tt->rows > tidx){
5732 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
5733 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
5734 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
5735 } else {
5736 field_last = image->tables [MONO_TABLE_FIELD].rows;
5737 method_last = image->tables [MONO_TABLE_METHOD].rows;
5740 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
5741 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
5742 class->field.count = field_last - class->field.first;
5743 else
5744 class->field.count = 0;
5746 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
5747 class->method.count = method_last - class->method.first;
5748 else
5749 class->method.count = 0;
5751 /* reserve space to store vector pointer in arrays */
5752 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
5753 class->instance_size += 2 * sizeof (gpointer);
5754 g_assert (class->field.count == 0);
5757 if (class->enumtype) {
5758 MonoType *enum_basetype = mono_class_find_enum_basetype (class);
5759 if (!enum_basetype) {
5760 /*set it to a default value as the whole runtime can't handle this to be null*/
5761 class->cast_class = class->element_class = mono_defaults.int32_class;
5762 mono_class_set_failure_and_error (class, error, "Could not enum basetype");
5763 mono_loader_unlock ();
5764 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5765 g_assert (!mono_loader_get_last_error ());
5766 return NULL;
5768 class->cast_class = class->element_class = mono_class_from_mono_type (enum_basetype);
5772 * If we're a generic type definition, load the constraints.
5773 * We must do this after the class has been constructed to make certain recursive scenarios
5774 * work.
5776 if (class->generic_container && !mono_metadata_load_generic_param_constraints_full (image, type_token, class->generic_container)){
5777 mono_class_set_failure_from_loader_error (class, error, g_strdup ("Could not load generic parameter constraints"));
5778 mono_loader_unlock ();
5779 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5780 g_assert (!mono_loader_get_last_error ());
5781 return NULL;
5784 if (class->image->assembly_name && !strcmp (class->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
5785 if (!strncmp (name, "Vector", 6))
5786 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");
5789 mono_loader_unlock ();
5791 mono_profiler_class_loaded (class, MONO_PROFILE_OK);
5792 g_assert (!mono_loader_get_last_error ());
5794 return class;
5796 parent_failure:
5797 mono_class_setup_mono_type (class);
5798 mono_loader_unlock ();
5799 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5800 g_assert (!mono_loader_get_last_error ());
5801 return NULL;
5804 /** is klass Nullable<T>? */
5805 gboolean
5806 mono_class_is_nullable (MonoClass *klass)
5808 return klass->generic_class != NULL &&
5809 klass->generic_class->container_class == mono_defaults.generic_nullable_class;
5813 /** if klass is T? return T */
5814 MonoClass*
5815 mono_class_get_nullable_param (MonoClass *klass)
5817 g_assert (mono_class_is_nullable (klass));
5818 return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
5821 static void
5822 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
5824 if (gtd->parent) {
5825 MonoError error;
5826 MonoGenericClass *gclass = klass->generic_class;
5828 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
5829 if (!mono_error_ok (&error)) {
5830 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
5831 klass->parent = mono_defaults.object_class;
5832 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
5833 mono_error_cleanup (&error);
5836 if (klass->parent)
5837 mono_class_setup_parent (klass, klass->parent);
5839 if (klass->enumtype) {
5840 klass->cast_class = gtd->cast_class;
5841 klass->element_class = gtd->element_class;
5847 * Create the `MonoClass' for an instantiation of a generic type.
5848 * We only do this if we actually need it.
5850 MonoClass*
5851 mono_generic_class_get_class (MonoGenericClass *gclass)
5853 MonoClass *klass, *gklass;
5855 if (gclass->cached_class)
5856 return gclass->cached_class;
5858 mono_loader_lock ();
5859 if (gclass->cached_class) {
5860 mono_loader_unlock ();
5861 return gclass->cached_class;
5864 klass = mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
5866 gklass = gclass->container_class;
5868 if (record_gclass_instantiation > 0)
5869 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
5871 if (gklass->nested_in) {
5872 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
5873 klass->nested_in = gklass->nested_in;
5876 klass->name = gklass->name;
5877 klass->name_space = gklass->name_space;
5879 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
5881 klass->image = gklass->image;
5882 klass->flags = gklass->flags;
5883 klass->type_token = gklass->type_token;
5884 klass->field.count = gklass->field.count;
5886 klass->is_inflated = 1;
5887 klass->generic_class = gclass;
5889 klass->this_arg.type = klass->byval_arg.type = MONO_TYPE_GENERICINST;
5890 klass->this_arg.data.generic_class = klass->byval_arg.data.generic_class = gclass;
5891 klass->this_arg.byref = TRUE;
5892 klass->enumtype = gklass->enumtype;
5893 klass->valuetype = gklass->valuetype;
5895 klass->cast_class = klass->element_class = klass;
5897 if (mono_class_is_nullable (klass))
5898 klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
5901 * We're not interested in the nested classes of a generic instance.
5902 * We use the generic type definition to look for nested classes.
5905 mono_generic_class_setup_parent (klass, gklass);
5907 if (gclass->is_dynamic) {
5908 klass->inited = 1;
5910 mono_class_setup_supertypes (klass);
5912 if (klass->enumtype) {
5914 * For enums, gklass->fields might not been set, but instance_size etc. is
5915 * already set in mono_reflection_create_internal_class (). For non-enums,
5916 * these will be computed normally in mono_class_layout_fields ().
5918 klass->instance_size = gklass->instance_size;
5919 klass->sizes.class_size = gklass->sizes.class_size;
5920 mono_memory_barrier ();
5921 klass->size_inited = 1;
5925 mono_memory_barrier ();
5926 gclass->cached_class = klass;
5928 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
5930 inflated_classes ++;
5931 inflated_classes_size += sizeof (MonoClass);
5933 mono_loader_unlock ();
5935 return klass;
5938 static MonoClass*
5939 make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is_mvar, MonoGenericParamInfo *pinfo)
5941 MonoClass *klass, **ptr;
5942 int count, pos, i;
5943 MonoGenericContainer *container = mono_generic_param_owner (param);
5945 if (!image)
5946 /* FIXME: */
5947 image = mono_defaults.corlib;
5949 klass = mono_image_alloc0 (image, sizeof (MonoClass));
5950 classes_size += sizeof (MonoClass);
5952 if (pinfo) {
5953 klass->name = pinfo->name;
5954 } else {
5955 int n = mono_generic_param_num (param);
5956 klass->name = mono_image_alloc0 (image, 16);
5957 sprintf ((char*)klass->name, "%d", n);
5960 if (container) {
5961 if (is_mvar) {
5962 MonoMethod *omethod = container->owner.method;
5963 klass->name_space = (omethod && omethod->klass) ? omethod->klass->name_space : "";
5964 } else {
5965 MonoClass *oklass = container->owner.klass;
5966 klass->name_space = oklass ? oklass->name_space : "";
5968 } else {
5969 klass->name_space = "";
5972 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
5974 count = 0;
5975 if (pinfo)
5976 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
5979 pos = 0;
5980 if ((count > 0) && !MONO_CLASS_IS_INTERFACE (pinfo->constraints [0])) {
5981 klass->parent = pinfo->constraints [0];
5982 pos++;
5983 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
5984 klass->parent = mono_class_from_name (mono_defaults.corlib, "System", "ValueType");
5985 else
5986 klass->parent = mono_defaults.object_class;
5989 if (count - pos > 0) {
5990 klass->interface_count = count - pos;
5991 klass->interfaces = mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos));
5992 klass->interfaces_inited = TRUE;
5993 for (i = pos; i < count; i++)
5994 klass->interfaces [i - pos] = pinfo->constraints [i];
5997 klass->image = image;
5999 klass->inited = TRUE;
6000 klass->cast_class = klass->element_class = klass;
6001 klass->flags = TYPE_ATTRIBUTE_PUBLIC;
6003 klass->this_arg.type = klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
6004 klass->this_arg.data.generic_param = klass->byval_arg.data.generic_param = param;
6005 klass->this_arg.byref = TRUE;
6007 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
6008 klass->sizes.generic_param_token = pinfo ? pinfo->token : 0;
6010 /*Init these fields to sane values*/
6011 klass->min_align = 1;
6012 klass->instance_size = sizeof (gpointer);
6013 mono_memory_barrier ();
6014 klass->size_inited = 1;
6016 mono_class_setup_supertypes (klass);
6018 if (count - pos > 0) {
6019 mono_class_setup_vtable (klass->parent);
6020 if (klass->parent->exception_type)
6021 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to setup parent interfaces"));
6022 else
6023 setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
6026 return klass;
6029 #define FAST_CACHE_SIZE 16
6031 static MonoClass *
6032 get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar)
6034 int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
6035 MonoImage *image = param->image;
6036 GHashTable *ht;
6038 g_assert (image);
6040 if (n < FAST_CACHE_SIZE) {
6041 if (is_mvar)
6042 return image->mvar_cache_fast ? image->mvar_cache_fast [n] : NULL;
6043 else
6044 return image->var_cache_fast ? image->var_cache_fast [n] : NULL;
6045 } else {
6046 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6047 return ht ? g_hash_table_lookup (ht, GINT_TO_POINTER (n)) : NULL;
6052 * LOCKING: Acquires the loader lock.
6054 static void
6055 set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
6057 int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
6058 MonoImage *image = param->image;
6059 GHashTable *ht;
6061 g_assert (image);
6063 if (n < FAST_CACHE_SIZE) {
6064 if (is_mvar) {
6065 /* No locking needed */
6066 if (!image->mvar_cache_fast)
6067 image->mvar_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6068 image->mvar_cache_fast [n] = klass;
6069 } else {
6070 if (!image->var_cache_fast)
6071 image->var_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6072 image->var_cache_fast [n] = klass;
6074 return;
6076 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6077 if (!ht) {
6078 mono_loader_lock ();
6079 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6080 if (!ht) {
6081 ht = g_hash_table_new (NULL, NULL);
6082 mono_memory_barrier ();
6083 if (is_mvar)
6084 image->mvar_cache_slow = ht;
6085 else
6086 image->var_cache_slow = ht;
6088 mono_loader_unlock ();
6091 g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
6095 * LOCKING: Acquires the loader lock.
6097 MonoClass *
6098 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar)
6100 MonoGenericContainer *container = mono_generic_param_owner (param);
6101 MonoGenericParamInfo *pinfo;
6102 MonoClass *klass;
6104 mono_loader_lock ();
6106 if (container) {
6107 pinfo = mono_generic_param_info (param);
6108 if (pinfo->pklass) {
6109 mono_loader_unlock ();
6110 return pinfo->pklass;
6112 } else {
6113 pinfo = NULL;
6114 image = NULL;
6116 klass = get_anon_gparam_class (param, is_mvar);
6117 if (klass) {
6118 mono_loader_unlock ();
6119 return klass;
6123 if (!image && container) {
6124 if (is_mvar) {
6125 MonoMethod *method = container->owner.method;
6126 image = (method && method->klass) ? method->klass->image : NULL;
6127 } else {
6128 MonoClass *klass = container->owner.klass;
6129 // FIXME: 'klass' should not be null
6130 // But, monodis creates GenericContainers without associating a owner to it
6131 image = klass ? klass->image : NULL;
6135 klass = make_generic_param_class (param, image, is_mvar, pinfo);
6137 mono_memory_barrier ();
6139 if (container)
6140 pinfo->pklass = klass;
6141 else
6142 set_anon_gparam_class (param, is_mvar, klass);
6144 mono_loader_unlock ();
6146 /* FIXME: Should this go inside 'make_generic_param_klass'? */
6147 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6149 return klass;
6152 MonoClass *
6153 mono_ptr_class_get (MonoType *type)
6155 MonoClass *result;
6156 MonoClass *el_class;
6157 MonoImage *image;
6158 char *name;
6160 el_class = mono_class_from_mono_type (type);
6161 image = el_class->image;
6163 mono_loader_lock ();
6165 if (!image->ptr_cache)
6166 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6168 if ((result = g_hash_table_lookup (image->ptr_cache, el_class))) {
6169 mono_loader_unlock ();
6170 return result;
6172 result = mono_image_alloc0 (image, sizeof (MonoClass));
6174 classes_size += sizeof (MonoClass);
6176 result->parent = NULL; /* no parent for PTR types */
6177 result->name_space = el_class->name_space;
6178 name = g_strdup_printf ("%s*", el_class->name);
6179 result->name = mono_image_strdup (image, name);
6180 g_free (name);
6182 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6184 result->image = el_class->image;
6185 result->inited = TRUE;
6186 result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
6187 /* Can pointers get boxed? */
6188 result->instance_size = sizeof (gpointer);
6189 result->cast_class = result->element_class = el_class;
6190 result->blittable = TRUE;
6192 result->this_arg.type = result->byval_arg.type = MONO_TYPE_PTR;
6193 result->this_arg.data.type = result->byval_arg.data.type = &result->element_class->byval_arg;
6194 result->this_arg.byref = TRUE;
6196 mono_class_setup_supertypes (result);
6198 g_hash_table_insert (image->ptr_cache, el_class, result);
6200 mono_loader_unlock ();
6202 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6204 return result;
6207 static MonoClass *
6208 mono_fnptr_class_get (MonoMethodSignature *sig)
6210 MonoClass *result;
6211 static GHashTable *ptr_hash = NULL;
6213 /* FIXME: These should be allocate from a mempool as well, but which one ? */
6215 mono_loader_lock ();
6217 if (!ptr_hash)
6218 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
6220 if ((result = g_hash_table_lookup (ptr_hash, sig))) {
6221 mono_loader_unlock ();
6222 return result;
6224 result = g_new0 (MonoClass, 1);
6226 result->parent = NULL; /* no parent for PTR types */
6227 result->name_space = "System";
6228 result->name = "MonoFNPtrFakeClass";
6230 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6232 result->image = mono_defaults.corlib; /* need to fix... */
6233 result->inited = TRUE;
6234 result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */
6235 /* Can pointers get boxed? */
6236 result->instance_size = sizeof (gpointer);
6237 result->cast_class = result->element_class = result;
6238 result->blittable = TRUE;
6240 result->this_arg.type = result->byval_arg.type = MONO_TYPE_FNPTR;
6241 result->this_arg.data.method = result->byval_arg.data.method = sig;
6242 result->this_arg.byref = TRUE;
6243 result->blittable = TRUE;
6245 mono_class_setup_supertypes (result);
6247 g_hash_table_insert (ptr_hash, sig, result);
6249 mono_loader_unlock ();
6251 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6253 return result;
6256 MonoClass *
6257 mono_class_from_mono_type (MonoType *type)
6259 switch (type->type) {
6260 case MONO_TYPE_OBJECT:
6261 return type->data.klass? type->data.klass: mono_defaults.object_class;
6262 case MONO_TYPE_VOID:
6263 return type->data.klass? type->data.klass: mono_defaults.void_class;
6264 case MONO_TYPE_BOOLEAN:
6265 return type->data.klass? type->data.klass: mono_defaults.boolean_class;
6266 case MONO_TYPE_CHAR:
6267 return type->data.klass? type->data.klass: mono_defaults.char_class;
6268 case MONO_TYPE_I1:
6269 return type->data.klass? type->data.klass: mono_defaults.sbyte_class;
6270 case MONO_TYPE_U1:
6271 return type->data.klass? type->data.klass: mono_defaults.byte_class;
6272 case MONO_TYPE_I2:
6273 return type->data.klass? type->data.klass: mono_defaults.int16_class;
6274 case MONO_TYPE_U2:
6275 return type->data.klass? type->data.klass: mono_defaults.uint16_class;
6276 case MONO_TYPE_I4:
6277 return type->data.klass? type->data.klass: mono_defaults.int32_class;
6278 case MONO_TYPE_U4:
6279 return type->data.klass? type->data.klass: mono_defaults.uint32_class;
6280 case MONO_TYPE_I:
6281 return type->data.klass? type->data.klass: mono_defaults.int_class;
6282 case MONO_TYPE_U:
6283 return type->data.klass? type->data.klass: mono_defaults.uint_class;
6284 case MONO_TYPE_I8:
6285 return type->data.klass? type->data.klass: mono_defaults.int64_class;
6286 case MONO_TYPE_U8:
6287 return type->data.klass? type->data.klass: mono_defaults.uint64_class;
6288 case MONO_TYPE_R4:
6289 return type->data.klass? type->data.klass: mono_defaults.single_class;
6290 case MONO_TYPE_R8:
6291 return type->data.klass? type->data.klass: mono_defaults.double_class;
6292 case MONO_TYPE_STRING:
6293 return type->data.klass? type->data.klass: mono_defaults.string_class;
6294 case MONO_TYPE_TYPEDBYREF:
6295 return type->data.klass? type->data.klass: mono_defaults.typed_reference_class;
6296 case MONO_TYPE_ARRAY:
6297 return mono_bounded_array_class_get (type->data.array->eklass, type->data.array->rank, TRUE);
6298 case MONO_TYPE_PTR:
6299 return mono_ptr_class_get (type->data.type);
6300 case MONO_TYPE_FNPTR:
6301 return mono_fnptr_class_get (type->data.method);
6302 case MONO_TYPE_SZARRAY:
6303 return mono_array_class_get (type->data.klass, 1);
6304 case MONO_TYPE_CLASS:
6305 case MONO_TYPE_VALUETYPE:
6306 return type->data.klass;
6307 case MONO_TYPE_GENERICINST:
6308 return mono_generic_class_get_class (type->data.generic_class);
6309 case MONO_TYPE_VAR:
6310 return mono_class_from_generic_parameter (type->data.generic_param, NULL, FALSE);
6311 case MONO_TYPE_MVAR:
6312 return mono_class_from_generic_parameter (type->data.generic_param, NULL, TRUE);
6313 default:
6314 g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
6315 g_assert_not_reached ();
6318 return NULL;
6322 * mono_type_retrieve_from_typespec
6323 * @image: context where the image is created
6324 * @type_spec: typespec token
6325 * @context: the generic context used to evaluate generic instantiations in
6327 static MonoType *
6328 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
6330 MonoType *t = mono_type_create_from_typespec (image, type_spec);
6332 mono_error_init (error);
6333 *did_inflate = FALSE;
6335 if (!t) {
6336 char *name = mono_class_name_from_token (image, type_spec);
6337 char *assembly = mono_assembly_name_from_token (image, type_spec);
6338 mono_error_set_type_load_name (error, name, assembly, "Could not resolve typespec token %08x", type_spec);
6339 return NULL;
6342 if (context && (context->class_inst || context->method_inst)) {
6343 MonoType *inflated = inflate_generic_type (NULL, t, context, error);
6345 if (!mono_error_ok (error))
6346 return NULL;
6348 if (inflated) {
6349 t = inflated;
6350 *did_inflate = TRUE;
6353 return t;
6357 * mono_class_create_from_typespec
6358 * @image: context where the image is created
6359 * @type_spec: typespec token
6360 * @context: the generic context used to evaluate generic instantiations in
6362 static MonoClass *
6363 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
6365 MonoClass *ret;
6366 gboolean inflated = FALSE;
6367 MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
6368 if (!mono_error_ok (error))
6369 return NULL;
6370 ret = mono_class_from_mono_type (t);
6371 if (inflated)
6372 mono_metadata_free_type (t);
6373 return ret;
6377 * mono_bounded_array_class_get:
6378 * @element_class: element class
6379 * @rank: the dimension of the array class
6380 * @bounded: whenever the array has non-zero bounds
6382 * Returns: a class object describing the array with element type @element_type and
6383 * dimension @rank.
6385 MonoClass *
6386 mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
6388 MonoImage *image;
6389 MonoClass *class;
6390 MonoClass *parent = NULL;
6391 GSList *list, *rootlist = NULL;
6392 int nsize;
6393 char *name;
6394 gboolean corlib_type = FALSE;
6396 g_assert (rank <= 255);
6398 if (rank > 1)
6399 /* bounded only matters for one-dimensional arrays */
6400 bounded = FALSE;
6402 image = eclass->image;
6404 if (rank == 1 && !bounded) {
6406 * This case is very frequent not just during compilation because of calls
6407 * from mono_class_from_mono_type (), mono_array_new (),
6408 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
6410 EnterCriticalSection (&image->szarray_cache_lock);
6411 if (!image->szarray_cache)
6412 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6413 class = g_hash_table_lookup (image->szarray_cache, eclass);
6414 LeaveCriticalSection (&image->szarray_cache_lock);
6415 if (class)
6416 return class;
6418 mono_loader_lock ();
6419 } else {
6420 mono_loader_lock ();
6422 if (!image->array_cache)
6423 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6425 if ((rootlist = list = g_hash_table_lookup (image->array_cache, eclass))) {
6426 for (; list; list = list->next) {
6427 class = list->data;
6428 if ((class->rank == rank) && (class->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
6429 mono_loader_unlock ();
6430 return class;
6436 /* for the building corlib use System.Array from it */
6437 if (image->assembly && image->assembly->dynamic && image->assembly_name && strcmp (image->assembly_name, "mscorlib") == 0) {
6438 parent = mono_class_from_name (image, "System", "Array");
6439 corlib_type = TRUE;
6440 } else {
6441 parent = mono_defaults.array_class;
6442 if (!parent->inited)
6443 mono_class_init (parent);
6446 class = mono_image_alloc0 (image, sizeof (MonoClass));
6448 class->image = image;
6449 class->name_space = eclass->name_space;
6450 nsize = strlen (eclass->name);
6451 name = g_malloc (nsize + 2 + rank + 1);
6452 memcpy (name, eclass->name, nsize);
6453 name [nsize] = '[';
6454 if (rank > 1)
6455 memset (name + nsize + 1, ',', rank - 1);
6456 if (bounded)
6457 name [nsize + rank] = '*';
6458 name [nsize + rank + bounded] = ']';
6459 name [nsize + rank + bounded + 1] = 0;
6460 class->name = mono_image_strdup (image, name);
6461 g_free (name);
6463 mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
6465 classes_size += sizeof (MonoClass);
6467 class->type_token = 0;
6468 /* all arrays are marked serializable and sealed, bug #42779 */
6469 class->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC;
6470 class->parent = parent;
6471 class->instance_size = mono_class_instance_size (class->parent);
6473 if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
6474 /*Arrays of those two types are invalid.*/
6475 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
6476 } else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
6477 if (!eclass->ref_info_handle || eclass->wastypebuilder) {
6478 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
6479 g_assert (eclass->ref_info_handle && !eclass->wastypebuilder);
6481 /* element_size -1 is ok as this is not an instantitable type*/
6482 class->sizes.element_size = -1;
6483 } else
6484 class->sizes.element_size = mono_class_array_element_size (eclass);
6486 mono_class_setup_supertypes (class);
6488 if (eclass->generic_class)
6489 mono_class_init (eclass);
6490 if (!eclass->size_inited)
6491 mono_class_setup_fields (eclass);
6492 if (eclass->exception_type) /*FIXME we fail the array type, but we have to let other fields be set.*/
6493 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
6495 class->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
6497 class->rank = rank;
6499 if (eclass->enumtype)
6500 class->cast_class = eclass->element_class;
6501 else
6502 class->cast_class = eclass;
6504 switch (class->cast_class->byval_arg.type) {
6505 case MONO_TYPE_I1:
6506 class->cast_class = mono_defaults.byte_class;
6507 break;
6508 case MONO_TYPE_U2:
6509 class->cast_class = mono_defaults.int16_class;
6510 break;
6511 case MONO_TYPE_U4:
6512 #if SIZEOF_VOID_P == 4
6513 case MONO_TYPE_I:
6514 case MONO_TYPE_U:
6515 #endif
6516 class->cast_class = mono_defaults.int32_class;
6517 break;
6518 case MONO_TYPE_U8:
6519 #if SIZEOF_VOID_P == 8
6520 case MONO_TYPE_I:
6521 case MONO_TYPE_U:
6522 #endif
6523 class->cast_class = mono_defaults.int64_class;
6524 break;
6527 class->element_class = eclass;
6529 if ((rank > 1) || bounded) {
6530 MonoArrayType *at = mono_image_alloc0 (image, sizeof (MonoArrayType));
6531 class->byval_arg.type = MONO_TYPE_ARRAY;
6532 class->byval_arg.data.array = at;
6533 at->eklass = eclass;
6534 at->rank = rank;
6535 /* FIXME: complete.... */
6536 } else {
6537 class->byval_arg.type = MONO_TYPE_SZARRAY;
6538 class->byval_arg.data.klass = eclass;
6540 class->this_arg = class->byval_arg;
6541 class->this_arg.byref = 1;
6542 if (corlib_type) {
6543 class->inited = 1;
6546 class->generic_container = eclass->generic_container;
6548 if (rank == 1 && !bounded) {
6549 MonoClass *prev_class;
6551 EnterCriticalSection (&image->szarray_cache_lock);
6552 prev_class = g_hash_table_lookup (image->szarray_cache, eclass);
6553 if (prev_class)
6554 /* Someone got in before us */
6555 class = prev_class;
6556 else
6557 g_hash_table_insert (image->szarray_cache, eclass, class);
6558 LeaveCriticalSection (&image->szarray_cache_lock);
6559 } else {
6560 list = g_slist_append (rootlist, class);
6561 g_hash_table_insert (image->array_cache, eclass, list);
6564 mono_loader_unlock ();
6566 mono_profiler_class_loaded (class, MONO_PROFILE_OK);
6568 return class;
6572 * mono_array_class_get:
6573 * @element_class: element class
6574 * @rank: the dimension of the array class
6576 * Returns: a class object describing the array with element type @element_type and
6577 * dimension @rank.
6579 MonoClass *
6580 mono_array_class_get (MonoClass *eclass, guint32 rank)
6582 return mono_bounded_array_class_get (eclass, rank, FALSE);
6586 * mono_class_instance_size:
6587 * @klass: a class
6589 * Returns: the size of an object instance
6591 gint32
6592 mono_class_instance_size (MonoClass *klass)
6594 if (!klass->size_inited)
6595 mono_class_init (klass);
6597 return klass->instance_size;
6601 * mono_class_min_align:
6602 * @klass: a class
6604 * Returns: minimm alignment requirements
6606 gint32
6607 mono_class_min_align (MonoClass *klass)
6609 if (!klass->size_inited)
6610 mono_class_init (klass);
6612 return klass->min_align;
6616 * mono_class_value_size:
6617 * @klass: a class
6619 * This function is used for value types, and return the
6620 * space and the alignment to store that kind of value object.
6622 * Returns: the size of a value of kind @klass
6624 gint32
6625 mono_class_value_size (MonoClass *klass, guint32 *align)
6627 gint32 size;
6629 /* fixme: check disable, because we still have external revereces to
6630 * mscorlib and Dummy Objects
6632 /*g_assert (klass->valuetype);*/
6634 size = mono_class_instance_size (klass) - sizeof (MonoObject);
6636 if (align)
6637 *align = klass->min_align;
6639 return size;
6643 * mono_class_data_size:
6644 * @klass: a class
6646 * Returns: the size of the static class data
6648 gint32
6649 mono_class_data_size (MonoClass *klass)
6651 if (!klass->inited)
6652 mono_class_init (klass);
6653 /* This can happen with dynamically created types */
6654 if (!klass->fields_inited)
6655 mono_class_setup_fields_locking (klass);
6657 /* in arrays, sizes.class_size is unioned with element_size
6658 * and arrays have no static fields
6660 if (klass->rank)
6661 return 0;
6662 return klass->sizes.class_size;
6666 * Auxiliary routine to mono_class_get_field
6668 * Takes a field index instead of a field token.
6670 static MonoClassField *
6671 mono_class_get_field_idx (MonoClass *class, int idx)
6673 mono_class_setup_fields_locking (class);
6674 if (class->exception_type)
6675 return NULL;
6677 while (class) {
6678 if (class->image->uncompressed_metadata) {
6680 * class->field.first points to the FieldPtr table, while idx points into the
6681 * Field table, so we have to do a search.
6683 /*FIXME this is broken for types with multiple fields with the same name.*/
6684 const char *name = mono_metadata_string_heap (class->image, mono_metadata_decode_row_col (&class->image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
6685 int i;
6687 for (i = 0; i < class->field.count; ++i)
6688 if (mono_field_get_name (&class->fields [i]) == name)
6689 return &class->fields [i];
6690 g_assert_not_reached ();
6691 } else {
6692 if (class->field.count) {
6693 if ((idx >= class->field.first) && (idx < class->field.first + class->field.count)){
6694 return &class->fields [idx - class->field.first];
6698 class = class->parent;
6700 return NULL;
6704 * mono_class_get_field:
6705 * @class: the class to lookup the field.
6706 * @field_token: the field token
6708 * Returns: A MonoClassField representing the type and offset of
6709 * the field, or a NULL value if the field does not belong to this
6710 * class.
6712 MonoClassField *
6713 mono_class_get_field (MonoClass *class, guint32 field_token)
6715 int idx = mono_metadata_token_index (field_token);
6717 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
6719 return mono_class_get_field_idx (class, idx - 1);
6723 * mono_class_get_field_from_name:
6724 * @klass: the class to lookup the field.
6725 * @name: the field name
6727 * Search the class @klass and it's parents for a field with the name @name.
6729 * Returns: the MonoClassField pointer of the named field or NULL
6731 MonoClassField *
6732 mono_class_get_field_from_name (MonoClass *klass, const char *name)
6734 return mono_class_get_field_from_name_full (klass, name, NULL);
6738 * mono_class_get_field_from_name_full:
6739 * @klass: the class to lookup the field.
6740 * @name: the field name
6741 * @type: the type of the fields. This optional.
6743 * Search the class @klass and it's parents for a field with the name @name and type @type.
6745 * If @klass is an inflated generic type, the type comparison is done with the equivalent field
6746 * of its generic type definition.
6748 * Returns: the MonoClassField pointer of the named field or NULL
6750 MonoClassField *
6751 mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
6753 int i;
6755 mono_class_setup_fields_locking (klass);
6756 if (klass->exception_type)
6757 return NULL;
6759 while (klass) {
6760 for (i = 0; i < klass->field.count; ++i) {
6761 MonoClassField *field = &klass->fields [i];
6763 if (strcmp (name, mono_field_get_name (field)) != 0)
6764 continue;
6766 if (type) {
6767 MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
6768 if (!mono_metadata_type_equal_full (type, field_type, TRUE))
6769 continue;
6771 return field;
6773 klass = klass->parent;
6775 return NULL;
6779 * mono_class_get_field_token:
6780 * @field: the field we need the token of
6782 * Get the token of a field. Note that the tokesn is only valid for the image
6783 * the field was loaded from. Don't use this function for fields in dynamic types.
6785 * Returns: the token representing the field in the image it was loaded from.
6787 guint32
6788 mono_class_get_field_token (MonoClassField *field)
6790 MonoClass *klass = field->parent;
6791 int i;
6793 mono_class_setup_fields_locking (klass);
6795 while (klass) {
6796 if (!klass->fields)
6797 return 0;
6798 for (i = 0; i < klass->field.count; ++i) {
6799 if (&klass->fields [i] == field) {
6800 int idx = klass->field.first + i + 1;
6802 if (klass->image->uncompressed_metadata)
6803 idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx);
6804 return mono_metadata_make_token (MONO_TABLE_FIELD, idx);
6807 klass = klass->parent;
6810 g_assert_not_reached ();
6811 return 0;
6814 static int
6815 mono_field_get_index (MonoClassField *field)
6817 int index = field - field->parent->fields;
6819 g_assert (index >= 0 && index < field->parent->field.count);
6821 return index;
6825 * mono_class_get_field_default_value:
6827 * Return the default value of the field as a pointer into the metadata blob.
6829 const char*
6830 mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
6832 guint32 cindex;
6833 guint32 constant_cols [MONO_CONSTANT_SIZE];
6834 int field_index;
6835 MonoClass *klass = field->parent;
6837 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
6839 if (!klass->ext || !klass->ext->field_def_values) {
6840 mono_loader_lock ();
6841 mono_class_alloc_ext (klass);
6842 if (!klass->ext->field_def_values)
6843 klass->ext->field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
6844 mono_loader_unlock ();
6847 field_index = mono_field_get_index (field);
6849 if (!klass->ext->field_def_values [field_index].data) {
6850 cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
6851 if (!cindex)
6852 return NULL;
6854 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
6856 mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
6857 klass->ext->field_def_values [field_index].def_type = constant_cols [MONO_CONSTANT_TYPE];
6858 klass->ext->field_def_values [field_index].data = (gpointer)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
6861 *def_type = klass->ext->field_def_values [field_index].def_type;
6862 return klass->ext->field_def_values [field_index].data;
6865 static int
6866 mono_property_get_index (MonoProperty *prop)
6868 int index = prop - prop->parent->ext->properties;
6870 g_assert (index >= 0 && index < prop->parent->ext->property.count);
6872 return index;
6876 * mono_class_get_property_default_value:
6878 * Return the default value of the field as a pointer into the metadata blob.
6880 const char*
6881 mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type)
6883 guint32 cindex;
6884 guint32 constant_cols [MONO_CONSTANT_SIZE];
6885 MonoClass *klass = property->parent;
6887 g_assert (property->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT);
6889 * We don't cache here because it is not used by C# so it's quite rare, but
6890 * we still do the lookup in klass->ext because that is where the data
6891 * is stored for dynamic assemblies.
6894 if (klass->image->dynamic) {
6895 int prop_index = mono_property_get_index (property);
6896 if (klass->ext->prop_def_values && klass->ext->prop_def_values [prop_index].data) {
6897 *def_type = klass->ext->prop_def_values [prop_index].def_type;
6898 return klass->ext->prop_def_values [prop_index].data;
6900 return NULL;
6902 cindex = mono_metadata_get_constant_index (klass->image, mono_class_get_property_token (property), 0);
6903 if (!cindex)
6904 return NULL;
6906 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
6907 *def_type = constant_cols [MONO_CONSTANT_TYPE];
6908 return (gpointer)mono_metadata_blob_heap (klass->image, constant_cols [MONO_CONSTANT_VALUE]);
6911 guint32
6912 mono_class_get_event_token (MonoEvent *event)
6914 MonoClass *klass = event->parent;
6915 int i;
6917 while (klass) {
6918 if (klass->ext) {
6919 for (i = 0; i < klass->ext->event.count; ++i) {
6920 if (&klass->ext->events [i] == event)
6921 return mono_metadata_make_token (MONO_TABLE_EVENT, klass->ext->event.first + i + 1);
6924 klass = klass->parent;
6927 g_assert_not_reached ();
6928 return 0;
6931 MonoProperty*
6932 mono_class_get_property_from_name (MonoClass *klass, const char *name)
6934 while (klass) {
6935 MonoProperty* p;
6936 gpointer iter = NULL;
6937 while ((p = mono_class_get_properties (klass, &iter))) {
6938 if (! strcmp (name, p->name))
6939 return p;
6941 klass = klass->parent;
6943 return NULL;
6946 guint32
6947 mono_class_get_property_token (MonoProperty *prop)
6949 MonoClass *klass = prop->parent;
6950 while (klass) {
6951 MonoProperty* p;
6952 int i = 0;
6953 gpointer iter = NULL;
6954 while ((p = mono_class_get_properties (klass, &iter))) {
6955 if (&klass->ext->properties [i] == prop)
6956 return mono_metadata_make_token (MONO_TABLE_PROPERTY, klass->ext->property.first + i + 1);
6958 i ++;
6960 klass = klass->parent;
6963 g_assert_not_reached ();
6964 return 0;
6967 char *
6968 mono_class_name_from_token (MonoImage *image, guint32 type_token)
6970 const char *name, *nspace;
6971 if (image->dynamic)
6972 return g_strdup_printf ("DynamicType 0x%08x", type_token);
6974 switch (type_token & 0xff000000){
6975 case MONO_TOKEN_TYPE_DEF: {
6976 guint32 cols [MONO_TYPEDEF_SIZE];
6977 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
6978 guint tidx = mono_metadata_token_index (type_token);
6980 if (tidx > tt->rows)
6981 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
6983 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
6984 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
6985 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
6986 if (strlen (nspace) == 0)
6987 return g_strdup_printf ("%s", name);
6988 else
6989 return g_strdup_printf ("%s.%s", nspace, name);
6992 case MONO_TOKEN_TYPE_REF: {
6993 MonoError error;
6994 guint32 cols [MONO_TYPEREF_SIZE];
6995 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
6996 guint tidx = mono_metadata_token_index (type_token);
6998 if (tidx > t->rows)
6999 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7001 if (!mono_verifier_verify_typeref_row (image, tidx - 1, &error)) {
7002 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7003 mono_error_cleanup (&error);
7004 return msg;
7007 mono_metadata_decode_row (t, tidx-1, cols, MONO_TYPEREF_SIZE);
7008 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
7009 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
7010 if (strlen (nspace) == 0)
7011 return g_strdup_printf ("%s", name);
7012 else
7013 return g_strdup_printf ("%s.%s", nspace, name);
7016 case MONO_TOKEN_TYPE_SPEC:
7017 return g_strdup_printf ("Typespec 0x%08x", type_token);
7018 default:
7019 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7023 static char *
7024 mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
7026 if (image->dynamic)
7027 return g_strdup_printf ("DynamicAssembly %s", image->name);
7029 switch (type_token & 0xff000000){
7030 case MONO_TOKEN_TYPE_DEF:
7031 if (image->assembly)
7032 return mono_stringify_assembly_name (&image->assembly->aname);
7033 else if (image->assembly_name)
7034 return g_strdup (image->assembly_name);
7035 return g_strdup_printf ("%s", image->name ? image->name : "[Could not resolve assembly name");
7036 case MONO_TOKEN_TYPE_REF: {
7037 MonoError error;
7038 MonoAssemblyName aname;
7039 guint32 cols [MONO_TYPEREF_SIZE];
7040 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
7041 guint32 idx = mono_metadata_token_index (type_token);
7043 if (idx > t->rows)
7044 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7046 if (!mono_verifier_verify_typeref_row (image, idx - 1, &error)) {
7047 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7048 mono_error_cleanup (&error);
7049 return msg;
7051 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
7053 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLTION_SCOPE_BITS;
7054 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLTION_SCOPE_MASK) {
7055 case MONO_RESOLTION_SCOPE_MODULE:
7056 /* FIXME: */
7057 return g_strdup ("");
7058 case MONO_RESOLTION_SCOPE_MODULEREF:
7059 /* FIXME: */
7060 return g_strdup ("");
7061 case MONO_RESOLTION_SCOPE_TYPEREF:
7062 /* FIXME: */
7063 return g_strdup ("");
7064 case MONO_RESOLTION_SCOPE_ASSEMBLYREF:
7065 mono_assembly_get_assemblyref (image, idx - 1, &aname);
7066 return mono_stringify_assembly_name (&aname);
7067 default:
7068 g_assert_not_reached ();
7070 break;
7072 case MONO_TOKEN_TYPE_SPEC:
7073 /* FIXME: */
7074 return g_strdup ("");
7075 default:
7076 g_assert_not_reached ();
7079 return NULL;
7083 * mono_class_get_full:
7084 * @image: the image where the class resides
7085 * @type_token: the token for the class
7086 * @context: the generic context used to evaluate generic instantiations in
7088 * Returns: the MonoClass that represents @type_token in @image
7090 MonoClass *
7091 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
7093 MonoError error;
7094 MonoClass *class = NULL;
7096 if (image->dynamic) {
7097 int table = mono_metadata_token_table (type_token);
7099 if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
7100 mono_loader_set_error_bad_image (g_strdup ("Bad type token."));
7101 return NULL;
7103 return mono_lookup_dynamic_token (image, type_token, context);
7106 switch (type_token & 0xff000000){
7107 case MONO_TOKEN_TYPE_DEF:
7108 class = mono_class_create_from_typedef (image, type_token, &error);
7109 if (!mono_error_ok (&error)) {
7110 mono_loader_set_error_from_mono_error (&error);
7111 /*FIXME don't swallow the error message*/
7112 mono_error_cleanup (&error);
7113 return NULL;
7115 break;
7116 case MONO_TOKEN_TYPE_REF:
7117 class = mono_class_from_typeref (image, type_token);
7118 break;
7119 case MONO_TOKEN_TYPE_SPEC:
7120 class = mono_class_create_from_typespec (image, type_token, context, &error);
7121 if (!mono_error_ok (&error)) {
7122 /*FIXME don't swallow the error message*/
7123 mono_error_cleanup (&error);
7125 break;
7126 default:
7127 g_warning ("unknown token type %x", type_token & 0xff000000);
7128 g_assert_not_reached ();
7131 if (!class){
7132 char *name = mono_class_name_from_token (image, type_token);
7133 char *assembly = mono_assembly_name_from_token (image, type_token);
7134 mono_loader_set_error_type_load (name, assembly);
7135 g_free (name);
7136 g_free (assembly);
7139 return class;
7144 * mono_type_get_full:
7145 * @image: the image where the type resides
7146 * @type_token: the token for the type
7147 * @context: the generic context used to evaluate generic instantiations in
7149 * This functions exists to fullfill the fact that sometimes it's desirable to have access to the
7151 * Returns: the MonoType that represents @type_token in @image
7153 MonoType *
7154 mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
7156 MonoError error;
7157 MonoType *type = NULL;
7158 gboolean inflated = FALSE;
7160 //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
7161 if (image->dynamic)
7162 return mono_class_get_type (mono_lookup_dynamic_token (image, type_token, context));
7164 if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
7165 MonoClass *class = mono_class_get_full (image, type_token, context);
7166 return class ? mono_class_get_type (class) : NULL;
7169 type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, &error);
7171 if (!mono_error_ok (&error)) {
7172 /*FIXME don't swalloc the error message.*/
7173 char *name = mono_class_name_from_token (image, type_token);
7174 char *assembly = mono_assembly_name_from_token (image, type_token);
7176 g_warning ("Error loading type %s from %s due to %s", name, assembly, mono_error_get_message (&error));
7178 mono_error_cleanup (&error);
7179 mono_loader_set_error_type_load (name, assembly);
7180 return NULL;
7183 if (inflated) {
7184 MonoType *tmp = type;
7185 type = mono_class_get_type (mono_class_from_mono_type (type));
7186 /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
7187 * A MonoClass::byval_arg of a generic type definion has type CLASS.
7188 * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with byval_arg.
7190 * The long term solution is to chaise this places and make then set MonoType::type correctly.
7191 * */
7192 if (type->type != tmp->type)
7193 type = tmp;
7194 else
7195 mono_metadata_free_type (tmp);
7197 return type;
7201 MonoClass *
7202 mono_class_get (MonoImage *image, guint32 type_token)
7204 return mono_class_get_full (image, type_token, NULL);
7208 * mono_image_init_name_cache:
7210 * Initializes the class name cache stored in image->name_cache.
7212 * LOCKING: Acquires the corresponding image lock.
7214 void
7215 mono_image_init_name_cache (MonoImage *image)
7217 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7218 guint32 cols [MONO_TYPEDEF_SIZE];
7219 const char *name;
7220 const char *nspace;
7221 guint32 i, visib, nspace_index;
7222 GHashTable *name_cache2, *nspace_table;
7224 mono_image_lock (image);
7226 if (image->name_cache) {
7227 mono_image_unlock (image);
7228 return;
7231 image->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
7233 if (image->dynamic) {
7234 mono_image_unlock (image);
7235 return;
7238 /* Temporary hash table to avoid lookups in the nspace_table */
7239 name_cache2 = g_hash_table_new (NULL, NULL);
7241 for (i = 1; i <= t->rows; ++i) {
7242 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7243 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7245 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7246 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7248 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7249 continue;
7250 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7251 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7253 nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
7254 nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7255 if (!nspace_table) {
7256 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7257 g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
7258 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7259 nspace_table);
7261 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
7264 /* Load type names from EXPORTEDTYPES table */
7266 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7267 guint32 cols [MONO_EXP_TYPE_SIZE];
7268 int i;
7270 for (i = 0; i < t->rows; ++i) {
7271 mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
7272 name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
7273 nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
7275 nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
7276 nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7277 if (!nspace_table) {
7278 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7279 g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
7280 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7281 nspace_table);
7283 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
7287 g_hash_table_destroy (name_cache2);
7288 mono_image_unlock (image);
7291 /*FIXME Only dynamic assemblies should allow this operation.*/
7292 void
7293 mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
7294 const char *name, guint32 index)
7296 GHashTable *nspace_table;
7297 GHashTable *name_cache;
7298 guint32 old_index;
7300 mono_image_lock (image);
7302 if (!image->name_cache)
7303 mono_image_init_name_cache (image);
7305 name_cache = image->name_cache;
7306 if (!(nspace_table = g_hash_table_lookup (name_cache, nspace))) {
7307 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7308 g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
7311 if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
7312 g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
7314 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
7316 mono_image_unlock (image);
7319 typedef struct {
7320 gconstpointer key;
7321 gpointer value;
7322 } FindUserData;
7324 static void
7325 find_nocase (gpointer key, gpointer value, gpointer user_data)
7327 char *name = (char*)key;
7328 FindUserData *data = (FindUserData*)user_data;
7330 if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
7331 data->value = value;
7335 * mono_class_from_name_case:
7336 * @image: The MonoImage where the type is looked up in
7337 * @name_space: the type namespace
7338 * @name: the type short name.
7340 * Obtains a MonoClass with a given namespace and a given name which
7341 * is located in the given MonoImage. The namespace and name
7342 * lookups are case insensitive.
7344 MonoClass *
7345 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
7347 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7348 guint32 cols [MONO_TYPEDEF_SIZE];
7349 const char *n;
7350 const char *nspace;
7351 guint32 i, visib;
7353 if (image->dynamic) {
7354 guint32 token = 0;
7355 FindUserData user_data;
7357 mono_image_lock (image);
7359 if (!image->name_cache)
7360 mono_image_init_name_cache (image);
7362 user_data.key = name_space;
7363 user_data.value = NULL;
7364 g_hash_table_foreach (image->name_cache, find_nocase, &user_data);
7366 if (user_data.value) {
7367 GHashTable *nspace_table = (GHashTable*)user_data.value;
7369 user_data.key = name;
7370 user_data.value = NULL;
7372 g_hash_table_foreach (nspace_table, find_nocase, &user_data);
7374 if (user_data.value)
7375 token = GPOINTER_TO_UINT (user_data.value);
7378 mono_image_unlock (image);
7380 if (token)
7381 return mono_class_get (image, MONO_TOKEN_TYPE_DEF | token);
7382 else
7383 return NULL;
7387 /* add a cache if needed */
7388 for (i = 1; i <= t->rows; ++i) {
7389 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7390 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7392 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7393 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7395 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7396 continue;
7397 n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7398 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7399 if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
7400 return mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
7402 return NULL;
7405 static MonoClass*
7406 return_nested_in (MonoClass *class, char *nested)
7408 MonoClass *found;
7409 char *s = strchr (nested, '/');
7410 gpointer iter = NULL;
7412 if (s) {
7413 *s = 0;
7414 s++;
7417 while ((found = mono_class_get_nested_types (class, &iter))) {
7418 if (strcmp (found->name, nested) == 0) {
7419 if (s)
7420 return return_nested_in (found, s);
7421 return found;
7424 return NULL;
7427 static MonoClass*
7428 search_modules (MonoImage *image, const char *name_space, const char *name)
7430 MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
7431 MonoImage *file_image;
7432 MonoClass *class;
7433 int i;
7436 * The EXPORTEDTYPES table only contains public types, so have to search the
7437 * modules as well.
7438 * Note: image->modules contains the contents of the MODULEREF table, while
7439 * the real module list is in the FILE table.
7441 for (i = 0; i < file_table->rows; i++) {
7442 guint32 cols [MONO_FILE_SIZE];
7443 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
7444 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
7445 continue;
7447 file_image = mono_image_load_file_for_image (image, i + 1);
7448 if (file_image) {
7449 class = mono_class_from_name (file_image, name_space, name);
7450 if (class)
7451 return class;
7455 return NULL;
7459 * mono_class_from_name:
7460 * @image: The MonoImage where the type is looked up in
7461 * @name_space: the type namespace
7462 * @name: the type short name.
7464 * Obtains a MonoClass with a given namespace and a given name which
7465 * is located in the given MonoImage.
7467 * To reference nested classes, use the "/" character as a separator.
7468 * For example use "Foo/Bar" to reference the class Bar that is nested
7469 * inside Foo, like this: "class Foo { class Bar {} }".
7471 MonoClass *
7472 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
7474 GHashTable *nspace_table;
7475 MonoImage *loaded_image;
7476 guint32 token = 0;
7477 int i;
7478 MonoClass *class;
7479 char *nested;
7480 char buf [1024];
7482 if ((nested = strchr (name, '/'))) {
7483 int pos = nested - name;
7484 int len = strlen (name);
7485 if (len > 1023)
7486 return NULL;
7487 memcpy (buf, name, len + 1);
7488 buf [pos] = 0;
7489 nested = buf + pos + 1;
7490 name = buf;
7493 /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */
7494 if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
7495 gboolean res = get_class_from_name (image, name_space, name, &class);
7496 if (res) {
7497 if (!class)
7498 class = search_modules (image, name_space, name);
7499 if (nested)
7500 return class ? return_nested_in (class, nested) : NULL;
7501 else
7502 return class;
7506 mono_image_lock (image);
7508 if (!image->name_cache)
7509 mono_image_init_name_cache (image);
7511 nspace_table = g_hash_table_lookup (image->name_cache, name_space);
7513 if (nspace_table)
7514 token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
7516 mono_image_unlock (image);
7518 if (!token && image->dynamic && image->modules) {
7519 /* Search modules as well */
7520 for (i = 0; i < image->module_count; ++i) {
7521 MonoImage *module = image->modules [i];
7523 class = mono_class_from_name (module, name_space, name);
7524 if (class)
7525 return class;
7529 if (!token) {
7530 class = search_modules (image, name_space, name);
7531 if (class)
7532 return class;
7535 if (!token)
7536 return NULL;
7538 if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
7539 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7540 guint32 cols [MONO_EXP_TYPE_SIZE];
7541 guint32 idx, impl;
7543 idx = mono_metadata_token_index (token);
7545 mono_metadata_decode_row (t, idx - 1, cols, MONO_EXP_TYPE_SIZE);
7547 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
7548 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
7549 loaded_image = mono_assembly_load_module (image->assembly, impl >> MONO_IMPLEMENTATION_BITS);
7550 if (!loaded_image)
7551 return NULL;
7552 class = mono_class_from_name (loaded_image, name_space, name);
7553 if (nested)
7554 return return_nested_in (class, nested);
7555 return class;
7556 } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
7557 guint32 assembly_idx;
7559 assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
7561 mono_assembly_load_reference (image, assembly_idx - 1);
7562 g_assert (image->references [assembly_idx - 1]);
7563 if (image->references [assembly_idx - 1] == (gpointer)-1)
7564 return NULL;
7565 else
7566 /* FIXME: Cycle detection */
7567 return mono_class_from_name (image->references [assembly_idx - 1]->image, name_space, name);
7568 } else {
7569 g_error ("not yet implemented");
7573 token = MONO_TOKEN_TYPE_DEF | token;
7575 class = mono_class_get (image, token);
7576 if (nested)
7577 return return_nested_in (class, nested);
7578 return class;
7582 * mono_class_is_subclass_of:
7583 * @klass: class to probe if it is a subclass of another one
7584 * @klassc: the class we suspect is the base class
7585 * @check_interfaces: whether we should perform interface checks
7587 * This method determines whether @klass is a subclass of @klassc.
7589 * If the @check_interfaces flag is set, then if @klassc is an interface
7590 * this method return true if the @klass implements the interface or
7591 * if @klass is an interface, if one of its base classes is @klass.
7593 * If @check_interfaces is false then, then if @klass is not an interface
7594 * then it returns true if the @klass is a subclass of @klassc.
7596 * if @klass is an interface and @klassc is System.Object, then this function
7597 * return true.
7600 gboolean
7601 mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
7602 gboolean check_interfaces)
7604 /*FIXME test for interfaces with variant generic arguments*/
7606 if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
7607 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
7608 return TRUE;
7609 } else if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && MONO_CLASS_IS_INTERFACE (klass)) {
7610 int i;
7612 for (i = 0; i < klass->interface_count; i ++) {
7613 MonoClass *ic = klass->interfaces [i];
7614 if (ic == klassc)
7615 return TRUE;
7617 } else {
7618 if (!MONO_CLASS_IS_INTERFACE (klass) && mono_class_has_parent (klass, klassc))
7619 return TRUE;
7623 * MS.NET thinks interfaces are a subclass of Object, so we think it as
7624 * well.
7626 if (klassc == mono_defaults.object_class)
7627 return TRUE;
7629 return FALSE;
7632 static gboolean
7633 mono_type_is_generic_argument (MonoType *type)
7635 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
7638 gboolean
7639 mono_class_has_variant_generic_params (MonoClass *klass)
7641 int i;
7642 MonoGenericContainer *container;
7644 if (!klass->generic_class)
7645 return FALSE;
7647 container = klass->generic_class->container_class->generic_container;
7649 for (i = 0; i < container->type_argc; ++i)
7650 if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
7651 return TRUE;
7653 return FALSE;
7656 static gboolean
7657 mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
7659 if (target == candidate)
7660 return TRUE;
7662 if (check_for_reference_conv &&
7663 mono_type_is_generic_argument (&target->byval_arg) &&
7664 mono_type_is_generic_argument (&candidate->byval_arg)) {
7665 MonoGenericParam *gparam = candidate->byval_arg.data.generic_param;
7666 MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
7668 if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
7669 return FALSE;
7671 if (!mono_class_is_assignable_from (target, candidate))
7672 return FALSE;
7673 return TRUE;
7677 * @container the generic container from the GTD
7678 * @klass: the class to be assigned to
7679 * @oklass: the source class
7681 * Both klass and oklass must be instances of the same generic interface.
7682 * Return true if @klass can be assigned to a @klass variable
7684 gboolean
7685 mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
7687 int j;
7688 MonoType **klass_argv, **oklass_argv;
7689 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
7690 MonoGenericContainer *container = klass_gtd->generic_container;
7692 if (klass == oklass)
7693 return TRUE;
7695 /*Viable candidates are instances of the same generic interface*/
7696 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
7697 return FALSE;
7699 klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
7700 oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
7702 for (j = 0; j < container->type_argc; ++j) {
7703 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
7704 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
7706 if (param1_class->valuetype != param2_class->valuetype || (param1_class->valuetype && param1_class != param2_class))
7707 return FALSE;
7710 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
7711 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
7713 if (param1_class != param2_class) {
7714 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
7715 if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
7716 return FALSE;
7717 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
7718 if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
7719 return FALSE;
7720 } else
7721 return FALSE;
7724 return TRUE;
7727 static gboolean
7728 mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
7730 MonoGenericParam *gparam, *ogparam;
7731 MonoGenericParamInfo *tinfo, *cinfo;
7732 MonoClass **candidate_class;
7733 gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
7734 int tmask, cmask;
7736 if (target == candidate)
7737 return TRUE;
7738 if (target->byval_arg.type != candidate->byval_arg.type)
7739 return FALSE;
7741 gparam = target->byval_arg.data.generic_param;
7742 ogparam = candidate->byval_arg.data.generic_param;
7743 tinfo = mono_generic_param_info (gparam);
7744 cinfo = mono_generic_param_info (ogparam);
7746 class_constraint_satisfied = FALSE;
7747 valuetype_constraint_satisfied = FALSE;
7749 /*candidate must have a super set of target's special constraints*/
7750 tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
7751 cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
7753 if (cinfo->constraints) {
7754 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
7755 MonoClass *cc = *candidate_class;
7757 if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
7758 class_constraint_satisfied = TRUE;
7759 else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
7760 valuetype_constraint_satisfied = TRUE;
7763 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
7764 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
7766 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
7767 return FALSE;
7768 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
7769 return FALSE;
7770 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
7771 valuetype_constraint_satisfied)) {
7772 return FALSE;
7776 /*candidate type constraints must be a superset of target's*/
7777 if (tinfo->constraints) {
7778 MonoClass **target_class;
7779 for (target_class = tinfo->constraints; *target_class; ++target_class) {
7780 MonoClass *tc = *target_class;
7783 * A constraint from @target might inflate into @candidate itself and in that case we don't need
7784 * check it's constraints since it satisfy the constraint by itself.
7786 if (mono_metadata_type_equal (&tc->byval_arg, &candidate->byval_arg))
7787 continue;
7789 if (!cinfo->constraints)
7790 return FALSE;
7792 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
7793 MonoClass *cc = *candidate_class;
7795 if (mono_class_is_assignable_from (tc, cc))
7796 break;
7799 * This happens when we have the following:
7801 * Bar<K> where K : IFace
7802 * Foo<T, U> where T : U where U : IFace
7803 * ...
7804 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
7807 if (mono_type_is_generic_argument (&cc->byval_arg)) {
7808 if (mono_gparam_is_assignable_from (target, cc))
7809 break;
7812 if (!*candidate_class)
7813 return FALSE;
7817 /*candidate itself must have a constraint that satisfy target*/
7818 if (cinfo->constraints) {
7819 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
7820 MonoClass *cc = *candidate_class;
7821 if (mono_class_is_assignable_from (target, cc))
7822 return TRUE;
7825 return FALSE;
7829 * mono_class_is_assignable_from:
7830 * @klass: the class to be assigned to
7831 * @oklass: the source class
7833 * Return: true if an instance of object oklass can be assigned to an
7834 * instance of object @klass
7836 gboolean
7837 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
7839 /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
7840 if (!klass->inited)
7841 mono_class_init (klass);
7843 if (!oklass->inited)
7844 mono_class_init (oklass);
7846 if (klass->exception_type || oklass->exception_type)
7847 return FALSE;
7849 if (mono_type_is_generic_argument (&klass->byval_arg)) {
7850 if (!mono_type_is_generic_argument (&oklass->byval_arg))
7851 return FALSE;
7852 return mono_gparam_is_assignable_from (klass, oklass);
7855 if (MONO_CLASS_IS_INTERFACE (klass)) {
7856 if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
7857 MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
7858 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
7859 int i;
7861 if (constraints) {
7862 for (i = 0; constraints [i]; ++i) {
7863 if (mono_class_is_assignable_from (klass, constraints [i]))
7864 return TRUE;
7868 return FALSE;
7871 /* interface_offsets might not be set for dynamic classes */
7872 if (oklass->ref_info_handle && !oklass->interface_bitmap)
7874 * oklass might be a generic type parameter but they have
7875 * interface_offsets set.
7877 return mono_reflection_call_is_assignable_to (oklass, klass);
7878 if (!oklass->interface_bitmap)
7879 /* Happens with generic instances of not-yet created dynamic types */
7880 return FALSE;
7881 if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
7882 return TRUE;
7884 if (mono_class_has_variant_generic_params (klass)) {
7885 MonoError error;
7886 int i;
7887 mono_class_setup_interfaces (oklass, &error);
7888 if (!mono_error_ok (&error)) {
7889 mono_error_cleanup (&error);
7890 return FALSE;
7893 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
7894 for (i = 0; i < oklass->interface_offsets_count; ++i) {
7895 MonoClass *iface = oklass->interfaces_packed [i];
7897 if (mono_class_is_variant_compatible (klass, iface, FALSE))
7898 return TRUE;
7901 return FALSE;
7902 } else if (klass->delegate) {
7903 if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE))
7904 return TRUE;
7905 }else if (klass->rank) {
7906 MonoClass *eclass, *eoclass;
7908 if (oklass->rank != klass->rank)
7909 return FALSE;
7911 /* vectors vs. one dimensional arrays */
7912 if (oklass->byval_arg.type != klass->byval_arg.type)
7913 return FALSE;
7915 eclass = klass->cast_class;
7916 eoclass = oklass->cast_class;
7919 * a is b does not imply a[] is b[] when a is a valuetype, and
7920 * b is a reference type.
7923 if (eoclass->valuetype) {
7924 if ((eclass == mono_defaults.enum_class) ||
7925 (eclass == mono_defaults.enum_class->parent) ||
7926 (eclass == mono_defaults.object_class))
7927 return FALSE;
7930 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
7931 } else if (mono_class_is_nullable (klass)) {
7932 if (mono_class_is_nullable (oklass))
7933 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
7934 else
7935 return mono_class_is_assignable_from (klass->cast_class, oklass);
7936 } else if (klass == mono_defaults.object_class)
7937 return TRUE;
7939 return mono_class_has_parent (oklass, klass);
7942 /*Check if @oklass is variant compatible with @klass.*/
7943 static gboolean
7944 mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
7946 int j;
7947 MonoType **klass_argv, **oklass_argv;
7948 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
7949 MonoGenericContainer *container = klass_gtd->generic_container;
7951 /*Viable candidates are instances of the same generic interface*/
7952 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
7953 return FALSE;
7955 klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
7956 oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
7958 for (j = 0; j < container->type_argc; ++j) {
7959 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
7960 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
7962 if (param1_class->valuetype != param2_class->valuetype)
7963 return FALSE;
7966 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
7967 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
7969 if (param1_class != param2_class) {
7970 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
7971 if (!mono_class_is_assignable_from_slow (param1_class, param2_class))
7972 return FALSE;
7973 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
7974 if (!mono_class_is_assignable_from_slow (param2_class, param1_class))
7975 return FALSE;
7976 } else
7977 return FALSE;
7980 return TRUE;
7982 /*Check if @candidate implements the interface @target*/
7983 static gboolean
7984 mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
7986 MonoError error;
7987 int i;
7988 gboolean is_variant = mono_class_has_variant_generic_params (target);
7990 if (is_variant && MONO_CLASS_IS_INTERFACE (candidate)) {
7991 if (mono_class_is_variant_compatible_slow (target, candidate))
7992 return TRUE;
7995 do {
7996 if (candidate == target)
7997 return TRUE;
7999 /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
8000 if (candidate->image->dynamic && !candidate->wastypebuilder) {
8001 MonoReflectionTypeBuilder *tb = mono_class_get_ref_info (candidate);
8002 int j;
8003 if (tb && tb->interfaces) {
8004 for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
8005 MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
8006 MonoClass *iface_class;
8008 /* we can't realize the type here since it can do pretty much anything. */
8009 if (!iface->type)
8010 continue;
8011 iface_class = mono_class_from_mono_type (iface->type);
8012 if (iface_class == target)
8013 return TRUE;
8014 if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class))
8015 return TRUE;
8016 if (mono_class_implement_interface_slow (target, iface_class))
8017 return TRUE;
8020 } else {
8021 /*setup_interfaces don't mono_class_init anything*/
8022 /*FIXME this doesn't handle primitive type arrays.
8023 ICollection<sbyte> x byte [] won't work because candidate->interfaces, for byte[], won't have IList<sbyte>.
8024 A possible way to fix this would be to move that to setup_interfaces from setup_interface_offsets.
8026 mono_class_setup_interfaces (candidate, &error);
8027 if (!mono_error_ok (&error)) {
8028 mono_error_cleanup (&error);
8029 return FALSE;
8032 for (i = 0; i < candidate->interface_count; ++i) {
8033 if (candidate->interfaces [i] == target)
8034 return TRUE;
8036 if (is_variant && mono_class_is_variant_compatible_slow (target, candidate->interfaces [i]))
8037 return TRUE;
8039 if (mono_class_implement_interface_slow (target, candidate->interfaces [i]))
8040 return TRUE;
8043 candidate = candidate->parent;
8044 } while (candidate);
8046 return FALSE;
8050 * Check if @oklass can be assigned to @klass.
8051 * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context.
8053 gboolean
8054 mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
8056 if (candidate == target)
8057 return TRUE;
8058 if (target == mono_defaults.object_class)
8059 return TRUE;
8061 if (mono_class_has_parent (candidate, target))
8062 return TRUE;
8064 /*If target is not an interface there is no need to check them.*/
8065 if (MONO_CLASS_IS_INTERFACE (target))
8066 return mono_class_implement_interface_slow (target, candidate);
8068 if (target->delegate && mono_class_has_variant_generic_params (target))
8069 return mono_class_is_variant_compatible (target, candidate, FALSE);
8071 if (target->rank) {
8072 MonoClass *eclass, *eoclass;
8074 if (target->rank != candidate->rank)
8075 return FALSE;
8077 /* vectors vs. one dimensional arrays */
8078 if (target->byval_arg.type != candidate->byval_arg.type)
8079 return FALSE;
8081 eclass = target->cast_class;
8082 eoclass = candidate->cast_class;
8085 * a is b does not imply a[] is b[] when a is a valuetype, and
8086 * b is a reference type.
8089 if (eoclass->valuetype) {
8090 if ((eclass == mono_defaults.enum_class) ||
8091 (eclass == mono_defaults.enum_class->parent) ||
8092 (eclass == mono_defaults.object_class))
8093 return FALSE;
8096 return mono_class_is_assignable_from_slow (target->cast_class, candidate->cast_class);
8098 /*FIXME properly handle nullables */
8099 /*FIXME properly handle (M)VAR */
8100 return FALSE;
8104 * mono_class_get_cctor:
8105 * @klass: A MonoClass pointer
8107 * Returns: the static constructor of @klass if it exists, NULL otherwise.
8109 MonoMethod*
8110 mono_class_get_cctor (MonoClass *klass)
8112 MonoCachedClassInfo cached_info;
8114 if (klass->image->dynamic) {
8116 * has_cctor is not set for these classes because mono_class_init () is
8117 * not run for them.
8119 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8122 if (!klass->has_cctor)
8123 return NULL;
8125 if (mono_class_get_cached_class_info (klass, &cached_info))
8126 return mono_get_method (klass->image, cached_info.cctor_token, klass);
8128 if (klass->generic_class && !klass->methods)
8129 return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class));
8131 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8135 * mono_class_get_finalizer:
8136 * @klass: The MonoClass pointer
8138 * Returns: the finalizer method of @klass if it exists, NULL otherwise.
8140 MonoMethod*
8141 mono_class_get_finalizer (MonoClass *klass)
8143 MonoCachedClassInfo cached_info;
8145 if (!klass->inited)
8146 mono_class_init (klass);
8147 if (!mono_class_has_finalizer (klass))
8148 return NULL;
8150 if (mono_class_get_cached_class_info (klass, &cached_info))
8151 return mono_get_method (cached_info.finalize_image, cached_info.finalize_token, NULL);
8152 else {
8153 mono_class_setup_vtable (klass);
8154 return klass->vtable [finalize_slot];
8159 * mono_class_needs_cctor_run:
8160 * @klass: the MonoClass pointer
8161 * @caller: a MonoMethod describing the caller
8163 * Determines whenever the class has a static constructor and whenever it
8164 * needs to be called when executing CALLER.
8166 gboolean
8167 mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
8169 MonoMethod *method;
8171 method = mono_class_get_cctor (klass);
8172 if (method)
8173 return (method == caller) ? FALSE : TRUE;
8174 else
8175 return FALSE;
8179 * mono_class_array_element_size:
8180 * @klass:
8182 * Returns: the number of bytes an element of type @klass
8183 * uses when stored into an array.
8185 gint32
8186 mono_class_array_element_size (MonoClass *klass)
8188 MonoType *type = &klass->byval_arg;
8190 handle_enum:
8191 switch (type->type) {
8192 case MONO_TYPE_I1:
8193 case MONO_TYPE_U1:
8194 case MONO_TYPE_BOOLEAN:
8195 return 1;
8196 case MONO_TYPE_I2:
8197 case MONO_TYPE_U2:
8198 case MONO_TYPE_CHAR:
8199 return 2;
8200 case MONO_TYPE_I4:
8201 case MONO_TYPE_U4:
8202 case MONO_TYPE_R4:
8203 return 4;
8204 case MONO_TYPE_I:
8205 case MONO_TYPE_U:
8206 case MONO_TYPE_PTR:
8207 case MONO_TYPE_CLASS:
8208 case MONO_TYPE_STRING:
8209 case MONO_TYPE_OBJECT:
8210 case MONO_TYPE_SZARRAY:
8211 case MONO_TYPE_ARRAY:
8212 case MONO_TYPE_VAR:
8213 case MONO_TYPE_MVAR:
8214 return sizeof (gpointer);
8215 case MONO_TYPE_I8:
8216 case MONO_TYPE_U8:
8217 case MONO_TYPE_R8:
8218 return 8;
8219 case MONO_TYPE_VALUETYPE:
8220 if (type->data.klass->enumtype) {
8221 type = mono_class_enum_basetype (type->data.klass);
8222 klass = klass->element_class;
8223 goto handle_enum;
8225 return mono_class_instance_size (klass) - sizeof (MonoObject);
8226 case MONO_TYPE_GENERICINST:
8227 type = &type->data.generic_class->container_class->byval_arg;
8228 goto handle_enum;
8230 case MONO_TYPE_VOID:
8231 return 0;
8233 default:
8234 g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
8236 return -1;
8240 * mono_array_element_size:
8241 * @ac: pointer to a #MonoArrayClass
8243 * Returns: the size of single array element.
8245 gint32
8246 mono_array_element_size (MonoClass *ac)
8248 g_assert (ac->rank);
8249 return ac->sizes.element_size;
8252 gpointer
8253 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
8254 MonoGenericContext *context)
8256 if (image->dynamic) {
8257 MonoClass *tmp_handle_class;
8258 gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context);
8260 g_assert (tmp_handle_class);
8261 if (handle_class)
8262 *handle_class = tmp_handle_class;
8264 if (tmp_handle_class == mono_defaults.typehandle_class)
8265 return &((MonoClass*)obj)->byval_arg;
8266 else
8267 return obj;
8270 switch (token & 0xff000000) {
8271 case MONO_TOKEN_TYPE_DEF:
8272 case MONO_TOKEN_TYPE_REF:
8273 case MONO_TOKEN_TYPE_SPEC: {
8274 MonoType *type;
8275 if (handle_class)
8276 *handle_class = mono_defaults.typehandle_class;
8277 type = mono_type_get_full (image, token, context);
8278 if (!type)
8279 return NULL;
8280 mono_class_init (mono_class_from_mono_type (type));
8281 /* We return a MonoType* as handle */
8282 return type;
8284 case MONO_TOKEN_FIELD_DEF: {
8285 MonoClass *class;
8286 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
8287 if (!type)
8288 return NULL;
8289 if (handle_class)
8290 *handle_class = mono_defaults.fieldhandle_class;
8291 class = mono_class_get_full (image, MONO_TOKEN_TYPE_DEF | type, context);
8292 if (!class)
8293 return NULL;
8294 mono_class_init (class);
8295 return mono_class_get_field (class, token);
8297 case MONO_TOKEN_METHOD_DEF:
8298 case MONO_TOKEN_METHOD_SPEC: {
8299 MonoMethod *meth;
8300 meth = mono_get_method_full (image, token, NULL, context);
8301 if (handle_class)
8302 *handle_class = mono_defaults.methodhandle_class;
8303 return meth;
8305 case MONO_TOKEN_MEMBER_REF: {
8306 guint32 cols [MONO_MEMBERREF_SIZE];
8307 const char *sig;
8308 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE);
8309 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
8310 mono_metadata_decode_blob_size (sig, &sig);
8311 if (*sig == 0x6) { /* it's a field */
8312 MonoClass *klass;
8313 MonoClassField *field;
8314 field = mono_field_from_token (image, token, &klass, context);
8315 if (handle_class)
8316 *handle_class = mono_defaults.fieldhandle_class;
8317 return field;
8318 } else {
8319 MonoMethod *meth;
8320 meth = mono_get_method_full (image, token, NULL, context);
8321 if (handle_class)
8322 *handle_class = mono_defaults.methodhandle_class;
8323 return meth;
8326 default:
8327 g_warning ("Unknown token 0x%08x in ldtoken", token);
8328 break;
8330 return NULL;
8334 * This function might need to call runtime functions so it can't be part
8335 * of the metadata library.
8337 static MonoLookupDynamicToken lookup_dynamic = NULL;
8339 void
8340 mono_install_lookup_dynamic_token (MonoLookupDynamicToken func)
8342 lookup_dynamic = func;
8345 gpointer
8346 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
8348 MonoClass *handle_class;
8350 return lookup_dynamic (image, token, TRUE, &handle_class, context);
8353 gpointer
8354 mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
8356 return lookup_dynamic (image, token, valid_token, handle_class, context);
8359 static MonoGetCachedClassInfo get_cached_class_info = NULL;
8361 void
8362 mono_install_get_cached_class_info (MonoGetCachedClassInfo func)
8364 get_cached_class_info = func;
8367 static gboolean
8368 mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
8370 if (!get_cached_class_info)
8371 return FALSE;
8372 else
8373 return get_cached_class_info (klass, res);
8376 void
8377 mono_install_get_class_from_name (MonoGetClassFromName func)
8379 get_class_from_name = func;
8382 MonoImage*
8383 mono_class_get_image (MonoClass *klass)
8385 return klass->image;
8389 * mono_class_get_element_class:
8390 * @klass: the MonoClass to act on
8392 * Returns: the element class of an array or an enumeration.
8394 MonoClass*
8395 mono_class_get_element_class (MonoClass *klass)
8397 return klass->element_class;
8401 * mono_class_is_valuetype:
8402 * @klass: the MonoClass to act on
8404 * Returns: true if the MonoClass represents a ValueType.
8406 gboolean
8407 mono_class_is_valuetype (MonoClass *klass)
8409 return klass->valuetype;
8413 * mono_class_is_enum:
8414 * @klass: the MonoClass to act on
8416 * Returns: true if the MonoClass represents an enumeration.
8418 gboolean
8419 mono_class_is_enum (MonoClass *klass)
8421 return klass->enumtype;
8425 * mono_class_enum_basetype:
8426 * @klass: the MonoClass to act on
8428 * Returns: the underlying type representation for an enumeration.
8430 MonoType*
8431 mono_class_enum_basetype (MonoClass *klass)
8433 if (klass->element_class == klass)
8434 /* SRE or broken types */
8435 return NULL;
8436 else
8437 return &klass->element_class->byval_arg;
8441 * mono_class_get_parent
8442 * @klass: the MonoClass to act on
8444 * Returns: the parent class for this class.
8446 MonoClass*
8447 mono_class_get_parent (MonoClass *klass)
8449 return klass->parent;
8453 * mono_class_get_nesting_type;
8454 * @klass: the MonoClass to act on
8456 * Returns: the container type where this type is nested or NULL if this type is not a nested type.
8458 MonoClass*
8459 mono_class_get_nesting_type (MonoClass *klass)
8461 return klass->nested_in;
8465 * mono_class_get_rank:
8466 * @klass: the MonoClass to act on
8468 * Returns: the rank for the array (the number of dimensions).
8471 mono_class_get_rank (MonoClass *klass)
8473 return klass->rank;
8477 * mono_class_get_flags:
8478 * @klass: the MonoClass to act on
8480 * The type flags from the TypeDef table from the metadata.
8481 * see the TYPE_ATTRIBUTE_* definitions on tabledefs.h for the
8482 * different values.
8484 * Returns: the flags from the TypeDef table.
8486 guint32
8487 mono_class_get_flags (MonoClass *klass)
8489 return klass->flags;
8493 * mono_class_get_name
8494 * @klass: the MonoClass to act on
8496 * Returns: the name of the class.
8498 const char*
8499 mono_class_get_name (MonoClass *klass)
8501 return klass->name;
8505 * mono_class_get_namespace:
8506 * @klass: the MonoClass to act on
8508 * Returns: the namespace of the class.
8510 const char*
8511 mono_class_get_namespace (MonoClass *klass)
8513 return klass->name_space;
8517 * mono_class_get_type:
8518 * @klass: the MonoClass to act on
8520 * This method returns the internal Type representation for the class.
8522 * Returns: the MonoType from the class.
8524 MonoType*
8525 mono_class_get_type (MonoClass *klass)
8527 return &klass->byval_arg;
8531 * mono_class_get_type_token
8532 * @klass: the MonoClass to act on
8534 * This method returns type token for the class.
8536 * Returns: the type token for the class.
8538 guint32
8539 mono_class_get_type_token (MonoClass *klass)
8541 return klass->type_token;
8545 * mono_class_get_byref_type:
8546 * @klass: the MonoClass to act on
8550 MonoType*
8551 mono_class_get_byref_type (MonoClass *klass)
8553 return &klass->this_arg;
8557 * mono_class_num_fields:
8558 * @klass: the MonoClass to act on
8560 * Returns: the number of static and instance fields in the class.
8563 mono_class_num_fields (MonoClass *klass)
8565 return klass->field.count;
8569 * mono_class_num_methods:
8570 * @klass: the MonoClass to act on
8572 * Returns: the number of methods in the class.
8575 mono_class_num_methods (MonoClass *klass)
8577 return klass->method.count;
8581 * mono_class_num_properties
8582 * @klass: the MonoClass to act on
8584 * Returns: the number of properties in the class.
8587 mono_class_num_properties (MonoClass *klass)
8589 mono_class_setup_properties (klass);
8591 return klass->ext->property.count;
8595 * mono_class_num_events:
8596 * @klass: the MonoClass to act on
8598 * Returns: the number of events in the class.
8601 mono_class_num_events (MonoClass *klass)
8603 mono_class_setup_events (klass);
8605 return klass->ext->event.count;
8609 * mono_class_get_fields:
8610 * @klass: the MonoClass to act on
8612 * This routine is an iterator routine for retrieving the fields in a class.
8614 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8615 * iterate over all of the elements. When no more values are
8616 * available, the return value is NULL.
8618 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
8620 MonoClassField*
8621 mono_class_get_fields (MonoClass* klass, gpointer *iter)
8623 MonoClassField* field;
8624 if (!iter)
8625 return NULL;
8626 if (!*iter) {
8627 mono_class_setup_fields_locking (klass);
8628 if (klass->exception_type)
8629 return NULL;
8630 /* start from the first */
8631 if (klass->field.count) {
8632 return *iter = &klass->fields [0];
8633 } else {
8634 /* no fields */
8635 return NULL;
8638 field = *iter;
8639 field++;
8640 if (field < &klass->fields [klass->field.count]) {
8641 return *iter = field;
8643 return NULL;
8647 * mono_class_get_methods
8648 * @klass: the MonoClass to act on
8650 * This routine is an iterator routine for retrieving the fields in a class.
8652 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8653 * iterate over all of the elements. When no more values are
8654 * available, the return value is NULL.
8656 * Returns: a MonoMethod on each iteration or NULL when no more methods are available.
8658 MonoMethod*
8659 mono_class_get_methods (MonoClass* klass, gpointer *iter)
8661 MonoMethod** method;
8662 if (!iter)
8663 return NULL;
8664 if (!*iter) {
8665 mono_class_setup_methods (klass);
8668 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
8669 * FIXME we should better report this error to the caller
8671 if (!klass->methods)
8672 return NULL;
8673 /* start from the first */
8674 if (klass->method.count) {
8675 *iter = &klass->methods [0];
8676 return klass->methods [0];
8677 } else {
8678 /* no method */
8679 return NULL;
8682 method = *iter;
8683 method++;
8684 if (method < &klass->methods [klass->method.count]) {
8685 *iter = method;
8686 return *method;
8688 return NULL;
8692 * mono_class_get_virtual_methods:
8694 * Iterate over the virtual methods of KLASS.
8696 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
8698 static MonoMethod*
8699 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
8701 MonoMethod** method;
8702 if (!iter)
8703 return NULL;
8704 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
8705 if (!*iter) {
8706 mono_class_setup_methods (klass);
8708 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
8709 * FIXME we should better report this error to the caller
8711 if (!klass->methods)
8712 return NULL;
8713 /* start from the first */
8714 method = &klass->methods [0];
8715 } else {
8716 method = *iter;
8717 method++;
8719 while (method < &klass->methods [klass->method.count]) {
8720 if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
8721 break;
8722 method ++;
8724 if (method < &klass->methods [klass->method.count]) {
8725 *iter = method;
8726 return *method;
8727 } else {
8728 return NULL;
8730 } else {
8731 /* Search directly in metadata to avoid calling setup_methods () */
8732 MonoMethod *res = NULL;
8733 int i, start_index;
8735 if (!*iter) {
8736 start_index = 0;
8737 } else {
8738 start_index = GPOINTER_TO_UINT (*iter);
8741 for (i = start_index; i < klass->method.count; ++i) {
8742 guint32 flags;
8744 /* class->method.first points into the methodptr table */
8745 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
8747 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
8748 break;
8751 if (i < klass->method.count) {
8752 res = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass);
8753 /* Add 1 here so the if (*iter) check fails */
8754 *iter = GUINT_TO_POINTER (i + 1);
8755 return res;
8756 } else {
8757 return NULL;
8763 * mono_class_get_properties:
8764 * @klass: the MonoClass to act on
8766 * This routine is an iterator routine for retrieving the properties in a class.
8768 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8769 * iterate over all of the elements. When no more values are
8770 * available, the return value is NULL.
8772 * Returns: a @MonoProperty* on each invocation, or NULL when no more are available.
8774 MonoProperty*
8775 mono_class_get_properties (MonoClass* klass, gpointer *iter)
8777 MonoProperty* property;
8778 if (!iter)
8779 return NULL;
8780 if (!*iter) {
8781 mono_class_setup_properties (klass);
8782 /* start from the first */
8783 if (klass->ext->property.count) {
8784 return *iter = &klass->ext->properties [0];
8785 } else {
8786 /* no fields */
8787 return NULL;
8790 property = *iter;
8791 property++;
8792 if (property < &klass->ext->properties [klass->ext->property.count]) {
8793 return *iter = property;
8795 return NULL;
8799 * mono_class_get_events:
8800 * @klass: the MonoClass to act on
8802 * This routine is an iterator routine for retrieving the properties in a class.
8804 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8805 * iterate over all of the elements. When no more values are
8806 * available, the return value is NULL.
8808 * Returns: a @MonoEvent* on each invocation, or NULL when no more are available.
8810 MonoEvent*
8811 mono_class_get_events (MonoClass* klass, gpointer *iter)
8813 MonoEvent* event;
8814 if (!iter)
8815 return NULL;
8816 if (!*iter) {
8817 mono_class_setup_events (klass);
8818 /* start from the first */
8819 if (klass->ext->event.count) {
8820 return *iter = &klass->ext->events [0];
8821 } else {
8822 /* no fields */
8823 return NULL;
8826 event = *iter;
8827 event++;
8828 if (event < &klass->ext->events [klass->ext->event.count]) {
8829 return *iter = event;
8831 return NULL;
8835 * mono_class_get_interfaces
8836 * @klass: the MonoClass to act on
8838 * This routine is an iterator routine for retrieving the interfaces implemented by this class.
8840 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8841 * iterate over all of the elements. When no more values are
8842 * available, the return value is NULL.
8844 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
8846 MonoClass*
8847 mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
8849 MonoError error;
8850 MonoClass** iface;
8851 if (!iter)
8852 return NULL;
8853 if (!*iter) {
8854 if (!klass->inited)
8855 mono_class_init (klass);
8856 if (!klass->interfaces_inited) {
8857 mono_class_setup_interfaces (klass, &error);
8858 if (!mono_error_ok (&error)) {
8859 mono_error_cleanup (&error);
8860 return NULL;
8863 /* start from the first */
8864 if (klass->interface_count) {
8865 *iter = &klass->interfaces [0];
8866 return klass->interfaces [0];
8867 } else {
8868 /* no interface */
8869 return NULL;
8872 iface = *iter;
8873 iface++;
8874 if (iface < &klass->interfaces [klass->interface_count]) {
8875 *iter = iface;
8876 return *iface;
8878 return NULL;
8882 * mono_class_get_nested_types
8883 * @klass: the MonoClass to act on
8885 * This routine is an iterator routine for retrieving the nested types of a class.
8886 * This works only if @klass is non-generic, or a generic type definition.
8888 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8889 * iterate over all of the elements. When no more values are
8890 * available, the return value is NULL.
8892 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
8894 MonoClass*
8895 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
8897 MonoError error;
8898 GList *item;
8899 int i;
8901 if (!iter)
8902 return NULL;
8903 if (!klass->nested_classes_inited) {
8904 if (!klass->type_token)
8905 klass->nested_classes_inited = TRUE;
8906 mono_loader_lock ();
8907 if (!klass->nested_classes_inited) {
8908 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
8909 while (i) {
8910 MonoClass* nclass;
8911 guint32 cols [MONO_NESTED_CLASS_SIZE];
8912 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
8913 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error);
8914 if (!mono_error_ok (&error)) {
8915 /*FIXME don't swallow the error message*/
8916 mono_error_cleanup (&error);
8918 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
8919 continue;
8921 mono_class_alloc_ext (klass);
8922 klass->ext->nested_classes = g_list_prepend_image (klass->image, klass->ext->nested_classes, nclass);
8924 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
8927 mono_memory_barrier ();
8928 klass->nested_classes_inited = TRUE;
8929 mono_loader_unlock ();
8932 if (!*iter) {
8933 /* start from the first */
8934 if (klass->ext && klass->ext->nested_classes) {
8935 *iter = klass->ext->nested_classes;
8936 return klass->ext->nested_classes->data;
8937 } else {
8938 /* no nested types */
8939 return NULL;
8942 item = *iter;
8943 item = item->next;
8944 if (item) {
8945 *iter = item;
8946 return item->data;
8948 return NULL;
8953 * mono_class_is_delegate
8954 * @klass: the MonoClass to act on
8956 * Returns: true if the MonoClass represents a System.Delegate.
8958 mono_bool
8959 mono_class_is_delegate (MonoClass *klass)
8961 return klass->delegate;
8965 * mono_class_implements_interface
8966 * @klass: The MonoClass to act on
8967 * @interface: The interface to check if @klass implements.
8969 * Returns: true if @klass implements @interface.
8971 mono_bool
8972 mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
8974 return mono_class_is_assignable_from (iface, klass);
8978 * mono_field_get_name:
8979 * @field: the MonoClassField to act on
8981 * Returns: the name of the field.
8983 const char*
8984 mono_field_get_name (MonoClassField *field)
8986 return field->name;
8990 * mono_field_get_type:
8991 * @field: the MonoClassField to act on
8993 * Returns: MonoType of the field.
8995 MonoType*
8996 mono_field_get_type (MonoClassField *field)
8998 MonoError error;
8999 MonoType *type = mono_field_get_type_checked (field, &error);
9000 if (!mono_error_ok (&error)) {
9001 mono_trace_warning (MONO_TRACE_TYPE, "Could not load field's type due to %s", mono_error_get_message (&error));
9002 mono_error_cleanup (&error);
9004 return type;
9009 * mono_field_get_type_checked:
9010 * @field: the MonoClassField to act on
9011 * @error: used to return any erro found while retrieving @field type
9013 * Returns: MonoType of the field.
9015 MonoType*
9016 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
9018 mono_error_init (error);
9019 if (!field->type)
9020 mono_field_resolve_type (field, error);
9021 return field->type;
9025 * mono_field_get_parent:
9026 * @field: the MonoClassField to act on
9028 * Returns: MonoClass where the field was defined.
9030 MonoClass*
9031 mono_field_get_parent (MonoClassField *field)
9033 return field->parent;
9037 * mono_field_get_flags;
9038 * @field: the MonoClassField to act on
9040 * The metadata flags for a field are encoded using the
9041 * FIELD_ATTRIBUTE_* constants. See the tabledefs.h file for details.
9043 * Returns: the flags for the field.
9045 guint32
9046 mono_field_get_flags (MonoClassField *field)
9048 if (!field->type)
9049 return mono_field_resolve_flags (field);
9050 return field->type->attrs;
9054 * mono_field_get_offset;
9055 * @field: the MonoClassField to act on
9057 * Returns: the field offset.
9059 guint32
9060 mono_field_get_offset (MonoClassField *field)
9062 return field->offset;
9065 static const char *
9066 mono_field_get_rva (MonoClassField *field)
9068 guint32 rva;
9069 int field_index;
9070 MonoClass *klass = field->parent;
9072 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
9074 if (!klass->ext || !klass->ext->field_def_values) {
9075 mono_loader_lock ();
9076 mono_class_alloc_ext (klass);
9077 if (!klass->ext->field_def_values)
9078 klass->ext->field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
9079 mono_loader_unlock ();
9082 field_index = mono_field_get_index (field);
9084 if (!klass->ext->field_def_values [field_index].data && !klass->image->dynamic) {
9085 mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL);
9086 if (!rva)
9087 g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
9088 klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
9091 return klass->ext->field_def_values [field_index].data;
9095 * mono_field_get_data;
9096 * @field: the MonoClassField to act on
9098 * Returns: pointer to the metadata constant value or to the field
9099 * data if it has an RVA flag.
9101 const char *
9102 mono_field_get_data (MonoClassField *field)
9104 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
9105 MonoTypeEnum def_type;
9107 return mono_class_get_field_default_value (field, &def_type);
9108 } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
9109 return mono_field_get_rva (field);
9110 } else {
9111 return NULL;
9116 * mono_property_get_name:
9117 * @prop: the MonoProperty to act on
9119 * Returns: the name of the property
9121 const char*
9122 mono_property_get_name (MonoProperty *prop)
9124 return prop->name;
9128 * mono_property_get_set_method
9129 * @prop: the MonoProperty to act on.
9131 * Returns: the setter method of the property (A MonoMethod)
9133 MonoMethod*
9134 mono_property_get_set_method (MonoProperty *prop)
9136 return prop->set;
9140 * mono_property_get_get_method
9141 * @prop: the MonoProperty to act on.
9143 * Returns: the setter method of the property (A MonoMethod)
9145 MonoMethod*
9146 mono_property_get_get_method (MonoProperty *prop)
9148 return prop->get;
9152 * mono_property_get_parent:
9153 * @prop: the MonoProperty to act on.
9155 * Returns: the MonoClass where the property was defined.
9157 MonoClass*
9158 mono_property_get_parent (MonoProperty *prop)
9160 return prop->parent;
9164 * mono_property_get_flags:
9165 * @prop: the MonoProperty to act on.
9167 * The metadata flags for a property are encoded using the
9168 * PROPERTY_ATTRIBUTE_* constants. See the tabledefs.h file for details.
9170 * Returns: the flags for the property.
9172 guint32
9173 mono_property_get_flags (MonoProperty *prop)
9175 return prop->attrs;
9179 * mono_event_get_name:
9180 * @event: the MonoEvent to act on
9182 * Returns: the name of the event.
9184 const char*
9185 mono_event_get_name (MonoEvent *event)
9187 return event->name;
9191 * mono_event_get_add_method:
9192 * @event: The MonoEvent to act on.
9194 * Returns: the @add' method for the event (a MonoMethod).
9196 MonoMethod*
9197 mono_event_get_add_method (MonoEvent *event)
9199 return event->add;
9203 * mono_event_get_remove_method:
9204 * @event: The MonoEvent to act on.
9206 * Returns: the @remove method for the event (a MonoMethod).
9208 MonoMethod*
9209 mono_event_get_remove_method (MonoEvent *event)
9211 return event->remove;
9215 * mono_event_get_raise_method:
9216 * @event: The MonoEvent to act on.
9218 * Returns: the @raise method for the event (a MonoMethod).
9220 MonoMethod*
9221 mono_event_get_raise_method (MonoEvent *event)
9223 return event->raise;
9227 * mono_event_get_parent:
9228 * @event: the MonoEvent to act on.
9230 * Returns: the MonoClass where the event is defined.
9232 MonoClass*
9233 mono_event_get_parent (MonoEvent *event)
9235 return event->parent;
9239 * mono_event_get_flags
9240 * @event: the MonoEvent to act on.
9242 * The metadata flags for an event are encoded using the
9243 * EVENT_* constants. See the tabledefs.h file for details.
9245 * Returns: the flags for the event.
9247 guint32
9248 mono_event_get_flags (MonoEvent *event)
9250 return event->attrs;
9254 * mono_class_get_method_from_name:
9255 * @klass: where to look for the method
9256 * @name_space: name of the method
9257 * @param_count: number of parameters. -1 for any number.
9259 * Obtains a MonoMethod with a given name and number of parameters.
9260 * It only works if there are no multiple signatures for any given method name.
9262 MonoMethod *
9263 mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_count)
9265 return mono_class_get_method_from_name_flags (klass, name, param_count, 0);
9268 static MonoMethod*
9269 find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
9271 MonoMethod *res = NULL;
9272 int i;
9274 /* Search directly in the metadata to avoid calling setup_methods () */
9275 for (i = 0; i < klass->method.count; ++i) {
9276 guint32 cols [MONO_METHOD_SIZE];
9277 MonoMethod *method;
9278 MonoMethodSignature *sig;
9280 /* class->method.first points into the methodptr table */
9281 mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE);
9283 if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
9284 method = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass);
9285 if (param_count == -1) {
9286 res = method;
9287 break;
9289 sig = mono_method_signature (method);
9290 if (sig && sig->param_count == param_count) {
9291 res = method;
9292 break;
9297 return res;
9301 * mono_class_get_method_from_name_flags:
9302 * @klass: where to look for the method
9303 * @name_space: name of the method
9304 * @param_count: number of parameters. -1 for any number.
9305 * @flags: flags which must be set in the method
9307 * Obtains a MonoMethod with a given name and number of parameters.
9308 * It only works if there are no multiple signatures for any given method name.
9310 MonoMethod *
9311 mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int param_count, int flags)
9313 MonoMethod *res = NULL;
9314 int i;
9316 mono_class_init (klass);
9318 if (klass->generic_class && !klass->methods) {
9319 res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags);
9320 if (res)
9321 res = mono_class_inflate_generic_method_full (res, klass, mono_class_get_context (klass));
9322 return res;
9325 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
9326 mono_class_setup_methods (klass);
9328 We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9329 See mono/tests/array_load_exception.il
9330 FIXME we should better report this error to the caller
9332 if (!klass->methods)
9333 return NULL;
9334 for (i = 0; i < klass->method.count; ++i) {
9335 MonoMethod *method = klass->methods [i];
9337 if (method->name[0] == name [0] &&
9338 !strcmp (name, method->name) &&
9339 (param_count == -1 || mono_method_signature (method)->param_count == param_count) &&
9340 ((method->flags & flags) == flags)) {
9341 res = method;
9342 break;
9346 else {
9347 res = find_method_in_metadata (klass, name, param_count, flags);
9350 return res;
9354 * mono_class_set_failure:
9355 * @klass: class in which the failure was detected
9356 * @ex_type: the kind of exception/error to be thrown (later)
9357 * @ex_data: exception data (specific to each type of exception/error)
9359 * Keep a detected failure informations in the class for later processing.
9360 * Note that only the first failure is kept.
9362 * LOCKING: Acquires the loader lock.
9364 gboolean
9365 mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
9367 if (klass->exception_type)
9368 return FALSE;
9370 mono_loader_lock ();
9371 klass->exception_type = ex_type;
9372 if (ex_data)
9373 mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
9374 mono_loader_unlock ();
9376 return TRUE;
9380 * mono_class_get_exception_data:
9382 * Return the exception_data property of KLASS.
9384 * LOCKING: Acquires the loader lock.
9386 gpointer
9387 mono_class_get_exception_data (MonoClass *klass)
9389 return mono_image_property_lookup (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA);
9393 * mono_classes_init:
9395 * Initialize the resources used by this module.
9397 void
9398 mono_classes_init (void)
9400 mono_counters_register ("Inflated methods size",
9401 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
9402 mono_counters_register ("Inflated classes",
9403 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes);
9404 mono_counters_register ("Inflated classes size",
9405 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
9406 mono_counters_register ("MonoClass size",
9407 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
9408 mono_counters_register ("MonoClassExt size",
9409 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size);
9413 * mono_classes_cleanup:
9415 * Free the resources used by this module.
9417 void
9418 mono_classes_cleanup (void)
9420 if (global_interface_bitset)
9421 mono_bitset_free (global_interface_bitset);
9422 global_interface_bitset = NULL;
9426 * mono_class_get_exception_for_failure:
9427 * @klass: class in which the failure was detected
9429 * Return a constructed MonoException than the caller can then throw
9430 * using mono_raise_exception - or NULL if no failure is present (or
9431 * doesn't result in an exception).
9433 MonoException*
9434 mono_class_get_exception_for_failure (MonoClass *klass)
9436 gpointer exception_data = mono_class_get_exception_data (klass);
9438 switch (klass->exception_type) {
9439 #ifndef DISABLE_SECURITY
9440 case MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND: {
9441 MonoDomain *domain = mono_domain_get ();
9442 MonoSecurityManager* secman = mono_security_manager_get_methods ();
9443 MonoMethod *method = exception_data;
9444 guint32 error = (method) ? MONO_METADATA_INHERITANCEDEMAND_METHOD : MONO_METADATA_INHERITANCEDEMAND_CLASS;
9445 MonoObject *exc = NULL;
9446 gpointer args [4];
9448 args [0] = &error;
9449 args [1] = mono_assembly_get_object (domain, mono_image_get_assembly (klass->image));
9450 args [2] = mono_type_get_object (domain, &klass->byval_arg);
9451 args [3] = (method) ? mono_method_get_object (domain, method, NULL) : NULL;
9453 mono_runtime_invoke (secman->inheritsecurityexception, NULL, args, &exc);
9454 return (MonoException*) exc;
9456 #endif
9457 case MONO_EXCEPTION_TYPE_LOAD: {
9458 MonoString *name;
9459 MonoException *ex;
9460 char *str = mono_type_get_full_name (klass);
9461 char *astr = klass->image->assembly? mono_stringify_assembly_name (&klass->image->assembly->aname): NULL;
9462 name = mono_string_new (mono_domain_get (), str);
9463 g_free (str);
9464 ex = mono_get_exception_type_load (name, astr);
9465 g_free (astr);
9466 return ex;
9468 case MONO_EXCEPTION_MISSING_METHOD: {
9469 char *class_name = exception_data;
9470 char *assembly_name = class_name + strlen (class_name) + 1;
9472 return mono_get_exception_missing_method (class_name, assembly_name);
9474 case MONO_EXCEPTION_MISSING_FIELD: {
9475 char *class_name = exception_data;
9476 char *member_name = class_name + strlen (class_name) + 1;
9478 return mono_get_exception_missing_field (class_name, member_name);
9480 case MONO_EXCEPTION_FILE_NOT_FOUND: {
9481 char *msg_format = exception_data;
9482 char *assembly_name = msg_format + strlen (msg_format) + 1;
9483 char *msg = g_strdup_printf (msg_format, assembly_name);
9484 MonoException *ex;
9486 ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), assembly_name));
9488 g_free (msg);
9490 return ex;
9492 case MONO_EXCEPTION_BAD_IMAGE: {
9493 return mono_get_exception_bad_image_format (exception_data);
9495 default: {
9496 MonoLoaderError *error;
9497 MonoException *ex;
9499 error = mono_loader_get_last_error ();
9500 if (error != NULL){
9501 ex = mono_loader_error_prepare_exception (error);
9502 return ex;
9505 /* TODO - handle other class related failures */
9506 return NULL;
9511 static gboolean
9512 is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
9514 outer_klass = mono_class_get_generic_type_definition (outer_klass);
9515 inner_klass = mono_class_get_generic_type_definition (inner_klass);
9516 do {
9517 if (outer_klass == inner_klass)
9518 return TRUE;
9519 inner_klass = inner_klass->nested_in;
9520 } while (inner_klass);
9521 return FALSE;
9524 MonoClass *
9525 mono_class_get_generic_type_definition (MonoClass *klass)
9527 return klass->generic_class ? klass->generic_class->container_class : klass;
9531 * Check if @klass is a subtype of @parent ignoring generic instantiations.
9533 * Generic instantiations are ignored for all super types of @klass.
9535 * Visibility checks ignoring generic instantiations.
9537 gboolean
9538 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
9540 int i;
9541 klass = mono_class_get_generic_type_definition (klass);
9542 parent = mono_class_get_generic_type_definition (parent);
9543 mono_class_setup_supertypes (klass);
9545 for (i = 0; i < klass->idepth; ++i) {
9546 if (parent == mono_class_get_generic_type_definition (klass->supertypes [i]))
9547 return TRUE;
9549 return FALSE;
9552 * Subtype can only access parent members with family protection if the site object
9553 * is subclass of Subtype. For example:
9554 * class A { protected int x; }
9555 * class B : A {
9556 * void valid_access () {
9557 * B b;
9558 * b.x = 0;
9560 * void invalid_access () {
9561 * A a;
9562 * a.x = 0;
9565 * */
9566 static gboolean
9567 is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
9569 if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
9570 return FALSE;
9572 if (context_klass == NULL)
9573 return TRUE;
9574 /*if access_klass is not member_klass context_klass must be type compat*/
9575 if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
9576 return FALSE;
9577 return TRUE;
9580 static gboolean
9581 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
9583 GSList *tmp;
9584 if (accessing == accessed)
9585 return TRUE;
9586 if (!accessed || !accessing)
9587 return FALSE;
9589 /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
9590 * anywhere so untrusted friends are not safe to access platform's code internals */
9591 if (mono_security_core_clr_enabled ()) {
9592 if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
9593 return FALSE;
9596 mono_assembly_load_friends (accessed);
9597 for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
9598 MonoAssemblyName *friend = tmp->data;
9599 /* Be conservative with checks */
9600 if (!friend->name)
9601 continue;
9602 if (strcmp (accessing->aname.name, friend->name))
9603 continue;
9604 if (friend->public_key_token [0]) {
9605 if (!accessing->aname.public_key_token [0])
9606 continue;
9607 if (!mono_public_tokens_are_equal (friend->public_key_token, accessing->aname.public_key_token))
9608 continue;
9610 return TRUE;
9612 return FALSE;
9616 * If klass is a generic type or if it is derived from a generic type, return the
9617 * MonoClass of the generic definition
9618 * Returns NULL if not found
9620 static MonoClass*
9621 get_generic_definition_class (MonoClass *klass)
9623 while (klass) {
9624 if (klass->generic_class && klass->generic_class->container_class)
9625 return klass->generic_class->container_class;
9626 klass = klass->parent;
9628 return NULL;
9631 static gboolean
9632 can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
9634 int i;
9635 for (i = 0; i < ginst->type_argc; ++i) {
9636 MonoType *type = ginst->type_argv[i];
9637 switch (type->type) {
9638 case MONO_TYPE_SZARRAY:
9639 if (!can_access_type (access_klass, type->data.klass))
9640 return FALSE;
9641 break;
9642 case MONO_TYPE_ARRAY:
9643 if (!can_access_type (access_klass, type->data.array->eklass))
9644 return FALSE;
9645 break;
9646 case MONO_TYPE_PTR:
9647 if (!can_access_type (access_klass, mono_class_from_mono_type (type->data.type)))
9648 return FALSE;
9649 break;
9650 case MONO_TYPE_CLASS:
9651 case MONO_TYPE_VALUETYPE:
9652 case MONO_TYPE_GENERICINST:
9653 if (!can_access_type (access_klass, mono_class_from_mono_type (type)))
9654 return FALSE;
9657 return TRUE;
9660 static gboolean
9661 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
9663 int access_level;
9665 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
9666 return TRUE;
9668 if (access_klass->element_class && !access_klass->enumtype)
9669 access_klass = access_klass->element_class;
9671 if (member_klass->element_class && !member_klass->enumtype)
9672 member_klass = member_klass->element_class;
9674 access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
9676 if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
9677 return TRUE;
9679 if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst))
9680 return FALSE;
9682 if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
9683 return TRUE;
9685 if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
9686 return FALSE;
9688 /*Non nested type with nested visibility. We just fail it.*/
9689 if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL)
9690 return FALSE;
9692 switch (access_level) {
9693 case TYPE_ATTRIBUTE_NOT_PUBLIC:
9694 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
9696 case TYPE_ATTRIBUTE_PUBLIC:
9697 return TRUE;
9699 case TYPE_ATTRIBUTE_NESTED_PUBLIC:
9700 return TRUE;
9702 case TYPE_ATTRIBUTE_NESTED_PRIVATE:
9703 return is_nesting_type (member_klass, access_klass);
9705 case TYPE_ATTRIBUTE_NESTED_FAMILY:
9706 return mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
9708 case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
9709 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
9711 case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
9712 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) &&
9713 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
9715 case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
9716 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) ||
9717 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
9719 return FALSE;
9722 /* FIXME: check visibility of type, too */
9723 static gboolean
9724 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
9726 MonoClass *member_generic_def;
9727 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
9728 return TRUE;
9730 if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
9731 access_klass->generic_container) &&
9732 (member_generic_def = get_generic_definition_class (member_klass))) {
9733 MonoClass *access_container;
9735 if (access_klass->generic_container)
9736 access_container = access_klass;
9737 else
9738 access_container = access_klass->generic_class->container_class;
9740 if (can_access_member (access_container, member_generic_def, context_klass, access_level))
9741 return TRUE;
9744 /* Partition I 8.5.3.2 */
9745 /* the access level values are the same for fields and methods */
9746 switch (access_level) {
9747 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
9748 /* same compilation unit */
9749 return access_klass->image == member_klass->image;
9750 case FIELD_ATTRIBUTE_PRIVATE:
9751 return access_klass == member_klass;
9752 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
9753 if (is_valid_family_access (access_klass, member_klass, context_klass) &&
9754 can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
9755 return TRUE;
9756 return FALSE;
9757 case FIELD_ATTRIBUTE_ASSEMBLY:
9758 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
9759 case FIELD_ATTRIBUTE_FAMILY:
9760 if (is_valid_family_access (access_klass, member_klass, context_klass))
9761 return TRUE;
9762 return FALSE;
9763 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
9764 if (is_valid_family_access (access_klass, member_klass, context_klass))
9765 return TRUE;
9766 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
9767 case FIELD_ATTRIBUTE_PUBLIC:
9768 return TRUE;
9770 return FALSE;
9773 gboolean
9774 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
9776 /* FIXME: check all overlapping fields */
9777 int can = can_access_member (method->klass, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
9778 if (!can) {
9779 MonoClass *nested = method->klass->nested_in;
9780 while (nested) {
9781 can = can_access_member (nested, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
9782 if (can)
9783 return TRUE;
9784 nested = nested->nested_in;
9787 return can;
9790 gboolean
9791 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
9793 int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
9794 if (!can) {
9795 MonoClass *nested = method->klass->nested_in;
9796 while (nested) {
9797 can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
9798 if (can)
9799 return TRUE;
9800 nested = nested->nested_in;
9804 * FIXME:
9805 * with generics calls to explicit interface implementations can be expressed
9806 * directly: the method is private, but we must allow it. This may be opening
9807 * a hole or the generics code should handle this differently.
9808 * Maybe just ensure the interface type is public.
9810 if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
9811 return TRUE;
9812 return can;
9816 * mono_method_can_access_method_full:
9817 * @method: The caller method
9818 * @called: The called method
9819 * @context_klass: The static type on stack of the owner @called object used
9821 * This function must be used with instance calls, as they have more strict family accessibility.
9822 * It can be used with static methods, but context_klass should be NULL.
9824 * Returns: TRUE if caller have proper visibility and acessibility to @called
9826 gboolean
9827 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
9829 MonoClass *access_class = method->klass;
9830 MonoClass *member_class = called->klass;
9831 int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
9832 if (!can) {
9833 MonoClass *nested = access_class->nested_in;
9834 while (nested) {
9835 can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
9836 if (can)
9837 break;
9838 nested = nested->nested_in;
9842 if (!can)
9843 return FALSE;
9845 can = can_access_type (access_class, member_class);
9846 if (!can) {
9847 MonoClass *nested = access_class->nested_in;
9848 while (nested) {
9849 can = can_access_type (nested, member_class);
9850 if (can)
9851 break;
9852 nested = nested->nested_in;
9856 if (!can)
9857 return FALSE;
9859 if (called->is_inflated) {
9860 MonoMethodInflated * infl = (MonoMethodInflated*)called;
9861 if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
9862 return FALSE;
9865 return TRUE;
9870 * mono_method_can_access_field_full:
9871 * @method: The caller method
9872 * @field: The accessed field
9873 * @context_klass: The static type on stack of the owner @field object used
9875 * This function must be used with instance fields, as they have more strict family accessibility.
9876 * It can be used with static fields, but context_klass should be NULL.
9878 * Returns: TRUE if caller have proper visibility and acessibility to @field
9880 gboolean
9881 mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
9883 MonoClass *access_class = method->klass;
9884 MonoClass *member_class = field->parent;
9885 /* FIXME: check all overlapping fields */
9886 int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
9887 if (!can) {
9888 MonoClass *nested = access_class->nested_in;
9889 while (nested) {
9890 can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
9891 if (can)
9892 break;
9893 nested = nested->nested_in;
9897 if (!can)
9898 return FALSE;
9900 can = can_access_type (access_class, member_class);
9901 if (!can) {
9902 MonoClass *nested = access_class->nested_in;
9903 while (nested) {
9904 can = can_access_type (nested, member_class);
9905 if (can)
9906 break;
9907 nested = nested->nested_in;
9911 if (!can)
9912 return FALSE;
9913 return TRUE;
9917 * mono_class_can_access_class:
9918 * @source_class: The source class
9919 * @target_class: The accessed class
9921 * This function returns is @target_class is visible to @source_class
9923 * Returns: TRUE if source have proper visibility and acessibility to target
9925 gboolean
9926 mono_class_can_access_class (MonoClass *source_class, MonoClass *target_class)
9928 return can_access_type (source_class, target_class);
9932 * mono_type_is_valid_enum_basetype:
9933 * @type: The MonoType to check
9935 * Returns: TRUE if the type can be used as the basetype of an enum
9937 gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
9938 switch (type->type) {
9939 case MONO_TYPE_I1:
9940 case MONO_TYPE_U1:
9941 case MONO_TYPE_BOOLEAN:
9942 case MONO_TYPE_I2:
9943 case MONO_TYPE_U2:
9944 case MONO_TYPE_CHAR:
9945 case MONO_TYPE_I4:
9946 case MONO_TYPE_U4:
9947 case MONO_TYPE_I8:
9948 case MONO_TYPE_U8:
9949 case MONO_TYPE_I:
9950 case MONO_TYPE_U:
9951 return TRUE;
9953 return FALSE;
9957 * mono_class_is_valid_enum:
9958 * @klass: An enum class to be validated
9960 * This method verify the required properties an enum should have.
9962 * Returns: TRUE if the informed enum class is valid
9964 * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
9965 * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
9966 * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
9968 gboolean mono_class_is_valid_enum (MonoClass *klass) {
9969 MonoClassField * field;
9970 gpointer iter = NULL;
9971 gboolean found_base_field = FALSE;
9973 g_assert (klass->enumtype);
9974 /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
9975 if (!klass->parent || strcmp (klass->parent->name, "Enum") || strcmp (klass->parent->name_space, "System") ) {
9976 return FALSE;
9979 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)
9980 return FALSE;
9982 while ((field = mono_class_get_fields (klass, &iter))) {
9983 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
9984 if (found_base_field)
9985 return FALSE;
9986 found_base_field = TRUE;
9987 if (!mono_type_is_valid_enum_basetype (field->type))
9988 return FALSE;
9992 if (!found_base_field)
9993 return FALSE;
9995 if (klass->method.count > 0)
9996 return FALSE;
9998 return TRUE;
10001 gboolean
10002 mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
10004 return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
10008 * mono_class_setup_interface_id:
10010 * Initializes MonoClass::interface_id if required.
10012 * LOCKING: Acquires the loader lock.
10014 void
10015 mono_class_setup_interface_id (MonoClass *class)
10017 mono_loader_lock ();
10018 if (MONO_CLASS_IS_INTERFACE (class) && !class->interface_id)
10019 class->interface_id = mono_get_unique_iid (class);
10020 mono_loader_unlock ();
10024 * mono_class_alloc_ext:
10026 * Allocate klass->ext if not already done.
10027 * LOCKING: Assumes the loader lock is held.
10029 void
10030 mono_class_alloc_ext (MonoClass *klass)
10032 if (!klass->ext) {
10033 klass->ext = mono_class_alloc0 (klass, sizeof (MonoClassExt));
10034 class_ext_size += sizeof (MonoClassExt);
10039 * mono_class_setup_interfaces:
10041 * Initialize class->interfaces/interfaces_count.
10042 * LOCKING: Acquires the loader lock.
10043 * This function can fail the type.
10045 void
10046 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
10048 int i;
10050 mono_error_init (error);
10052 if (klass->interfaces_inited)
10053 return;
10055 mono_loader_lock ();
10057 if (klass->interfaces_inited) {
10058 mono_loader_unlock ();
10059 return;
10062 if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY) {
10063 MonoType *args [1];
10065 /* generic IList, ICollection, IEnumerable */
10066 klass->interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
10067 klass->interfaces = mono_image_alloc0 (klass->image, sizeof (MonoClass*) * klass->interface_count);
10069 args [0] = &klass->element_class->byval_arg;
10070 klass->interfaces [0] = mono_class_bind_generic_parameters (
10071 mono_defaults.generic_ilist_class, 1, args, FALSE);
10072 if (klass->interface_count > 1)
10073 klass->interfaces [1] = mono_class_bind_generic_parameters (
10074 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
10075 } else if (klass->generic_class) {
10076 MonoClass *gklass = klass->generic_class->container_class;
10078 klass->interface_count = gklass->interface_count;
10079 klass->interfaces = mono_class_new0 (klass, MonoClass *, klass->interface_count);
10080 for (i = 0; i < klass->interface_count; i++) {
10081 klass->interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error);
10082 if (!mono_error_ok (error)) {
10083 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
10084 klass->interfaces = NULL;
10085 return;
10090 mono_memory_barrier ();
10092 klass->interfaces_inited = TRUE;
10094 mono_loader_unlock ();
10097 static void
10098 mono_field_resolve_type (MonoClassField *field, MonoError *error)
10100 MonoClass *class = field->parent;
10101 MonoImage *image = class->image;
10102 MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
10103 int field_idx = field - class->fields;
10105 mono_error_init (error);
10107 if (gtd) {
10108 MonoClassField *gfield = &gtd->fields [field_idx];
10109 MonoType *gtype = mono_field_get_type_checked (gfield, error);
10110 if (!mono_error_ok (error)) {
10111 char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
10112 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
10113 g_free (err_msg);
10116 field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (class), error);
10117 if (!mono_error_ok (error)) {
10118 char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
10119 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
10120 g_free (err_msg);
10122 } else {
10123 const char *sig;
10124 guint32 cols [MONO_FIELD_SIZE];
10125 MonoGenericContainer *container = NULL;
10126 int idx = class->field.first + field_idx;
10128 /*FIXME, in theory we do not lazy load SRE fields*/
10129 g_assert (!image->dynamic);
10131 if (class->generic_container) {
10132 container = class->generic_container;
10133 } else if (gtd) {
10134 container = gtd->generic_container;
10135 g_assert (container);
10138 /* class->field.first and idx points into the fieldptr table */
10139 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
10141 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) {
10142 mono_error_set_type_load_class (error, class, "Could not verify field %s signature", field->name);
10143 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
10144 return;
10147 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
10149 mono_metadata_decode_value (sig, &sig);
10150 /* FIELD signature == 0x06 */
10151 g_assert (*sig == 0x06);
10152 field->type = mono_metadata_parse_type_full (image, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
10153 if (!field->type)
10154 mono_class_set_failure_from_loader_error (class, error, g_strdup_printf ("Could not load field %s type", field->name));
10158 static guint32
10159 mono_field_resolve_flags (MonoClassField *field)
10161 MonoClass *class = field->parent;
10162 MonoImage *image = class->image;
10163 MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
10164 int field_idx = field - class->fields;
10167 if (gtd) {
10168 MonoClassField *gfield = &gtd->fields [field_idx];
10169 return mono_field_get_flags (gfield);
10170 } else {
10171 int idx = class->field.first + field_idx;
10173 /*FIXME, in theory we do not lazy load SRE fields*/
10174 g_assert (!image->dynamic);
10176 return mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_FLAGS);
10181 * mono_class_setup_basic_field_info:
10182 * @class: The class to initialize
10184 * Initializes the class->fields array of fields.
10185 * Aquires the loader lock.
10187 static void
10188 mono_class_setup_basic_field_info_locking (MonoClass *class)
10190 mono_loader_lock ();
10191 mono_class_setup_basic_field_info (class);
10192 mono_loader_unlock ();
10196 * mono_class_get_fields_lazy:
10197 * @klass: the MonoClass to act on
10199 * This routine is an iterator routine for retrieving the fields in a class.
10200 * Only minimal information about fields are loaded. Accessors must be used
10201 * for all MonoClassField returned.
10203 * You must pass a gpointer that points to zero and is treated as an opaque handle to
10204 * iterate over all of the elements. When no more values are
10205 * available, the return value is NULL.
10207 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
10209 MonoClassField*
10210 mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
10212 MonoClassField* field;
10213 if (!iter)
10214 return NULL;
10215 if (!*iter) {
10216 mono_class_setup_basic_field_info_locking (klass);
10217 if (!klass->fields)
10218 return NULL;
10219 /* start from the first */
10220 if (klass->field.count) {
10221 return *iter = &klass->fields [0];
10222 } else {
10223 /* no fields */
10224 return NULL;
10227 field = *iter;
10228 field++;
10229 if (field < &klass->fields [klass->field.count]) {
10230 return *iter = field;
10232 return NULL;
10235 char*
10236 mono_class_full_name (MonoClass *klass)
10238 return mono_type_full_name (&klass->byval_arg);