Add mono_class_can_access_class so the verifier can check if one type can access...
[mono-project.git] / mono / metadata / class.c
blob831ffa49cb333849555dcde27c2ad58ba709fed4
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 MonoStats mono_stats;
47 gboolean mono_print_vtable = FALSE;
49 /* Statistics */
50 guint32 inflated_classes, inflated_classes_size, inflated_methods_size;
51 guint32 classes_size, class_ext_size;
53 /* Function supplied by the runtime to find classes by name using information from the AOT file */
54 static MonoGetClassFromName get_class_from_name = NULL;
56 static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token);
57 static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res);
58 static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
59 static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
60 static int generic_array_methods (MonoClass *class);
61 static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos);
63 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
64 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
65 static void mono_field_resolve_type (MonoClassField *field, MonoError *error);
66 static guint32 mono_field_resolve_flags (MonoClassField *field);
67 static void mono_class_setup_vtable_full (MonoClass *class, GList *in_setup);
68 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
71 void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
72 void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL;
76 We use gclass recording to allow recursive system f types to be referenced by a parent.
78 Given the following type hierarchy:
80 class TextBox : TextBoxBase<TextBox> {}
81 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
82 class TextInput<T> : Input<T> where T: TextInput<T> {}
83 class Input<T> {}
85 The runtime tries to load TextBoxBase<>.
86 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
87 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
88 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
90 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
91 at this point, iow, both are registered in the type map and both and a NULL parent. This means
92 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
94 To fix that what we do is to record all generic instantes created while resolving the parent of
95 any generic type definition and, after resolved, correct the parent field if needed.
98 static int record_gclass_instantiation;
99 static GSList *gclass_recorded_list;
100 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
103 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
105 static void
106 enable_gclass_recording (void)
108 ++record_gclass_instantiation;
112 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
114 static void
115 disable_gclass_recording (gclass_record_func func, void *user_data)
117 GSList **head = &gclass_recorded_list;
119 g_assert (record_gclass_instantiation > 0);
120 --record_gclass_instantiation;
122 while (*head) {
123 GSList *node = *head;
124 if (func ((MonoClass*)node->data, user_data)) {
125 *head = node->next;
126 g_slist_free_1 (node);
127 } else {
128 head = &node->next;
132 /* We automatically discard all recorded gclasses when disabled. */
133 if (!record_gclass_instantiation && gclass_recorded_list) {
134 g_slist_free (gclass_recorded_list);
135 gclass_recorded_list = NULL;
140 * mono_class_from_typeref:
141 * @image: a MonoImage
142 * @type_token: a TypeRef token
144 * Creates the MonoClass* structure representing the type defined by
145 * the typeref token valid inside @image.
146 * Returns: the MonoClass* representing the typeref token, NULL ifcould
147 * not be loaded.
149 MonoClass *
150 mono_class_from_typeref (MonoImage *image, guint32 type_token)
152 MonoError error;
153 guint32 cols [MONO_TYPEREF_SIZE];
154 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
155 guint32 idx;
156 const char *name, *nspace;
157 MonoClass *res;
158 MonoImage *module;
160 if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, &error)) {
161 mono_trace_warning (MONO_TRACE_TYPE, "Failed to resolve typeref from %s due to '%s'", image->name, mono_error_get_message (&error));
162 return NULL;
165 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
167 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
168 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
170 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLTION_SCOPE_BITS;
171 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLTION_SCOPE_MASK) {
172 case MONO_RESOLTION_SCOPE_MODULE:
173 if (!idx)
174 g_error ("null ResolutionScope not yet handled");
175 /* a typedef in disguise */
176 return mono_class_from_name (image, nspace, name);
177 case MONO_RESOLTION_SCOPE_MODULEREF:
178 module = mono_image_load_module (image, idx);
179 if (module)
180 return mono_class_from_name (module, nspace, name);
181 else {
182 char *msg = g_strdup_printf ("%s%s%s", nspace, nspace [0] ? "." : "", name);
183 char *human_name;
185 human_name = mono_stringify_assembly_name (&image->assembly->aname);
186 mono_loader_set_error_type_load (msg, human_name);
187 g_free (msg);
188 g_free (human_name);
190 return NULL;
192 case MONO_RESOLTION_SCOPE_TYPEREF: {
193 MonoClass *enclosing;
194 GList *tmp;
196 if (idx == mono_metadata_token_index (type_token)) {
197 mono_loader_set_error_bad_image (g_strdup_printf ("Image %s with self-referencing typeref token %08x.", image->name, type_token));
198 return NULL;
201 enclosing = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | idx);
202 if (!enclosing)
203 return NULL;
205 if (enclosing->nested_classes_inited && enclosing->ext) {
206 /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
207 for (tmp = enclosing->ext->nested_classes; tmp; tmp = tmp->next) {
208 res = tmp->data;
209 if (strcmp (res->name, name) == 0)
210 return res;
212 } else {
213 /* Don't call mono_class_init as we might've been called by it recursively */
214 int i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, 1);
215 while (i) {
216 guint32 class_nested = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, MONO_NESTED_CLASS_NESTED);
217 guint32 string_offset = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
218 const char *nname = mono_metadata_string_heap (enclosing->image, string_offset);
220 if (strcmp (nname, name) == 0)
221 return mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested);
223 i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1);
226 g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
227 return NULL;
229 case MONO_RESOLTION_SCOPE_ASSEMBLYREF:
230 break;
233 if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
234 mono_loader_set_error_bad_image (g_strdup_printf ("Image %s with invalid assemblyref token %08x.", image->name, idx));
235 return NULL;
238 if (!image->references || !image->references [idx - 1])
239 mono_assembly_load_reference (image, idx - 1);
240 g_assert (image->references [idx - 1]);
242 /* If the assembly did not load, register this as a type load exception */
243 if (image->references [idx - 1] == REFERENCE_MISSING){
244 MonoAssemblyName aname;
245 char *human_name;
247 mono_assembly_get_assemblyref (image, idx - 1, &aname);
248 human_name = mono_stringify_assembly_name (&aname);
249 mono_loader_set_error_assembly_load (human_name, image->assembly ? image->assembly->ref_only : FALSE);
250 g_free (human_name);
252 return NULL;
255 return mono_class_from_name (image->references [idx - 1]->image, nspace, name);
259 static void *
260 mono_image_memdup (MonoImage *image, void *data, guint size)
262 void *res = mono_image_alloc (image, size);
263 memcpy (res, data, size);
264 return res;
267 /* Copy everything mono_metadata_free_array free. */
268 MonoArrayType *
269 mono_dup_array_type (MonoImage *image, MonoArrayType *a)
271 if (image) {
272 a = mono_image_memdup (image, a, sizeof (MonoArrayType));
273 if (a->sizes)
274 a->sizes = mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
275 if (a->lobounds)
276 a->lobounds = mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
277 } else {
278 a = g_memdup (a, sizeof (MonoArrayType));
279 if (a->sizes)
280 a->sizes = g_memdup (a->sizes, a->numsizes * sizeof (int));
281 if (a->lobounds)
282 a->lobounds = g_memdup (a->lobounds, a->numlobounds * sizeof (int));
284 return a;
287 /* Copy everything mono_metadata_free_method_signature free. */
288 MonoMethodSignature*
289 mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
291 int i;
293 sig = mono_metadata_signature_dup_full (image, sig);
295 sig->ret = mono_metadata_type_dup (image, sig->ret);
296 for (i = 0; i < sig->param_count; ++i)
297 sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
299 return sig;
302 static void
303 _mono_type_get_assembly_name (MonoClass *klass, GString *str)
305 MonoAssembly *ta = klass->image->assembly;
306 char *name;
308 name = mono_stringify_assembly_name (&ta->aname);
309 g_string_append_printf (str, ", %s", name);
310 g_free (name);
313 static inline void
314 mono_type_name_check_byref (MonoType *type, GString *str)
316 if (type->byref)
317 g_string_append_c (str, '&');
320 static void
321 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
322 MonoTypeNameFormat format)
324 MonoClass *klass;
326 switch (type->type) {
327 case MONO_TYPE_ARRAY: {
328 int i, rank = type->data.array->rank;
329 MonoTypeNameFormat nested_format;
331 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
332 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
334 mono_type_get_name_recurse (
335 &type->data.array->eklass->byval_arg, str, FALSE, nested_format);
336 g_string_append_c (str, '[');
337 if (rank == 1)
338 g_string_append_c (str, '*');
339 for (i = 1; i < rank; i++)
340 g_string_append_c (str, ',');
341 g_string_append_c (str, ']');
343 mono_type_name_check_byref (type, str);
345 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
346 _mono_type_get_assembly_name (type->data.array->eklass, str);
347 break;
349 case MONO_TYPE_SZARRAY: {
350 MonoTypeNameFormat nested_format;
352 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
353 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
355 mono_type_get_name_recurse (
356 &type->data.klass->byval_arg, str, FALSE, nested_format);
357 g_string_append (str, "[]");
359 mono_type_name_check_byref (type, str);
361 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
362 _mono_type_get_assembly_name (type->data.klass, str);
363 break;
365 case MONO_TYPE_PTR: {
366 MonoTypeNameFormat nested_format;
368 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
369 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
371 mono_type_get_name_recurse (
372 type->data.type, str, FALSE, nested_format);
373 g_string_append_c (str, '*');
375 mono_type_name_check_byref (type, str);
377 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
378 _mono_type_get_assembly_name (mono_class_from_mono_type (type->data.type), str);
379 break;
381 case MONO_TYPE_VAR:
382 case MONO_TYPE_MVAR:
383 if (!mono_generic_param_info (type->data.generic_param))
384 g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
385 else
386 g_string_append (str, mono_generic_param_info (type->data.generic_param)->name);
388 mono_type_name_check_byref (type, str);
390 break;
391 default:
392 klass = mono_class_from_mono_type (type);
393 if (klass->nested_in) {
394 mono_type_get_name_recurse (
395 &klass->nested_in->byval_arg, str, TRUE, format);
396 if (format == MONO_TYPE_NAME_FORMAT_IL)
397 g_string_append_c (str, '.');
398 else
399 g_string_append_c (str, '+');
400 } else if (*klass->name_space) {
401 g_string_append (str, klass->name_space);
402 g_string_append_c (str, '.');
404 if (format == MONO_TYPE_NAME_FORMAT_IL) {
405 char *s = strchr (klass->name, '`');
406 int len = s ? s - klass->name : strlen (klass->name);
408 g_string_append_len (str, klass->name, len);
409 } else
410 g_string_append (str, klass->name);
411 if (is_recursed)
412 break;
413 if (klass->generic_class) {
414 MonoGenericClass *gclass = klass->generic_class;
415 MonoGenericInst *inst = gclass->context.class_inst;
416 MonoTypeNameFormat nested_format;
417 int i;
419 nested_format = format == MONO_TYPE_NAME_FORMAT_FULL_NAME ?
420 MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format;
422 if (format == MONO_TYPE_NAME_FORMAT_IL)
423 g_string_append_c (str, '<');
424 else
425 g_string_append_c (str, '[');
426 for (i = 0; i < inst->type_argc; i++) {
427 MonoType *t = inst->type_argv [i];
429 if (i)
430 g_string_append_c (str, ',');
431 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
432 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
433 g_string_append_c (str, '[');
434 mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
435 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
436 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
437 g_string_append_c (str, ']');
439 if (format == MONO_TYPE_NAME_FORMAT_IL)
440 g_string_append_c (str, '>');
441 else
442 g_string_append_c (str, ']');
443 } else if (klass->generic_container &&
444 (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
445 (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
446 int i;
448 if (format == MONO_TYPE_NAME_FORMAT_IL)
449 g_string_append_c (str, '<');
450 else
451 g_string_append_c (str, '[');
452 for (i = 0; i < klass->generic_container->type_argc; i++) {
453 if (i)
454 g_string_append_c (str, ',');
455 g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name);
457 if (format == MONO_TYPE_NAME_FORMAT_IL)
458 g_string_append_c (str, '>');
459 else
460 g_string_append_c (str, ']');
463 mono_type_name_check_byref (type, str);
465 if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
466 (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
467 _mono_type_get_assembly_name (klass, str);
468 break;
473 * mono_type_get_name_full:
474 * @type: a type
475 * @format: the format for the return string.
478 * Returns: the string representation in a number of formats:
480 * if format is MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
481 * returned in the formatrequired by System.Reflection, this is the
482 * inverse of mono_reflection_parse_type ().
484 * if format is MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
485 * be used by the IL assembler.
487 * if format is MONO_TYPE_NAME_FORMAT_FULL_NAME
489 * if format is MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
491 char*
492 mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
494 GString* result;
496 result = g_string_new ("");
498 mono_type_get_name_recurse (type, result, FALSE, format);
500 return g_string_free (result, FALSE);
504 * mono_type_get_full_name:
505 * @class: a class
507 * Returns: the string representation for type as required by System.Reflection.
508 * The inverse of mono_reflection_parse_type ().
510 char *
511 mono_type_get_full_name (MonoClass *class)
513 return mono_type_get_name_full (mono_class_get_type (class), MONO_TYPE_NAME_FORMAT_REFLECTION);
517 * mono_type_get_name:
518 * @type: a type
520 * Returns: the string representation for type as it would be represented in IL code.
522 char*
523 mono_type_get_name (MonoType *type)
525 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
529 * mono_type_get_underlying_type:
530 * @type: a type
532 * Returns: the MonoType for the underlying integer type if @type
533 * is an enum and byref is false, otherwise the type itself.
535 MonoType*
536 mono_type_get_underlying_type (MonoType *type)
538 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype && !type->byref)
539 return mono_class_enum_basetype (type->data.klass);
540 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype && !type->byref)
541 return mono_class_enum_basetype (type->data.generic_class->container_class);
542 return type;
546 * mono_class_is_open_constructed_type:
547 * @type: a type
549 * Returns TRUE if type represents a generics open constructed type.
550 * IOW, not all type parameters required for the instantiation have
551 * been provided or it's a generic type definition.
553 * An open constructed type means it's a non realizable type. Not to
554 * be mixed up with an abstract type - we can't cast or dispatch to
555 * an open type, for example.
557 gboolean
558 mono_class_is_open_constructed_type (MonoType *t)
560 switch (t->type) {
561 case MONO_TYPE_VAR:
562 case MONO_TYPE_MVAR:
563 return TRUE;
564 case MONO_TYPE_SZARRAY:
565 return mono_class_is_open_constructed_type (&t->data.klass->byval_arg);
566 case MONO_TYPE_ARRAY:
567 return mono_class_is_open_constructed_type (&t->data.array->eklass->byval_arg);
568 case MONO_TYPE_PTR:
569 return mono_class_is_open_constructed_type (t->data.type);
570 case MONO_TYPE_GENERICINST:
571 return t->data.generic_class->context.class_inst->is_open;
572 case MONO_TYPE_CLASS:
573 case MONO_TYPE_VALUETYPE:
574 return t->data.klass->generic_container != NULL;
575 default:
576 return FALSE;
581 This is a simple function to catch the most common bad instances of generic types.
582 Specially those that might lead to further failures in the runtime.
584 static gboolean
585 is_valid_generic_argument (MonoType *type)
587 switch (type->type) {
588 case MONO_TYPE_VOID:
589 //case MONO_TYPE_TYPEDBYREF:
590 return FALSE;
592 return TRUE;
595 static MonoType*
596 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
598 mono_error_init (error);
600 switch (type->type) {
601 case MONO_TYPE_MVAR: {
602 MonoType *nt;
603 int num = mono_type_get_generic_param_num (type);
604 MonoGenericInst *inst = context->method_inst;
605 if (!inst || !inst->type_argv)
606 return NULL;
607 if (num >= inst->type_argc) {
608 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
609 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
610 num, info ? info->name : "", inst->type_argc);
611 return NULL;
614 if (!is_valid_generic_argument (inst->type_argv [num])) {
615 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
616 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
617 num, info ? info->name : "", inst->type_argv [num]->type);
618 return NULL;
621 * Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
622 * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
623 * ->byref and ->attrs from @type are propagated to the returned type.
625 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
626 nt->byref = type->byref;
627 nt->attrs = type->attrs;
628 return nt;
630 case MONO_TYPE_VAR: {
631 MonoType *nt;
632 int num = mono_type_get_generic_param_num (type);
633 MonoGenericInst *inst = context->class_inst;
634 if (!inst)
635 return NULL;
636 if (num >= inst->type_argc) {
637 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
638 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
639 num, info ? info->name : "", inst->type_argc);
640 return NULL;
642 if (!is_valid_generic_argument (inst->type_argv [num])) {
643 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
644 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
645 num, info ? info->name : "", inst->type_argv [num]->type);
646 return NULL;
648 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
649 nt->byref = type->byref;
650 nt->attrs = type->attrs;
651 return nt;
653 case MONO_TYPE_SZARRAY: {
654 MonoClass *eclass = type->data.klass;
655 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
656 if (!inflated || !mono_error_ok (error))
657 return NULL;
658 nt = mono_metadata_type_dup (image, type);
659 nt->data.klass = mono_class_from_mono_type (inflated);
660 mono_metadata_free_type (inflated);
661 return nt;
663 case MONO_TYPE_ARRAY: {
664 MonoClass *eclass = type->data.array->eklass;
665 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
666 if (!inflated || !mono_error_ok (error))
667 return NULL;
668 nt = mono_metadata_type_dup (image, type);
669 nt->data.array->eklass = mono_class_from_mono_type (inflated);
670 mono_metadata_free_type (inflated);
671 return nt;
673 case MONO_TYPE_GENERICINST: {
674 MonoGenericClass *gclass = type->data.generic_class;
675 MonoGenericInst *inst;
676 MonoType *nt;
677 if (!gclass->context.class_inst->is_open)
678 return NULL;
680 inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
681 if (!mono_error_ok (error))
682 return NULL;
683 if (inst != gclass->context.class_inst)
684 gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
686 if (gclass == type->data.generic_class)
687 return NULL;
689 nt = mono_metadata_type_dup (image, type);
690 nt->data.generic_class = gclass;
691 return nt;
693 case MONO_TYPE_CLASS:
694 case MONO_TYPE_VALUETYPE: {
695 MonoClass *klass = type->data.klass;
696 MonoGenericContainer *container = klass->generic_container;
697 MonoGenericInst *inst;
698 MonoGenericClass *gclass = NULL;
699 MonoType *nt;
701 if (!container)
702 return NULL;
704 /* We can't use context->class_inst directly, since it can have more elements */
705 inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
706 if (!mono_error_ok (error))
707 return NULL;
708 if (inst == container->context.class_inst)
709 return NULL;
711 gclass = mono_metadata_lookup_generic_class (klass, inst, klass->image->dynamic);
713 nt = mono_metadata_type_dup (image, type);
714 nt->type = MONO_TYPE_GENERICINST;
715 nt->data.generic_class = gclass;
716 return nt;
718 default:
719 return NULL;
721 return NULL;
724 MonoGenericContext *
725 mono_generic_class_get_context (MonoGenericClass *gclass)
727 return &gclass->context;
730 MonoGenericContext *
731 mono_class_get_context (MonoClass *class)
733 return class->generic_class ? mono_generic_class_get_context (class->generic_class) : NULL;
737 * mono_class_get_generic_container:
739 * Return the generic container of KLASS which should be a generic type definition.
741 MonoGenericContainer*
742 mono_class_get_generic_container (MonoClass *klass)
744 g_assert (klass->is_generic);
746 return klass->generic_container;
750 * mono_class_get_generic_class:
752 * Return the MonoGenericClass of KLASS, which should be a generic instance.
754 MonoGenericClass*
755 mono_class_get_generic_class (MonoClass *klass)
757 g_assert (klass->is_inflated);
759 return klass->generic_class;
763 * mono_class_inflate_generic_type_with_mempool:
764 * @mempool: a mempool
765 * @type: a type
766 * @context: a generics context
767 * @error: error context
769 * The same as mono_class_inflate_generic_type, but allocates the MonoType
770 * from mempool if it is non-NULL. If it is NULL, the MonoType is
771 * allocated on the heap and is owned by the caller.
772 * The returned type can potentially be the same as TYPE, so it should not be
773 * modified by the caller, and it should be freed using mono_metadata_free_type ().
775 MonoType*
776 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
778 MonoType *inflated = NULL;
779 mono_error_init (error);
781 if (context)
782 inflated = inflate_generic_type (image, type, context, error);
783 if (!mono_error_ok (error))
784 return NULL;
786 if (!inflated) {
787 MonoType *shared = mono_metadata_get_shared_type (type);
789 if (shared) {
790 return shared;
791 } else {
792 return mono_metadata_type_dup (image, type);
796 mono_stats.inflated_type_count++;
797 return inflated;
801 * mono_class_inflate_generic_type:
802 * @type: a type
803 * @context: a generics context
805 * If @type is a generic type and @context is not NULL, instantiate it using the
806 * generics context @context.
808 * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
809 * on the heap and is owned by the caller. Returns NULL on error.
811 * @deprecated Please use mono_class_inflate_generic_type_checked instead
813 MonoType*
814 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
816 MonoError error;
817 MonoType *result;
818 result = mono_class_inflate_generic_type_checked (type, context, &error);
820 if (!mono_error_ok (&error)) {
821 mono_error_cleanup (&error);
822 return NULL;
824 return result;
828 * mono_class_inflate_generic_type:
829 * @type: a type
830 * @context: a generics context
831 * @error: error context to use
833 * If @type is a generic type and @context is not NULL, instantiate it using the
834 * generics context @context.
836 * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
837 * on the heap and is owned by the caller.
839 MonoType*
840 mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
842 return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
846 * mono_class_inflate_generic_type_no_copy:
848 * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
849 * was done.
851 static MonoType*
852 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
854 MonoType *inflated = NULL;
856 mono_error_init (error);
857 if (context) {
858 inflated = inflate_generic_type (image, type, context, error);
859 if (!mono_error_ok (error))
860 return NULL;
863 if (!inflated)
864 return type;
866 mono_stats.inflated_type_count++;
867 return inflated;
870 static MonoClass*
871 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
873 MonoClass *res;
874 MonoType *inflated;
876 inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, error);
877 if (!mono_error_ok (error))
878 return NULL;
880 res = mono_class_from_mono_type (inflated);
881 mono_metadata_free_type (inflated);
883 return res;
886 * mono_class_inflate_generic_class:
888 * Inflate the class GKLASS with CONTEXT.
890 MonoClass*
891 mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context)
893 MonoError error;
894 MonoClass *res;
896 res = mono_class_inflate_generic_class_checked (gklass, context, &error);
897 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
899 return res;
904 static MonoGenericContext
905 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
907 MonoGenericInst *class_inst = NULL;
908 MonoGenericInst *method_inst = NULL;
909 MonoGenericContext res = { NULL, NULL };
911 mono_error_init (error);
913 if (context->class_inst) {
914 class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
915 if (!mono_error_ok (error))
916 goto fail;
919 if (context->method_inst) {
920 method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with, error);
921 if (!mono_error_ok (error))
922 goto fail;
925 res.class_inst = class_inst;
926 res.method_inst = method_inst;
927 fail:
928 return res;
932 * mono_class_inflate_generic_method:
933 * @method: a generic method
934 * @context: a generics context
936 * Instantiate the generic method @method using the generics context @context.
938 * Returns: the new instantiated method
940 MonoMethod *
941 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
943 return mono_class_inflate_generic_method_full (method, NULL, context);
947 * mono_class_inflate_generic_method_full:
949 * Instantiate method @method with the generic context @context.
950 * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
951 * Use mono_method_signature () and mono_method_get_header () to get the correct values.
953 MonoMethod*
954 mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context)
956 MonoError error;
957 MonoMethod *res = mono_class_inflate_generic_method_full_checked (method, klass_hint, context, &error);
958 if (!mono_error_ok (&error))
959 /*FIXME do proper error handling - on this case, kill this function. */
960 g_error ("Could not inflate generic method due to %s", mono_error_get_message (&error));
962 return res;
966 * mono_class_inflate_generic_method_full_checked:
967 * Same as mono_class_inflate_generic_method_full but return failure using @error.
969 MonoMethod*
970 mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error)
972 MonoMethod *result;
973 MonoMethodInflated *iresult, *cached;
974 MonoMethodSignature *sig;
975 MonoGenericContext tmp_context;
976 gboolean is_mb_open = FALSE;
978 mono_error_init (error);
980 /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
981 while (method->is_inflated) {
982 MonoGenericContext *method_context = mono_method_get_context (method);
983 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
985 tmp_context = inflate_generic_context (method_context, context, error);
986 if (!mono_error_ok (error))
987 return NULL;
988 context = &tmp_context;
990 if (mono_metadata_generic_context_equal (method_context, context))
991 return method;
993 method = imethod->declaring;
997 * A method only needs to be inflated if the context has argument for which it is
998 * parametric. Eg:
1000 * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
1001 * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
1004 if (!((method->is_generic && context->method_inst) ||
1005 (method->klass->generic_container && context->class_inst)))
1006 return method;
1009 * The reason for this hack is to fix the behavior of inflating generic methods that come from a MethodBuilder.
1010 * What happens is that instantiating a generic MethodBuilder with its own arguments should create a diferent object.
1011 * This is opposite to the way non-SRE MethodInfos behave.
1013 * This happens, for example, when we want to emit a recursive generic method. Given the following C# code:
1015 * void Example<T> () {
1016 * Example<T> ();
1019 * In Example, the method token must be encoded as: "void Example<!!0>()"
1021 * The reference to the first generic argument, "!!0", must be explicit otherwise it won't be inflated
1022 * properly. To get that we need to inflate the MethodBuilder with its own arguments.
1024 * On the other hand, inflating a non-SRE generic method with its own arguments should
1025 * return itself. For example:
1027 * MethodInfo m = ... //m is a generic method definition
1028 * MethodInfo res = m.MakeGenericMethod (m.GetGenericArguments ());
1029 * res == m
1031 * To allow such scenarios we must allow inflation of MethodBuilder to happen in a diferent way than
1032 * what happens with regular methods.
1034 * There is one last touch to this madness, once a TypeBuilder is finished, IOW CreateType() is called,
1035 * everything should behave like a regular type or method.
1038 is_mb_open = method->is_generic &&
1039 method->klass->image->dynamic && !method->klass->wastypebuilder && /* that is a MethodBuilder from an unfinished TypeBuilder */
1040 context->method_inst == mono_method_get_generic_container (method)->context.method_inst; /* and it's been instantiated with its own arguments. */
1042 iresult = g_new0 (MonoMethodInflated, 1);
1043 iresult->context = *context;
1044 iresult->declaring = method;
1045 iresult->method.method.is_mb_open = is_mb_open;
1047 if (!context->method_inst && method->is_generic)
1048 iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
1050 if (!context->class_inst) {
1051 g_assert (!iresult->declaring->klass->generic_class);
1052 if (iresult->declaring->klass->generic_container)
1053 iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst;
1054 else if (iresult->declaring->klass->generic_class)
1055 iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst;
1058 mono_loader_lock ();
1059 cached = mono_method_inflated_lookup (iresult, FALSE);
1060 if (cached) {
1061 mono_loader_unlock ();
1062 g_free (iresult);
1063 return (MonoMethod*)cached;
1066 mono_stats.inflated_method_count++;
1068 inflated_methods_size += sizeof (MonoMethodInflated);
1070 sig = mono_method_signature (method);
1071 if (!sig) {
1072 char *name = mono_type_get_full_name (method->klass);
1073 mono_error_set_bad_image (error, method->klass->image, "Could not resolve signature of method %s:%s", name, method->name);
1074 g_free (name);
1075 goto fail;
1078 if (sig->pinvoke) {
1079 memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
1080 } else {
1081 memcpy (&iresult->method.method, method, sizeof (MonoMethod));
1084 result = (MonoMethod *) iresult;
1085 result->is_inflated = TRUE;
1086 result->is_generic = FALSE;
1087 result->sre_method = FALSE;
1088 result->signature = NULL;
1089 result->is_mb_open = is_mb_open;
1091 if (!context->method_inst) {
1092 /* Set the generic_container of the result to the generic_container of method */
1093 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
1095 if (generic_container) {
1096 result->is_generic = 1;
1097 mono_method_set_generic_container (result, generic_container);
1101 if (!klass_hint || !klass_hint->generic_class ||
1102 klass_hint->generic_class->container_class != method->klass ||
1103 klass_hint->generic_class->context.class_inst != context->class_inst)
1104 klass_hint = NULL;
1106 if (method->klass->generic_container)
1107 result->klass = klass_hint;
1109 if (!result->klass) {
1110 MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context, error);
1111 if (!mono_error_ok (error))
1112 goto fail;
1114 result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
1115 if (inflated)
1116 mono_metadata_free_type (inflated);
1120 * FIXME: This should hold, but it doesn't:
1122 * if (result->is_inflated && mono_method_get_context (result)->method_inst &&
1123 * mono_method_get_context (result)->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)result)->declaring)->context.method_inst) {
1124 * g_assert (result->is_generic);
1127 * Fixing this here causes other things to break, hence a very
1128 * ugly hack in mini-trampolines.c - see
1129 * is_generic_method_definition().
1132 mono_method_inflated_lookup (iresult, TRUE);
1133 mono_loader_unlock ();
1134 return result;
1136 fail:
1137 mono_loader_unlock ();
1138 g_free (iresult);
1139 return NULL;
1143 * mono_get_inflated_method:
1145 * Obsolete. We keep it around since it's mentioned in the public API.
1147 MonoMethod*
1148 mono_get_inflated_method (MonoMethod *method)
1150 return method;
1154 * mono_method_get_context_general:
1155 * @method: a method
1156 * @uninflated: handle uninflated methods?
1158 * Returns the generic context of a method or NULL if it doesn't have
1159 * one. For an inflated method that's the context stored in the
1160 * method. Otherwise it's in the method's generic container or in the
1161 * generic container of the method's class.
1163 MonoGenericContext*
1164 mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
1166 if (method->is_inflated) {
1167 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1168 return &imethod->context;
1170 if (!uninflated)
1171 return NULL;
1172 if (method->is_generic)
1173 return &(mono_method_get_generic_container (method)->context);
1174 if (method->klass->generic_container)
1175 return &method->klass->generic_container->context;
1176 return NULL;
1180 * mono_method_get_context:
1181 * @method: a method
1183 * Returns the generic context for method if it's inflated, otherwise
1184 * NULL.
1186 MonoGenericContext*
1187 mono_method_get_context (MonoMethod *method)
1189 return mono_method_get_context_general (method, FALSE);
1193 * mono_method_get_generic_container:
1195 * Returns the generic container of METHOD, which should be a generic method definition.
1196 * Returns NULL if METHOD is not a generic method definition.
1197 * LOCKING: Acquires the loader lock.
1199 MonoGenericContainer*
1200 mono_method_get_generic_container (MonoMethod *method)
1202 MonoGenericContainer *container;
1204 if (!method->is_generic)
1205 return NULL;
1207 container = mono_image_property_lookup (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER);
1208 g_assert (container);
1210 return container;
1214 * mono_method_set_generic_container:
1216 * Sets the generic container of METHOD to CONTAINER.
1217 * LOCKING: Acquires the loader lock.
1219 void
1220 mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
1222 g_assert (method->is_generic);
1224 mono_image_property_insert (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
1227 /**
1228 * mono_class_find_enum_basetype:
1229 * @class: The enum class
1231 * Determine the basetype of an enum by iterating through its fields. We do this
1232 * in a separate function since it is cheaper than calling mono_class_setup_fields.
1234 static MonoType*
1235 mono_class_find_enum_basetype (MonoClass *class)
1237 MonoGenericContainer *container = NULL;
1238 MonoImage *m = class->image;
1239 const int top = class->field.count;
1240 int i;
1242 g_assert (class->enumtype);
1244 if (class->generic_container)
1245 container = class->generic_container;
1246 else if (class->generic_class) {
1247 MonoClass *gklass = class->generic_class->container_class;
1249 container = gklass->generic_container;
1250 g_assert (container);
1254 * Fetch all the field information.
1256 for (i = 0; i < top; i++){
1257 const char *sig;
1258 guint32 cols [MONO_FIELD_SIZE];
1259 int idx = class->field.first + i;
1260 MonoType *ftype;
1262 /* class->field.first and idx points into the fieldptr table */
1263 mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
1265 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
1266 continue;
1268 if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL))
1269 return NULL;
1271 sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
1272 mono_metadata_decode_value (sig, &sig);
1273 /* FIELD signature == 0x06 */
1274 if (*sig != 0x06)
1275 return NULL;
1277 ftype = mono_metadata_parse_type_full (m, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
1278 if (!ftype)
1279 return NULL;
1280 if (class->generic_class) {
1281 //FIXME do we leak here?
1282 ftype = mono_class_inflate_generic_type (ftype, mono_class_get_context (class));
1283 ftype->attrs = cols [MONO_FIELD_FLAGS];
1286 return ftype;
1289 return NULL;
1293 * Checks for MonoClass::exception_type without resolving all MonoType's into MonoClass'es
1295 static gboolean
1296 mono_type_has_exceptions (MonoType *type)
1298 switch (type->type) {
1299 case MONO_TYPE_CLASS:
1300 case MONO_TYPE_VALUETYPE:
1301 case MONO_TYPE_SZARRAY:
1302 return type->data.klass->exception_type;
1303 case MONO_TYPE_ARRAY:
1304 return type->data.array->eklass->exception_type;
1305 case MONO_TYPE_GENERICINST:
1306 return mono_generic_class_get_class (type->data.generic_class)->exception_type;
1308 return FALSE;
1312 * mono_class_alloc:
1314 * Allocate memory for some data belonging to CLASS, either from its image's mempool,
1315 * or from the heap.
1317 static gpointer
1318 mono_class_alloc (MonoClass *class, int size)
1320 if (class->generic_class)
1321 return mono_image_set_alloc (class->generic_class->owner, size);
1322 else
1323 return mono_image_alloc (class->image, size);
1326 static gpointer
1327 mono_class_alloc0 (MonoClass *class, int size)
1329 gpointer res;
1331 res = mono_class_alloc (class, size);
1332 memset (res, 0, size);
1333 return res;
1336 #define mono_class_new0(class,struct_type, n_structs) \
1337 ((struct_type *) mono_class_alloc0 ((class), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
1340 * mono_class_setup_basic_field_info:
1341 * @class: The class to initialize
1343 * Initializes the class->fields.
1344 * LOCKING: Assumes the loader lock is held.
1346 static void
1347 mono_class_setup_basic_field_info (MonoClass *class)
1349 MonoClassField *field;
1350 MonoClass *gtd;
1351 MonoImage *image;
1352 int i, top;
1354 if (class->fields)
1355 return;
1357 gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
1358 image = class->image;
1359 top = class->field.count;
1361 if (class->generic_class && class->generic_class->container_class->image->dynamic && !class->generic_class->container_class->wastypebuilder) {
1363 * This happens when a generic instance of an unfinished generic typebuilder
1364 * is used as an element type for creating an array type. We can't initialize
1365 * the fields of this class using the fields of gklass, since gklass is not
1366 * finished yet, fields could be added to it later.
1368 return;
1371 if (gtd) {
1372 mono_class_setup_basic_field_info (gtd);
1374 top = gtd->field.count;
1375 class->field.first = gtd->field.first;
1376 class->field.count = gtd->field.count;
1379 class->fields = mono_class_alloc0 (class, sizeof (MonoClassField) * top);
1382 * Fetch all the field information.
1384 for (i = 0; i < top; i++){
1385 field = &class->fields [i];
1386 field->parent = class;
1388 if (gtd) {
1389 field->name = mono_field_get_name (&gtd->fields [i]);
1390 } else {
1391 int idx = class->field.first + i;
1392 /* class->field.first and idx points into the fieldptr table */
1393 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
1394 /* The name is needed for fieldrefs */
1395 field->name = mono_metadata_string_heap (image, name_idx);
1400 /**
1401 * mono_class_setup_fields:
1402 * @class: The class to initialize
1404 * Initializes the class->fields.
1405 * LOCKING: Assumes the loader lock is held.
1407 static void
1408 mono_class_setup_fields (MonoClass *class)
1410 MonoError error;
1411 MonoImage *m = class->image;
1412 int top;
1413 guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
1414 int i, blittable = TRUE;
1415 guint32 real_size = 0;
1416 guint32 packing_size = 0;
1417 gboolean explicit_size;
1418 MonoClassField *field;
1419 MonoGenericContainer *container = NULL;
1420 MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
1422 if (class->setup_fields_called)
1423 return;
1425 if (class->generic_class && class->generic_class->container_class->image->dynamic && !class->generic_class->container_class->wastypebuilder) {
1427 * This happens when a generic instance of an unfinished generic typebuilder
1428 * is used as an element type for creating an array type. We can't initialize
1429 * the fields of this class using the fields of gklass, since gklass is not
1430 * finished yet, fields could be added to it later.
1432 return;
1435 mono_class_setup_basic_field_info (class);
1436 top = class->field.count;
1438 if (gtd) {
1439 mono_class_setup_fields (gtd);
1440 if (gtd->exception_type) {
1441 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1442 return;
1446 class->instance_size = 0;
1447 if (!class->rank)
1448 class->sizes.class_size = 0;
1450 if (class->parent) {
1451 /* For generic instances, class->parent might not have been initialized */
1452 mono_class_init (class->parent);
1453 if (!class->parent->size_inited) {
1454 mono_class_setup_fields (class->parent);
1455 if (class->parent->exception_type) {
1456 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1457 return;
1460 class->instance_size += class->parent->instance_size;
1461 class->min_align = class->parent->min_align;
1462 /* we use |= since it may have been set already */
1463 class->has_references |= class->parent->has_references;
1464 blittable = class->parent->blittable;
1465 } else {
1466 class->instance_size = sizeof (MonoObject);
1467 class->min_align = 1;
1470 /* We can't really enable 16 bytes alignment until the GC supports it.
1471 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
1472 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
1473 Bug #506144 is an example of this issue.
1475 if (class->simd_type)
1476 class->min_align = 16;
1478 /* Get the real size */
1479 explicit_size = mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &real_size);
1481 if (explicit_size) {
1482 if ((packing_size & 0xfffffff0) != 0) {
1483 char *err_msg = g_strdup_printf ("Could not load struct '%s' with packing size %d >= 16", class->name, packing_size);
1484 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
1485 return;
1487 class->packing_size = packing_size;
1488 real_size += class->instance_size;
1491 if (!top) {
1492 if (explicit_size && real_size) {
1493 class->instance_size = MAX (real_size, class->instance_size);
1495 class->blittable = blittable;
1496 mono_memory_barrier ();
1497 class->size_inited = 1;
1498 class->fields_inited = 1;
1499 return;
1502 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT)
1503 blittable = FALSE;
1505 /* Prevent infinite loops if the class references itself */
1506 class->setup_fields_called = 1;
1508 if (class->generic_container) {
1509 container = class->generic_container;
1510 } else if (gtd) {
1511 container = gtd->generic_container;
1512 g_assert (container);
1516 * Fetch all the field information.
1518 for (i = 0; i < top; i++){
1519 int idx = class->field.first + i;
1520 field = &class->fields [i];
1522 field->parent = class;
1524 if (!field->type) {
1525 mono_field_resolve_type (field, &error);
1526 if (!mono_error_ok (&error)) {
1527 /*mono_field_resolve_type already failed class*/
1528 mono_error_cleanup (&error);
1529 return;
1531 if (!field->type)
1532 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(class), field->name);
1533 g_assert (field->type);
1536 if (mono_field_is_deleted (field))
1537 continue;
1538 if (gtd) {
1539 MonoClassField *gfield = &gtd->fields [i];
1540 field->offset = gfield->offset;
1541 } else {
1542 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
1543 guint32 offset;
1544 mono_metadata_field_info (m, idx, &offset, NULL, NULL);
1545 field->offset = offset;
1547 if (field->offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1548 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Missing field layout info for %s", field->name));
1549 break;
1551 if (field->offset < -1) { /*-1 is used to encode special static fields */
1552 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Invalid negative field offset %d for %s", field->offset, field->name));
1553 break;
1558 /* Only do these checks if we still think this type is blittable */
1559 if (blittable && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1560 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
1561 blittable = FALSE;
1562 } else {
1563 MonoClass *field_class = mono_class_from_mono_type (field->type);
1564 if (field_class) {
1565 mono_class_setup_fields (field_class);
1566 if (field_class->exception_type) {
1567 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1568 break;
1571 if (!field_class || !field_class->blittable)
1572 blittable = FALSE;
1576 if (class->enumtype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1577 class->cast_class = class->element_class = mono_class_from_mono_type (field->type);
1578 blittable = class->element_class->blittable;
1581 if (mono_type_has_exceptions (field->type)) {
1582 char *class_name = mono_type_get_full_name (class);
1583 char *type_name = mono_type_full_name (field->type);
1585 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1586 g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
1587 g_free (class_name);
1588 g_free (type_name);
1589 break;
1591 /* The def_value of fields is compute lazily during vtable creation */
1594 if (class == mono_defaults.string_class)
1595 blittable = FALSE;
1597 class->blittable = blittable;
1599 if (class->enumtype && !mono_class_enum_basetype (class)) {
1600 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1601 return;
1603 if (explicit_size && real_size) {
1604 class->instance_size = MAX (real_size, class->instance_size);
1607 if (class->exception_type)
1608 return;
1609 mono_class_layout_fields (class);
1611 /*valuetypes can't be neither bigger than 1Mb or empty. */
1612 if (class->valuetype && (class->instance_size <= 0 || class->instance_size > (0x100000 + sizeof (MonoObject))))
1613 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1615 mono_memory_barrier ();
1616 class->fields_inited = 1;
1619 /**
1620 * mono_class_setup_fields_locking:
1621 * @class: The class to initialize
1623 * Initializes the class->fields array of fields.
1624 * Aquires the loader lock.
1626 void
1627 mono_class_setup_fields_locking (MonoClass *class)
1629 /* This can be checked without locks */
1630 if (class->fields_inited)
1631 return;
1632 mono_loader_lock ();
1633 mono_class_setup_fields (class);
1634 mono_loader_unlock ();
1638 * mono_class_has_references:
1640 * Returns whenever @klass->has_references is set, initializing it if needed.
1641 * Aquires the loader lock.
1643 static gboolean
1644 mono_class_has_references (MonoClass *klass)
1646 if (klass->init_pending) {
1647 /* Be conservative */
1648 return TRUE;
1649 } else {
1650 mono_class_init (klass);
1652 return klass->has_references;
1657 * mono_type_get_basic_type_from_generic:
1658 * @type: a type
1660 * Returns a closed type corresponding to the possibly open type
1661 * passed to it.
1663 MonoType*
1664 mono_type_get_basic_type_from_generic (MonoType *type)
1666 /* When we do generic sharing we let type variables stand for reference types. */
1667 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
1668 return &mono_defaults.object_class->byval_arg;
1669 return type;
1673 * mono_class_layout_fields:
1674 * @class: a class
1676 * Compute the placement of fields inside an object or struct, according to
1677 * the layout rules and set the following fields in @class:
1678 * - has_references (if the class contains instance references firled or structs that contain references)
1679 * - has_static_refs (same, but for static fields)
1680 * - instance_size (size of the object in memory)
1681 * - class_size (size needed for the static fields)
1682 * - size_inited (flag set when the instance_size is set)
1684 * LOCKING: this is supposed to be called with the loader lock held.
1686 void
1687 mono_class_layout_fields (MonoClass *class)
1689 int i;
1690 const int top = class->field.count;
1691 guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
1692 guint32 pass, passes, real_size;
1693 gboolean gc_aware_layout = FALSE;
1694 MonoClassField *field;
1697 * When we do generic sharing we need to have layout
1698 * information for open generic classes (either with a generic
1699 * context containing type variables or with a generic
1700 * container), so we don't return in that case anymore.
1704 * Enable GC aware auto layout: in this mode, reference
1705 * fields are grouped together inside objects, increasing collector
1706 * performance.
1707 * Requires that all classes whose layout is known to native code be annotated
1708 * with [StructLayout (LayoutKind.Sequential)]
1709 * Value types have gc_aware_layout disabled by default, as per
1710 * what the default is for other runtimes.
1712 /* corlib is missing [StructLayout] directives in many places */
1713 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
1714 if (!class->valuetype)
1715 gc_aware_layout = TRUE;
1718 /* Compute klass->has_references */
1720 * Process non-static fields first, since static fields might recursively
1721 * refer to the class itself.
1723 for (i = 0; i < top; i++) {
1724 MonoType *ftype;
1726 field = &class->fields [i];
1728 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1729 ftype = mono_type_get_underlying_type (field->type);
1730 ftype = mono_type_get_basic_type_from_generic (ftype);
1731 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
1732 class->has_references = TRUE;
1736 for (i = 0; i < top; i++) {
1737 MonoType *ftype;
1739 field = &class->fields [i];
1741 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1742 ftype = mono_type_get_underlying_type (field->type);
1743 ftype = mono_type_get_basic_type_from_generic (ftype);
1744 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
1745 class->has_static_refs = TRUE;
1749 for (i = 0; i < top; i++) {
1750 MonoType *ftype;
1752 field = &class->fields [i];
1754 ftype = mono_type_get_underlying_type (field->type);
1755 ftype = mono_type_get_basic_type_from_generic (ftype);
1756 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
1757 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1758 class->has_static_refs = TRUE;
1759 else
1760 class->has_references = TRUE;
1765 * Compute field layout and total size (not considering static fields)
1768 switch (layout) {
1769 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
1770 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
1772 if (gc_aware_layout)
1773 passes = 2;
1774 else
1775 passes = 1;
1777 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
1778 passes = 1;
1780 if (class->parent) {
1781 mono_class_setup_fields (class->parent);
1782 if (class->parent->exception_type) {
1783 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1784 return;
1786 real_size = class->parent->instance_size;
1787 } else {
1788 real_size = sizeof (MonoObject);
1791 for (pass = 0; pass < passes; ++pass) {
1792 for (i = 0; i < top; i++){
1793 gint32 align;
1794 guint32 size;
1795 MonoType *ftype;
1797 field = &class->fields [i];
1799 if (mono_field_is_deleted (field))
1800 continue;
1801 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1802 continue;
1804 ftype = mono_type_get_underlying_type (field->type);
1805 ftype = mono_type_get_basic_type_from_generic (ftype);
1806 if (gc_aware_layout) {
1807 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
1808 if (pass == 1)
1809 continue;
1810 } else {
1811 if (pass == 0)
1812 continue;
1816 if ((top == 1) && (class->instance_size == sizeof (MonoObject)) &&
1817 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
1818 /* This field is a hack inserted by MCS to empty structures */
1819 continue;
1822 size = mono_type_size (field->type, &align);
1824 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
1825 align = class->packing_size ? MIN (class->packing_size, align): align;
1826 /* if the field has managed references, we need to force-align it
1827 * see bug #77788
1829 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
1830 align = MAX (align, sizeof (gpointer));
1832 class->min_align = MAX (align, class->min_align);
1833 field->offset = real_size;
1834 if (align) {
1835 field->offset += align - 1;
1836 field->offset &= ~(align - 1);
1838 /*TypeBuilders produce all sort of weird things*/
1839 g_assert (class->image->dynamic || field->offset > 0);
1840 real_size = field->offset + size;
1843 class->instance_size = MAX (real_size, class->instance_size);
1845 if (class->instance_size & (class->min_align - 1)) {
1846 class->instance_size += class->min_align - 1;
1847 class->instance_size &= ~(class->min_align - 1);
1850 break;
1851 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
1852 real_size = 0;
1853 for (i = 0; i < top; i++) {
1854 gint32 align;
1855 guint32 size;
1856 MonoType *ftype;
1858 field = &class->fields [i];
1861 * There must be info about all the fields in a type if it
1862 * uses explicit layout.
1865 if (mono_field_is_deleted (field))
1866 continue;
1867 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1868 continue;
1870 size = mono_type_size (field->type, &align);
1871 align = class->packing_size ? MIN (class->packing_size, align): align;
1872 class->min_align = MAX (align, class->min_align);
1875 * When we get here, field->offset is already set by the
1876 * loader (for either runtime fields or fields loaded from metadata).
1877 * The offset is from the start of the object: this works for both
1878 * classes and valuetypes.
1880 field->offset += sizeof (MonoObject);
1881 ftype = mono_type_get_underlying_type (field->type);
1882 ftype = mono_type_get_basic_type_from_generic (ftype);
1883 if (MONO_TYPE_IS_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
1884 if (field->offset % sizeof (gpointer)) {
1885 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1890 * Calc max size.
1892 real_size = MAX (real_size, size + field->offset);
1894 class->instance_size = MAX (real_size, class->instance_size);
1895 if (class->instance_size & (class->min_align - 1)) {
1896 class->instance_size += class->min_align - 1;
1897 class->instance_size &= ~(class->min_align - 1);
1899 break;
1902 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
1904 * For small structs, set min_align to at least the struct size to improve
1905 * performance, and since the JIT memset/memcpy code assumes this and generates
1906 * unaligned accesses otherwise. See #78990 for a testcase.
1908 if (class->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
1909 class->min_align = MAX (class->min_align, class->instance_size - sizeof (MonoObject));
1912 mono_memory_barrier ();
1913 class->size_inited = 1;
1916 * Compute static field layout and size
1918 for (i = 0; i < top; i++){
1919 gint32 align;
1920 guint32 size;
1922 field = &class->fields [i];
1924 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
1925 continue;
1926 if (mono_field_is_deleted (field))
1927 continue;
1929 if (mono_type_has_exceptions (field->type)) {
1930 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1931 break;
1934 size = mono_type_size (field->type, &align);
1935 field->offset = class->sizes.class_size;
1936 /*align is always non-zero here*/
1937 field->offset += align - 1;
1938 field->offset &= ~(align - 1);
1939 class->sizes.class_size = field->offset + size;
1943 static MonoMethod*
1944 create_array_method (MonoClass *class, const char *name, MonoMethodSignature *sig)
1946 MonoMethod *method;
1948 method = (MonoMethod *) mono_image_alloc0 (class->image, sizeof (MonoMethodPInvoke));
1949 method->klass = class;
1950 method->flags = METHOD_ATTRIBUTE_PUBLIC;
1951 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
1952 method->signature = sig;
1953 method->name = name;
1954 method->slot = -1;
1955 /* .ctor */
1956 if (name [0] == '.') {
1957 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
1958 } else {
1959 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
1961 return method;
1965 * mono_class_setup_methods:
1966 * @class: a class
1968 * Initializes the 'methods' array in the klass.
1969 * Calling this method should be avoided if possible since it allocates a lot
1970 * of long-living MonoMethod structures.
1971 * Methods belonging to an interface are assigned a sequential slot starting
1972 * from 0.
1974 * On failure this function sets class->exception_type
1976 void
1977 mono_class_setup_methods (MonoClass *class)
1979 int i;
1980 MonoMethod **methods;
1982 if (class->methods)
1983 return;
1985 mono_loader_lock ();
1987 if (class->methods) {
1988 mono_loader_unlock ();
1989 return;
1992 if (class->generic_class) {
1993 MonoError error;
1994 MonoClass *gklass = class->generic_class->container_class;
1996 mono_class_init (gklass);
1997 if (!gklass->exception_type)
1998 mono_class_setup_methods (gklass);
1999 if (gklass->exception_type) {
2000 /*FIXME make exception_data less opaque so it's possible to dup it here*/
2001 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2002 mono_loader_unlock ();
2003 return;
2006 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
2007 class->method.count = gklass->method.count;
2008 methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * (class->method.count + 1));
2010 for (i = 0; i < class->method.count; i++) {
2011 methods [i] = mono_class_inflate_generic_method_full_checked (
2012 gklass->methods [i], class, mono_class_get_context (class), &error);
2013 if (!mono_error_ok (&error)) {
2014 char *method = mono_method_full_name (gklass->methods [i], TRUE);
2015 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)));
2017 g_free (method);
2018 mono_error_cleanup (&error);
2019 mono_loader_unlock ();
2020 return;
2023 } else if (class->rank) {
2024 MonoError error;
2025 MonoMethod *amethod;
2026 MonoMethodSignature *sig;
2027 int count_generic = 0, first_generic = 0;
2028 int method_num = 0;
2030 class->method.count = 3 + (class->rank > 1? 2: 1);
2032 mono_class_setup_interfaces (class, &error);
2033 g_assert (mono_error_ok (&error)); /*FIXME can this fail for array types?*/
2035 if (class->interface_count) {
2036 count_generic = generic_array_methods (class);
2037 first_generic = class->method.count;
2038 class->method.count += class->interface_count * count_generic;
2041 methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * class->method.count);
2043 sig = mono_metadata_signature_alloc (class->image, class->rank);
2044 sig->ret = &mono_defaults.void_class->byval_arg;
2045 sig->pinvoke = TRUE;
2046 sig->hasthis = TRUE;
2047 for (i = 0; i < class->rank; ++i)
2048 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2050 amethod = create_array_method (class, ".ctor", sig);
2051 methods [method_num++] = amethod;
2052 if (class->rank > 1) {
2053 sig = mono_metadata_signature_alloc (class->image, class->rank * 2);
2054 sig->ret = &mono_defaults.void_class->byval_arg;
2055 sig->pinvoke = TRUE;
2056 sig->hasthis = TRUE;
2057 for (i = 0; i < class->rank * 2; ++i)
2058 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2060 amethod = create_array_method (class, ".ctor", sig);
2061 methods [method_num++] = amethod;
2063 /* element Get (idx11, [idx2, ...]) */
2064 sig = mono_metadata_signature_alloc (class->image, class->rank);
2065 sig->ret = &class->element_class->byval_arg;
2066 sig->pinvoke = TRUE;
2067 sig->hasthis = TRUE;
2068 for (i = 0; i < class->rank; ++i)
2069 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2070 amethod = create_array_method (class, "Get", sig);
2071 methods [method_num++] = amethod;
2072 /* element& Address (idx11, [idx2, ...]) */
2073 sig = mono_metadata_signature_alloc (class->image, class->rank);
2074 sig->ret = &class->element_class->this_arg;
2075 sig->pinvoke = TRUE;
2076 sig->hasthis = TRUE;
2077 for (i = 0; i < class->rank; ++i)
2078 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2079 amethod = create_array_method (class, "Address", sig);
2080 methods [method_num++] = amethod;
2081 /* void Set (idx11, [idx2, ...], element) */
2082 sig = mono_metadata_signature_alloc (class->image, class->rank + 1);
2083 sig->ret = &mono_defaults.void_class->byval_arg;
2084 sig->pinvoke = TRUE;
2085 sig->hasthis = TRUE;
2086 for (i = 0; i < class->rank; ++i)
2087 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2088 sig->params [i] = &class->element_class->byval_arg;
2089 amethod = create_array_method (class, "Set", sig);
2090 methods [method_num++] = amethod;
2092 for (i = 0; i < class->interface_count; i++)
2093 setup_generic_array_ifaces (class, class->interfaces [i], methods, first_generic + i * count_generic);
2094 } else {
2095 methods = mono_class_alloc (class, sizeof (MonoMethod*) * class->method.count);
2096 for (i = 0; i < class->method.count; ++i) {
2097 int idx = mono_metadata_translate_token_index (class->image, MONO_TABLE_METHOD, class->method.first + i + 1);
2098 methods [i] = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | idx, class);
2102 if (MONO_CLASS_IS_INTERFACE (class)) {
2103 int slot = 0;
2104 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
2105 for (i = 0; i < class->method.count; ++i) {
2106 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
2107 methods [i]->slot = slot++;
2111 /* Needed because of the double-checking locking pattern */
2112 mono_memory_barrier ();
2114 class->methods = methods;
2116 if (mono_debugger_class_loaded_methods_func)
2117 mono_debugger_class_loaded_methods_func (class);
2119 mono_loader_unlock ();
2123 * mono_class_get_method_by_index:
2125 * Returns class->methods [index], initializing class->methods if neccesary.
2127 * LOCKING: Acquires the loader lock.
2129 MonoMethod*
2130 mono_class_get_method_by_index (MonoClass *class, int index)
2132 /* Avoid calling setup_methods () if possible */
2133 if (class->generic_class && !class->methods) {
2134 MonoClass *gklass = class->generic_class->container_class;
2135 MonoMethod *m;
2137 m = mono_class_inflate_generic_method_full (
2138 gklass->methods [index], class, mono_class_get_context (class));
2140 * If setup_methods () is called later for this class, no duplicates are created,
2141 * since inflate_generic_method guarantees that only one instance of a method
2142 * is created for each context.
2145 mono_class_setup_methods (class);
2146 g_assert (m == class->methods [index]);
2148 return m;
2149 } else {
2150 mono_class_setup_methods (class);
2151 if (class->exception_type) /*FIXME do proper error handling*/
2152 return NULL;
2153 g_assert (index >= 0 && index < class->method.count);
2154 return class->methods [index];
2159 * mono_class_get_inflated_method:
2161 * Given an inflated class CLASS and a method METHOD which should be a method of
2162 * CLASS's generic definition, return the inflated method corresponding to METHOD.
2164 MonoMethod*
2165 mono_class_get_inflated_method (MonoClass *class, MonoMethod *method)
2167 MonoClass *gklass = class->generic_class->container_class;
2168 int i;
2170 g_assert (method->klass == gklass);
2172 mono_class_setup_methods (gklass);
2173 g_assert (!gklass->exception_type); /*FIXME do proper error handling*/
2175 for (i = 0; i < gklass->method.count; ++i) {
2176 if (gklass->methods [i] == method) {
2177 if (class->methods)
2178 return class->methods [i];
2179 else
2180 return mono_class_inflate_generic_method_full (gklass->methods [i], class, mono_class_get_context (class));
2184 return NULL;
2188 * mono_class_get_vtable_entry:
2190 * Returns class->vtable [offset], computing it if neccesary. Returns NULL on failure.
2191 * LOCKING: Acquires the loader lock.
2193 MonoMethod*
2194 mono_class_get_vtable_entry (MonoClass *class, int offset)
2196 MonoMethod *m;
2198 if (class->rank == 1) {
2200 * szarrays do not overwrite any methods of Array, so we can avoid
2201 * initializing their vtables in some cases.
2203 mono_class_setup_vtable (class->parent);
2204 if (offset < class->parent->vtable_size)
2205 return class->parent->vtable [offset];
2208 if (class->generic_class) {
2209 MonoClass *gklass = class->generic_class->container_class;
2210 mono_class_setup_vtable (gklass);
2211 m = gklass->vtable [offset];
2213 m = mono_class_inflate_generic_method_full (m, class, mono_class_get_context (class));
2214 } else {
2215 mono_class_setup_vtable (class);
2216 if (class->exception_type)
2217 return NULL;
2218 m = class->vtable [offset];
2221 return m;
2225 * mono_class_get_vtable_size:
2227 * Return the vtable size for KLASS.
2230 mono_class_get_vtable_size (MonoClass *klass)
2232 mono_class_setup_vtable (klass);
2234 return klass->vtable_size;
2237 /*This method can fail the class.*/
2238 static void
2239 mono_class_setup_properties (MonoClass *class)
2241 guint startm, endm, i, j;
2242 guint32 cols [MONO_PROPERTY_SIZE];
2243 MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS];
2244 MonoProperty *properties;
2245 guint32 last;
2247 if (class->ext && class->ext->properties)
2248 return;
2250 mono_loader_lock ();
2252 if (class->ext && class->ext->properties) {
2253 mono_loader_unlock ();
2254 return;
2257 mono_class_alloc_ext (class);
2259 if (class->generic_class) {
2260 MonoClass *gklass = class->generic_class->container_class;
2262 mono_class_init (gklass);
2263 mono_class_setup_properties (gklass);
2264 if (gklass->exception_type) {
2265 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2266 mono_loader_unlock ();
2267 return;
2270 class->ext->property = gklass->ext->property;
2272 properties = mono_class_new0 (class, MonoProperty, class->ext->property.count + 1);
2274 for (i = 0; i < class->ext->property.count; i++) {
2275 MonoProperty *prop = &properties [i];
2277 *prop = gklass->ext->properties [i];
2279 if (prop->get)
2280 prop->get = mono_class_inflate_generic_method_full (
2281 prop->get, class, mono_class_get_context (class));
2282 if (prop->set)
2283 prop->set = mono_class_inflate_generic_method_full (
2284 prop->set, class, mono_class_get_context (class));
2286 prop->parent = class;
2288 } else {
2289 int first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
2290 int count = last - first;
2292 if (count) {
2293 mono_class_setup_methods (class);
2294 if (class->exception_type) {
2295 mono_loader_unlock ();
2296 return;
2300 class->ext->property.first = first;
2301 class->ext->property.count = count;
2302 properties = mono_class_alloc0 (class, sizeof (MonoProperty) * count);
2303 for (i = first; i < last; ++i) {
2304 mono_metadata_decode_table_row (class->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
2305 properties [i - first].parent = class;
2306 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
2307 properties [i - first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]);
2309 startm = mono_metadata_methods_from_property (class->image, i, &endm);
2310 for (j = startm; j < endm; ++j) {
2311 MonoMethod *method;
2313 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2315 if (class->image->uncompressed_metadata)
2316 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2317 method = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class);
2318 else
2319 method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
2321 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2322 case METHOD_SEMANTIC_SETTER:
2323 properties [i - first].set = method;
2324 break;
2325 case METHOD_SEMANTIC_GETTER:
2326 properties [i - first].get = method;
2327 break;
2328 default:
2329 break;
2334 /*Flush any pending writes as we do double checked locking on class->properties */
2335 mono_memory_barrier ();
2337 /* Leave this assignment as the last op in the function */
2338 class->ext->properties = properties;
2340 mono_loader_unlock ();
2343 static MonoMethod**
2344 inflate_method_listz (MonoMethod **methods, MonoClass *class, MonoGenericContext *context)
2346 MonoMethod **om, **retval;
2347 int count;
2349 for (om = methods, count = 0; *om; ++om, ++count)
2352 retval = g_new0 (MonoMethod*, count + 1);
2353 count = 0;
2354 for (om = methods, count = 0; *om; ++om, ++count)
2355 retval [count] = mono_class_inflate_generic_method_full (*om, class, context);
2357 return retval;
2360 /*This method can fail the class.*/
2361 static void
2362 mono_class_setup_events (MonoClass *class)
2364 int first, count;
2365 guint startm, endm, i, j;
2366 guint32 cols [MONO_EVENT_SIZE];
2367 MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS];
2368 guint32 last;
2369 MonoEvent *events;
2371 if (class->ext && class->ext->events)
2372 return;
2374 mono_loader_lock ();
2376 if (class->ext && class->ext->events) {
2377 mono_loader_unlock ();
2378 return;
2381 mono_class_alloc_ext (class);
2383 if (class->generic_class) {
2384 MonoClass *gklass = class->generic_class->container_class;
2385 MonoGenericContext *context;
2387 mono_class_setup_events (gklass);
2388 if (gklass->exception_type) {
2389 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2390 mono_loader_unlock ();
2391 return;
2394 class->ext->event = gklass->ext->event;
2395 class->ext->events = mono_class_new0 (class, MonoEvent, class->ext->event.count);
2397 if (class->ext->event.count)
2398 context = mono_class_get_context (class);
2400 for (i = 0; i < class->ext->event.count; i++) {
2401 MonoEvent *event = &class->ext->events [i];
2402 MonoEvent *gevent = &gklass->ext->events [i];
2404 event->parent = class;
2405 event->name = gevent->name;
2406 event->add = gevent->add ? mono_class_inflate_generic_method_full (gevent->add, class, context) : NULL;
2407 event->remove = gevent->remove ? mono_class_inflate_generic_method_full (gevent->remove, class, context) : NULL;
2408 event->raise = gevent->raise ? mono_class_inflate_generic_method_full (gevent->raise, class, context) : NULL;
2409 #ifndef MONO_SMALL_CONFIG
2410 event->other = gevent->other ? inflate_method_listz (gevent->other, class, context) : NULL;
2411 #endif
2412 event->attrs = gevent->attrs;
2415 mono_loader_unlock ();
2416 return;
2419 first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
2420 count = last - first;
2422 if (count) {
2423 mono_class_setup_methods (class);
2424 if (class->exception_type) {
2425 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
2426 mono_loader_unlock ();
2427 return;
2430 class->ext->event.first = first;
2431 class->ext->event.count = count;
2432 events = mono_class_alloc0 (class, sizeof (MonoEvent) * class->ext->event.count);
2433 for (i = first; i < last; ++i) {
2434 MonoEvent *event = &events [i - first];
2436 mono_metadata_decode_table_row (class->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
2437 event->parent = class;
2438 event->attrs = cols [MONO_EVENT_FLAGS];
2439 event->name = mono_metadata_string_heap (class->image, cols [MONO_EVENT_NAME]);
2441 startm = mono_metadata_methods_from_event (class->image, i, &endm);
2442 for (j = startm; j < endm; ++j) {
2443 MonoMethod *method;
2445 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2447 if (class->image->uncompressed_metadata)
2448 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2449 method = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class);
2450 else
2451 method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
2453 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2454 case METHOD_SEMANTIC_ADD_ON:
2455 event->add = method;
2456 break;
2457 case METHOD_SEMANTIC_REMOVE_ON:
2458 event->remove = method;
2459 break;
2460 case METHOD_SEMANTIC_FIRE:
2461 event->raise = method;
2462 break;
2463 case METHOD_SEMANTIC_OTHER: {
2464 #ifndef MONO_SMALL_CONFIG
2465 int n = 0;
2467 if (event->other == NULL) {
2468 event->other = g_new0 (MonoMethod*, 2);
2469 } else {
2470 while (event->other [n])
2471 n++;
2472 event->other = g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
2474 event->other [n] = method;
2475 /* NULL terminated */
2476 event->other [n + 1] = NULL;
2477 #endif
2478 break;
2480 default:
2481 break;
2485 /*Flush any pending writes as we do double checked locking on class->properties */
2486 mono_memory_barrier ();
2488 /* Leave this assignment as the last op in the function */
2489 class->ext->events = events;
2491 mono_loader_unlock ();
2495 * Global pool of interface IDs, represented as a bitset.
2496 * LOCKING: this is supposed to be accessed with the loader lock held.
2498 static MonoBitSet *global_interface_bitset = NULL;
2501 * mono_unload_interface_ids:
2502 * @bitset: bit set of interface IDs
2504 * When an image is unloaded, the interface IDs associated with
2505 * the image are put back in the global pool of IDs so the numbers
2506 * can be reused.
2508 void
2509 mono_unload_interface_ids (MonoBitSet *bitset)
2511 mono_loader_lock ();
2512 mono_bitset_sub (global_interface_bitset, bitset);
2513 mono_loader_unlock ();
2516 void
2517 mono_unload_interface_id (MonoClass *class)
2519 if (global_interface_bitset && class->interface_id) {
2520 mono_loader_lock ();
2521 mono_bitset_clear (global_interface_bitset, class->interface_id);
2522 mono_loader_unlock ();
2527 * mono_get_unique_iid:
2528 * @class: interface
2530 * Assign a unique integer ID to the interface represented by @class.
2531 * The ID will positive and as small as possible.
2532 * LOCKING: this is supposed to be called with the loader lock held.
2533 * Returns: the new ID.
2535 static guint
2536 mono_get_unique_iid (MonoClass *class)
2538 int iid;
2540 g_assert (MONO_CLASS_IS_INTERFACE (class));
2542 if (!global_interface_bitset) {
2543 global_interface_bitset = mono_bitset_new (128, 0);
2546 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
2547 if (iid < 0) {
2548 int old_size = mono_bitset_size (global_interface_bitset);
2549 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
2550 mono_bitset_free (global_interface_bitset);
2551 global_interface_bitset = new_set;
2552 iid = old_size;
2554 mono_bitset_set (global_interface_bitset, iid);
2555 /* set the bit also in the per-image set */
2556 if (!class->generic_class) {
2557 if (class->image->interface_bitset) {
2558 if (iid >= mono_bitset_size (class->image->interface_bitset)) {
2559 MonoBitSet *new_set = mono_bitset_clone (class->image->interface_bitset, iid + 1);
2560 mono_bitset_free (class->image->interface_bitset);
2561 class->image->interface_bitset = new_set;
2563 } else {
2564 class->image->interface_bitset = mono_bitset_new (iid + 1, 0);
2566 mono_bitset_set (class->image->interface_bitset, iid);
2569 #ifndef MONO_SMALL_CONFIG
2570 if (mono_print_vtable) {
2571 int generic_id;
2572 char *type_name = mono_type_full_name (&class->byval_arg);
2573 if (class->generic_class && !class->generic_class->context.class_inst->is_open) {
2574 generic_id = class->generic_class->context.class_inst->id;
2575 g_assert (generic_id != 0);
2576 } else {
2577 generic_id = 0;
2579 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, class->image->name, type_name, generic_id);
2580 g_free (type_name);
2582 #endif
2584 g_assert (iid <= 65535);
2585 return iid;
2588 static void
2589 collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, MonoError *error)
2591 int i;
2592 MonoClass *ic;
2594 mono_class_setup_interfaces (klass, error);
2595 if (!mono_error_ok (error))
2596 return;
2598 for (i = 0; i < klass->interface_count; i++) {
2599 ic = klass->interfaces [i];
2601 if (*res == NULL)
2602 *res = g_ptr_array_new ();
2603 g_ptr_array_add (*res, ic);
2604 mono_class_init (ic);
2605 if (ic->exception_type) {
2606 mono_error_set_type_load_class (error, ic, "Error Loading class");
2607 return;
2610 collect_implemented_interfaces_aux (ic, res, error);
2611 if (!mono_error_ok (error))
2612 return;
2616 GPtrArray*
2617 mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error)
2619 GPtrArray *res = NULL;
2621 collect_implemented_interfaces_aux (klass, &res, error);
2622 if (!mono_error_ok (error)) {
2623 if (res)
2624 g_ptr_array_free (res, TRUE);
2625 return NULL;
2627 return res;
2630 static int
2631 compare_interface_ids (const void *p_key, const void *p_element) {
2632 const MonoClass *key = p_key;
2633 const MonoClass *element = *(MonoClass**) p_element;
2635 return (key->interface_id - element->interface_id);
2638 /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/
2640 mono_class_interface_offset (MonoClass *klass, MonoClass *itf) {
2641 MonoClass **result = bsearch (
2642 itf,
2643 klass->interfaces_packed,
2644 klass->interface_offsets_count,
2645 sizeof (MonoClass *),
2646 compare_interface_ids);
2647 if (result) {
2648 return klass->interface_offsets_packed [result - (klass->interfaces_packed)];
2649 } else {
2650 return -1;
2655 * mono_class_interface_offset_with_variance:
2657 * Return the interface offset of @itf in @klass. Sets @non_exact_match to TRUE if the match required variance check
2658 * If @itf is an interface with generic variant arguments, try to find the compatible one.
2660 * Note that this function is responsible for resolving ambiguities. Right now we use whatever ordering interfaces_packed gives us.
2662 * FIXME figure out MS disambiguation rules and fix this function.
2665 mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match) {
2666 int i = mono_class_interface_offset (klass, itf);
2667 *non_exact_match = FALSE;
2668 if (i >= 0)
2669 return i;
2671 if (!mono_class_has_variant_generic_params (itf))
2672 return -1;
2674 for (i = 0; i < klass->interface_offsets_count; i++) {
2675 if (mono_class_is_variant_compatible (itf, klass->interfaces_packed [i], FALSE)) {
2676 *non_exact_match = TRUE;
2677 return klass->interface_offsets_packed [i];
2681 return -1;
2684 static void
2685 print_implemented_interfaces (MonoClass *klass) {
2686 char *name;
2687 MonoError error;
2688 GPtrArray *ifaces = NULL;
2689 int i;
2690 int ancestor_level = 0;
2692 name = mono_type_get_full_name (klass);
2693 printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
2694 g_free (name);
2696 for (i = 0; i < klass->interface_offsets_count; i++)
2697 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
2698 klass->interfaces_packed [i]->interface_id,
2699 klass->interface_offsets_packed [i],
2700 klass->interfaces_packed [i]->method.count,
2701 klass->interfaces_packed [i]->name_space,
2702 klass->interfaces_packed [i]->name );
2703 printf ("Interface flags: ");
2704 for (i = 0; i <= klass->max_interface_id; i++)
2705 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
2706 printf ("(%d,T)", i);
2707 else
2708 printf ("(%d,F)", i);
2709 printf ("\n");
2710 printf ("Dump interface flags:");
2711 #ifdef COMPRESSED_INTERFACE_BITMAP
2713 const uint8_t* p = klass->interface_bitmap;
2714 i = klass->max_interface_id;
2715 while (i > 0) {
2716 printf (" %d x 00 %02X", p [0], p [1]);
2717 i -= p [0] * 8;
2718 i -= 8;
2721 #else
2722 for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
2723 printf (" %02X", klass->interface_bitmap [i]);
2724 #endif
2725 printf ("\n");
2726 while (klass != NULL) {
2727 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
2728 ifaces = mono_class_get_implemented_interfaces (klass, &error);
2729 if (!mono_error_ok (&error)) {
2730 printf (" Type failed due to %s\n", mono_error_get_message (&error));
2731 mono_error_cleanup (&error);
2732 } else if (ifaces) {
2733 for (i = 0; i < ifaces->len; i++) {
2734 MonoClass *ic = g_ptr_array_index (ifaces, i);
2735 printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
2736 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
2737 ic->interface_id,
2738 mono_class_interface_offset (klass, ic),
2739 ic->method.count,
2740 ic->name_space,
2741 ic->name );
2743 g_ptr_array_free (ifaces, TRUE);
2745 ancestor_level ++;
2746 klass = klass->parent;
2750 static MonoClass*
2751 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
2753 MonoType *args [1];
2754 args [0] = &arg0->byval_arg;
2756 return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
2759 static MonoClass*
2760 array_class_get_if_rank (MonoClass *class, guint rank)
2762 return rank ? mono_array_class_get (class, rank) : class;
2765 static void
2766 fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *eclass, int rank)
2768 valuetype_types [0] = eclass;
2769 if (eclass == mono_defaults.int16_class)
2770 valuetype_types [1] = mono_defaults.uint16_class;
2771 else if (eclass == mono_defaults.uint16_class)
2772 valuetype_types [1] = mono_defaults.int16_class;
2773 else if (eclass == mono_defaults.int32_class)
2774 valuetype_types [1] = mono_defaults.uint32_class;
2775 else if (eclass == mono_defaults.uint32_class)
2776 valuetype_types [1] = mono_defaults.int32_class;
2777 else if (eclass == mono_defaults.int64_class)
2778 valuetype_types [1] = mono_defaults.uint64_class;
2779 else if (eclass == mono_defaults.uint64_class)
2780 valuetype_types [1] = mono_defaults.int64_class;
2781 else if (eclass == mono_defaults.byte_class)
2782 valuetype_types [1] = mono_defaults.sbyte_class;
2783 else if (eclass == mono_defaults.sbyte_class)
2784 valuetype_types [1] = mono_defaults.byte_class;
2785 else if (eclass->enumtype && mono_class_enum_basetype (eclass))
2786 valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass));
2789 /* this won't be needed once bug #325495 is completely fixed
2790 * though we'll need something similar to know which interfaces to allow
2791 * in arrays when they'll be lazyly created
2793 * FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
2794 * MS returns diferrent types based on which instance is called. For example:
2795 * object obj = new byte[10][];
2796 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
2797 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
2798 * a != b ==> true
2800 * Fixing this should kill quite some code, save some bits and improve compatibility.
2802 static MonoClass**
2803 get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enumerator)
2805 MonoClass *eclass = class->element_class;
2806 static MonoClass* generic_icollection_class = NULL;
2807 static MonoClass* generic_ienumerable_class = NULL;
2808 static MonoClass* generic_ienumerator_class = NULL;
2809 static MonoClass* generic_ireadonlylist_class = NULL;
2810 static MonoClass* generic_ireadonlycollection_class = NULL;
2811 MonoClass *valuetype_types[2] = { NULL, NULL };
2812 MonoClass **interfaces = NULL;
2813 int i, nifaces, interface_count, real_count, original_rank;
2814 int all_interfaces;
2815 gboolean internal_enumerator;
2816 gboolean eclass_is_valuetype;
2818 if (!mono_defaults.generic_ilist_class) {
2819 *num = 0;
2820 return NULL;
2822 internal_enumerator = FALSE;
2823 eclass_is_valuetype = FALSE;
2824 original_rank = eclass->rank;
2825 if (class->byval_arg.type != MONO_TYPE_SZARRAY) {
2826 if (class->generic_class && class->nested_in == mono_defaults.array_class && strcmp (class->name, "InternalEnumerator`1") == 0) {
2828 * For a Enumerator<T[]> we need to get the list of interfaces for T.
2830 eclass = mono_class_from_mono_type (class->generic_class->context.class_inst->type_argv [0]);
2831 original_rank = eclass->rank;
2832 if (!eclass->rank)
2833 eclass = eclass->element_class;
2834 internal_enumerator = TRUE;
2835 *is_enumerator = TRUE;
2836 } else {
2837 *num = 0;
2838 return NULL;
2843 * with this non-lazy impl we can't implement all the interfaces so we do just the minimal stuff
2844 * for deep levels of arrays of arrays (string[][] has all the interfaces, string[][][] doesn't)
2846 all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
2848 if (!generic_icollection_class) {
2849 generic_icollection_class = mono_class_from_name (mono_defaults.corlib,
2850 "System.Collections.Generic", "ICollection`1");
2851 generic_ienumerable_class = mono_class_from_name (mono_defaults.corlib,
2852 "System.Collections.Generic", "IEnumerable`1");
2853 generic_ienumerator_class = mono_class_from_name (mono_defaults.corlib,
2854 "System.Collections.Generic", "IEnumerator`1");
2855 generic_ireadonlylist_class = mono_class_from_name (mono_defaults.corlib,
2856 "System.Collections.Generic", "IReadOnlyList`1");
2857 generic_ireadonlycollection_class = mono_class_from_name (mono_defaults.corlib,
2858 "System.Collections.Generic", "IReadOnlyCollection`1");
2861 mono_class_init (eclass);
2864 * Arrays in 2.0 need to implement a number of generic interfaces
2865 * (IList`1, ICollection`1, IEnumerable`1 for a number of types depending
2866 * on the element class). For net 4.5, we also need to implement IReadOnlyList`1/IReadOnlyCollection`1.
2867 * We collect the types needed to build the
2868 * instantiations in interfaces at intervals of 3/5, because 3/5 are
2869 * the generic interfaces needed to implement.
2871 nifaces = generic_ireadonlylist_class ? 5 : 3;
2872 if (eclass->valuetype) {
2873 fill_valuetype_array_derived_types (valuetype_types, eclass, original_rank);
2875 /* IList, ICollection, IEnumerable, IReadOnlyList`1 */
2876 real_count = interface_count = valuetype_types [1] ? (nifaces * 2) : nifaces;
2877 if (internal_enumerator) {
2878 ++real_count;
2879 if (valuetype_types [1])
2880 ++real_count;
2883 interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
2884 interfaces [0] = valuetype_types [0];
2885 if (valuetype_types [1])
2886 interfaces [nifaces] = valuetype_types [1];
2888 eclass_is_valuetype = TRUE;
2889 } else {
2890 int j;
2891 int idepth = eclass->idepth;
2892 if (!internal_enumerator)
2893 idepth--;
2895 // FIXME: This doesn't seem to work/required for generic params
2896 if (!(eclass->this_arg.type == MONO_TYPE_VAR || eclass->this_arg.type == MONO_TYPE_MVAR || (eclass->image->dynamic && !eclass->wastypebuilder)))
2897 mono_class_setup_interface_offsets (eclass);
2899 interface_count = all_interfaces? eclass->interface_offsets_count: eclass->interface_count;
2900 /* we add object for interfaces and the supertypes for the other
2901 * types. The last of the supertypes is the element class itself which we
2902 * already created the explicit interfaces for (so we include it for IEnumerator
2903 * and exclude it for arrays).
2905 if (MONO_CLASS_IS_INTERFACE (eclass))
2906 interface_count++;
2907 else
2908 interface_count += idepth;
2909 if (eclass->rank && eclass->element_class->valuetype) {
2910 fill_valuetype_array_derived_types (valuetype_types, eclass->element_class, original_rank);
2911 if (valuetype_types [1])
2912 ++interface_count;
2914 /* IList, ICollection, IEnumerable, IReadOnlyList */
2915 interface_count *= nifaces;
2916 real_count = interface_count;
2917 if (internal_enumerator) {
2918 real_count += (MONO_CLASS_IS_INTERFACE (eclass) ? 1 : idepth) + eclass->interface_offsets_count;
2919 if (valuetype_types [1])
2920 ++real_count;
2922 interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
2923 if (MONO_CLASS_IS_INTERFACE (eclass)) {
2924 interfaces [0] = mono_defaults.object_class;
2925 j = nifaces;
2926 } else {
2927 j = 0;
2928 for (i = 0; i < idepth; i++) {
2929 mono_class_init (eclass->supertypes [i]);
2930 interfaces [j] = eclass->supertypes [i];
2931 j += nifaces;
2934 if (all_interfaces) {
2935 for (i = 0; i < eclass->interface_offsets_count; i++) {
2936 interfaces [j] = eclass->interfaces_packed [i];
2937 j += nifaces;
2939 } else {
2940 for (i = 0; i < eclass->interface_count; i++) {
2941 interfaces [j] = eclass->interfaces [i];
2942 j += nifaces;
2945 if (valuetype_types [1]) {
2946 interfaces [j] = array_class_get_if_rank (valuetype_types [1], original_rank);
2947 j += nifaces;
2951 /* instantiate the generic interfaces */
2952 for (i = 0; i < interface_count; i += nifaces) {
2953 MonoClass *iface = interfaces [i];
2955 interfaces [i + 0] = inflate_class_one_arg (mono_defaults.generic_ilist_class, iface);
2956 interfaces [i + 1] = inflate_class_one_arg (generic_icollection_class, iface);
2957 interfaces [i + 2] = inflate_class_one_arg (generic_ienumerable_class, iface);
2958 if (generic_ireadonlylist_class) {
2959 interfaces [i + 3] = inflate_class_one_arg (generic_ireadonlylist_class, iface);
2960 interfaces [i + 4] = inflate_class_one_arg (generic_ireadonlycollection_class, iface);
2963 if (internal_enumerator) {
2964 int j;
2965 /* instantiate IEnumerator<iface> */
2966 for (i = 0; i < interface_count; i++) {
2967 interfaces [i] = inflate_class_one_arg (generic_ienumerator_class, interfaces [i]);
2969 j = interface_count;
2970 if (!eclass_is_valuetype) {
2971 if (MONO_CLASS_IS_INTERFACE (eclass)) {
2972 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, mono_defaults.object_class);
2973 j ++;
2974 } else {
2975 for (i = 0; i < eclass->idepth; i++) {
2976 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->supertypes [i]);
2977 j ++;
2980 for (i = 0; i < eclass->interface_offsets_count; i++) {
2981 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, eclass->interfaces_packed [i]);
2982 j ++;
2984 } else {
2985 interfaces [j++] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [0], original_rank));
2987 if (valuetype_types [1])
2988 interfaces [j] = inflate_class_one_arg (generic_ienumerator_class, array_class_get_if_rank (valuetype_types [1], original_rank));
2990 #if 0
2992 char *type_name = mono_type_get_name_full (&class->byval_arg, 0);
2993 for (i = 0; i < real_count; ++i) {
2994 char *name = mono_type_get_name_full (&interfaces [i]->byval_arg, 0);
2995 g_print ("%s implements %s\n", type_name, name);
2996 g_free (name);
2998 g_free (type_name);
3000 #endif
3001 *num = real_count;
3002 return interfaces;
3005 static int
3006 find_array_interface (MonoClass *klass, const char *name)
3008 int i;
3009 for (i = 0; i < klass->interface_count; ++i) {
3010 if (strcmp (klass->interfaces [i]->name, name) == 0)
3011 return i;
3013 return -1;
3017 * Return the number of virtual methods.
3018 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
3019 * Return -1 on failure.
3020 * FIXME It would be nice if this information could be cached somewhere.
3022 static int
3023 count_virtual_methods (MonoClass *class)
3025 int i, count = 0;
3026 guint32 flags;
3027 class = mono_class_get_generic_type_definition (class); /*We can find this information by looking at the GTD*/
3029 if (class->methods || !MONO_CLASS_HAS_STATIC_METADATA (class)) {
3030 mono_class_setup_methods (class);
3031 if (class->exception_type)
3032 return -1;
3034 for (i = 0; i < class->method.count; ++i) {
3035 flags = class->methods [i]->flags;
3036 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3037 ++count;
3039 } else {
3040 for (i = 0; i < class->method.count; ++i) {
3041 flags = mono_metadata_decode_table_row_col (class->image, MONO_TABLE_METHOD, class->method.first + i, MONO_METHOD_FLAGS);
3043 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3044 ++count;
3047 return count;
3050 static int
3051 find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic)
3053 int m, l = 0;
3054 if (!num_ifaces)
3055 return -1;
3056 while (1) {
3057 if (l > num_ifaces)
3058 return -1;
3059 m = (l + num_ifaces) / 2;
3060 if (interfaces_full [m] == ic)
3061 return m;
3062 if (l == num_ifaces)
3063 return -1;
3064 if (!interfaces_full [m] || interfaces_full [m]->interface_id > ic->interface_id) {
3065 num_ifaces = m - 1;
3066 } else {
3067 l = m + 1;
3072 static int
3073 find_interface_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic)
3075 int i = find_interface (num_ifaces, interfaces_full, ic);
3076 if (ic >= 0)
3077 return interface_offsets_full [i];
3078 return -1;
3081 static mono_bool
3082 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
3084 int i = find_interface (num_ifaces, interfaces_full, ic);
3085 if (i >= 0) {
3086 if (!force_set)
3087 return TRUE;
3088 interface_offsets_full [i] = offset;
3089 return FALSE;
3091 for (i = 0; i < num_ifaces; ++i) {
3092 if (interfaces_full [i]) {
3093 int end;
3094 if (interfaces_full [i]->interface_id < ic->interface_id)
3095 continue;
3096 end = i + 1;
3097 while (end < num_ifaces && interfaces_full [end]) end++;
3098 memmove (interfaces_full + i + 1, interfaces_full + i, sizeof (MonoClass*) * (end - i));
3099 memmove (interface_offsets_full + i + 1, interface_offsets_full + i, sizeof (int) * (end - i));
3101 interfaces_full [i] = ic;
3102 interface_offsets_full [i] = offset;
3103 break;
3105 return FALSE;
3108 #ifdef COMPRESSED_INTERFACE_BITMAP
3111 * Compressed interface bitmap design.
3113 * Interface bitmaps take a large amount of memory, because their size is
3114 * linear with the maximum interface id assigned in the process (each interface
3115 * is assigned a unique id as it is loaded). The number of interface classes
3116 * is high because of the many implicit interfaces implemented by arrays (we'll
3117 * need to lazy-load them in the future).
3118 * Most classes implement a very small number of interfaces, so the bitmap is
3119 * sparse. This bitmap needs to be checked by interface casts, so access to the
3120 * needed bit must be fast and doable with few jit instructions.
3122 * The current compression format is as follows:
3123 * *) it is a sequence of one or more two-byte elements
3124 * *) the first byte in the element is the count of empty bitmap bytes
3125 * at the current bitmap position
3126 * *) the second byte in the element is an actual bitmap byte at the current
3127 * bitmap position
3129 * As an example, the following compressed bitmap bytes:
3130 * 0x07 0x01 0x00 0x7
3131 * correspond to the following bitmap:
3132 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
3134 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
3135 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
3136 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
3140 * mono_compress_bitmap:
3141 * @dest: destination buffer
3142 * @bitmap: bitmap buffer
3143 * @size: size of @bitmap in bytes
3145 * This is a mono internal function.
3146 * The @bitmap data is compressed into a format that is small but
3147 * still searchable in few instructions by the JIT and runtime.
3148 * The compressed data is stored in the buffer pointed to by the
3149 * @dest array. Passing a #NULL value for @dest allows to just compute
3150 * the size of the buffer.
3151 * This compression algorithm assumes the bits set in the bitmap are
3152 * few and far between, like in interface bitmaps.
3153 * Returns: the size of the compressed bitmap in bytes.
3156 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
3158 int numz = 0;
3159 int res = 0;
3160 const uint8_t *end = bitmap + size;
3161 while (bitmap < end) {
3162 if (*bitmap || numz == 255) {
3163 if (dest) {
3164 *dest++ = numz;
3165 *dest++ = *bitmap;
3167 res += 2;
3168 numz = 0;
3169 bitmap++;
3170 continue;
3172 bitmap++;
3173 numz++;
3175 if (numz) {
3176 res += 2;
3177 if (dest) {
3178 *dest++ = numz;
3179 *dest++ = 0;
3182 return res;
3186 * mono_class_interface_match:
3187 * @bitmap: a compressed bitmap buffer
3188 * @id: the index to check in the bitmap
3190 * This is a mono internal function.
3191 * Checks if a bit is set in a compressed interface bitmap. @id must
3192 * be already checked for being smaller than the maximum id encoded in the
3193 * bitmap.
3195 * Returns: a non-zero value if bit @id is set in the bitmap @bitmap,
3196 * #FALSE otherwise.
3199 mono_class_interface_match (const uint8_t *bitmap, int id)
3201 while (TRUE) {
3202 id -= bitmap [0] * 8;
3203 if (id < 8) {
3204 if (id < 0)
3205 return 0;
3206 return bitmap [1] & (1 << id);
3208 bitmap += 2;
3209 id -= 8;
3212 #endif
3215 * LOCKING: this is supposed to be called with the loader lock held.
3216 * Return -1 on failure and set exception_type
3218 static int
3219 setup_interface_offsets (MonoClass *class, int cur_slot, gboolean overwrite)
3221 MonoError error;
3222 MonoClass *k, *ic;
3223 int i, j, max_iid, num_ifaces;
3224 MonoClass **interfaces_full = NULL;
3225 int *interface_offsets_full = NULL;
3226 GPtrArray *ifaces;
3227 GPtrArray **ifaces_array = NULL;
3228 int interface_offsets_count;
3229 MonoClass **array_interfaces = NULL;
3230 int num_array_interfaces;
3231 int is_enumerator = FALSE;
3233 mono_class_setup_supertypes (class);
3235 * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator<T>
3236 * implicit interfaces have the property that they are assigned the same slot in the
3237 * vtables for compatible interfaces
3239 array_interfaces = get_implicit_generic_array_interfaces (class, &num_array_interfaces, &is_enumerator);
3241 /* compute maximum number of slots and maximum interface id */
3242 max_iid = 0;
3243 num_ifaces = num_array_interfaces; /* this can include duplicated ones */
3244 ifaces_array = g_new0 (GPtrArray *, class->idepth);
3245 for (j = 0; j < class->idepth; j++) {
3246 k = class->supertypes [j];
3247 num_ifaces += k->interface_count;
3248 for (i = 0; i < k->interface_count; i++) {
3249 ic = k->interfaces [i];
3251 if (!ic->inited)
3252 mono_class_init (ic);
3254 if (max_iid < ic->interface_id)
3255 max_iid = ic->interface_id;
3257 ifaces = mono_class_get_implemented_interfaces (k, &error);
3258 if (!mono_error_ok (&error)) {
3259 char *name = mono_type_get_full_name (k);
3260 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)));
3261 g_free (name);
3262 mono_error_cleanup (&error);
3263 cur_slot = -1;
3264 goto end;
3266 if (ifaces) {
3267 num_ifaces += ifaces->len;
3268 for (i = 0; i < ifaces->len; ++i) {
3269 ic = g_ptr_array_index (ifaces, i);
3270 if (max_iid < ic->interface_id)
3271 max_iid = ic->interface_id;
3273 ifaces_array [j] = ifaces;
3277 for (i = 0; i < num_array_interfaces; ++i) {
3278 ic = array_interfaces [i];
3279 mono_class_init (ic);
3280 if (max_iid < ic->interface_id)
3281 max_iid = ic->interface_id;
3284 if (MONO_CLASS_IS_INTERFACE (class)) {
3285 num_ifaces++;
3286 if (max_iid < class->interface_id)
3287 max_iid = class->interface_id;
3289 class->max_interface_id = max_iid;
3290 /* compute vtable offset for interfaces */
3291 interfaces_full = g_malloc0 (sizeof (MonoClass*) * num_ifaces);
3292 interface_offsets_full = g_malloc (sizeof (int) * num_ifaces);
3294 for (i = 0; i < num_ifaces; i++) {
3295 interface_offsets_full [i] = -1;
3298 /* skip the current class */
3299 for (j = 0; j < class->idepth - 1; j++) {
3300 k = class->supertypes [j];
3301 ifaces = ifaces_array [j];
3303 if (ifaces) {
3304 for (i = 0; i < ifaces->len; ++i) {
3305 int io;
3306 ic = g_ptr_array_index (ifaces, i);
3308 /*Force the sharing of interface offsets between parent and subtypes.*/
3309 io = mono_class_interface_offset (k, ic);
3310 g_assert (io >= 0);
3311 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
3316 g_assert (class == class->supertypes [class->idepth - 1]);
3317 ifaces = ifaces_array [class->idepth - 1];
3318 if (ifaces) {
3319 for (i = 0; i < ifaces->len; ++i) {
3320 int count;
3321 ic = g_ptr_array_index (ifaces, i);
3322 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
3323 continue;
3324 count = count_virtual_methods (ic);
3325 if (count == -1) {
3326 char *name = mono_type_get_full_name (ic);
3327 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error calculating interface offset of %s", name));
3328 g_free (name);
3329 cur_slot = -1;
3330 goto end;
3332 cur_slot += count;
3336 if (MONO_CLASS_IS_INTERFACE (class))
3337 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, class, cur_slot, TRUE);
3339 if (num_array_interfaces) {
3340 if (is_enumerator) {
3341 int ienumerator_idx = find_array_interface (class, "IEnumerator`1");
3342 int ienumerator_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, class->interfaces [ienumerator_idx]);
3343 g_assert (ienumerator_offset >= 0);
3344 for (i = 0; i < num_array_interfaces; ++i) {
3345 ic = array_interfaces [i];
3346 if (strcmp (ic->name, "IEnumerator`1") == 0)
3347 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, ienumerator_offset, TRUE);
3348 else
3349 g_assert_not_reached ();
3350 /*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);*/
3352 } else {
3353 int ilist_offset, icollection_offset, ienumerable_offset, ireadonlylist_offset, ireadonlycollection_offset;
3354 int ilist_iface_idx = find_array_interface (class, "IList`1");
3355 MonoClass* ilist_class = class->interfaces [ilist_iface_idx];
3356 int ireadonlylist_iface_idx = find_array_interface (class, "IReadOnlyList`1");
3357 MonoClass* ireadonlylist_class = ireadonlylist_iface_idx != -1 ? class->interfaces [ireadonlylist_iface_idx] : NULL;
3358 int icollection_iface_idx = find_array_interface (ilist_class, "ICollection`1");
3359 int ienumerable_iface_idx = find_array_interface (ilist_class, "IEnumerable`1");
3360 int ireadonlycollection_iface_idx = ireadonlylist_iface_idx != -1 ? find_array_interface (ireadonlylist_class, "IReadOnlyCollection`1") : -1;
3361 ilist_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, class->interfaces [ilist_iface_idx]);
3362 icollection_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [icollection_iface_idx]);
3363 ienumerable_offset = find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ilist_class->interfaces [ienumerable_iface_idx]);
3364 ireadonlylist_offset = ireadonlylist_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, class->interfaces [ireadonlylist_iface_idx]) : -1;
3365 ireadonlycollection_offset = ireadonlycollection_iface_idx != -1 ? find_interface_offset (num_ifaces, interfaces_full, interface_offsets_full, ireadonlylist_class->interfaces [ireadonlycollection_iface_idx]) : -1;
3366 g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0);
3367 for (i = 0; i < num_array_interfaces; ++i) {
3368 int offset;
3369 ic = array_interfaces [i];
3370 if (ic->generic_class->container_class == mono_defaults.generic_ilist_class)
3371 offset = ilist_offset;
3372 else if (strcmp (ic->name, "ICollection`1") == 0)
3373 offset = icollection_offset;
3374 else if (strcmp (ic->name, "IEnumerable`1") == 0)
3375 offset = ienumerable_offset;
3376 else if (strcmp (ic->name, "IReadOnlyList`1") == 0)
3377 offset = ireadonlylist_offset;
3378 else if (strcmp (ic->name, "IReadOnlyCollection`1") == 0)
3379 offset = ireadonlycollection_offset;
3380 else
3381 g_assert_not_reached ();
3382 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, offset, TRUE);
3383 /*g_print ("type %s has %s offset at %d (%s)\n", class->name, ic->name, offset, class->interfaces [0]->name);*/
3388 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
3389 if (interface_offsets_full [i] != -1) {
3390 interface_offsets_count ++;
3395 * We might get called multiple times:
3396 * - mono_class_init ()
3397 * - mono_class_setup_vtable ().
3398 * - mono_class_setup_interface_offsets ().
3399 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
3400 * means we have to overwrite those when called from other places (#4440).
3402 if (class->interfaces_packed && !overwrite) {
3403 g_assert (class->interface_offsets_count == interface_offsets_count);
3404 } else {
3405 uint8_t *bitmap;
3406 int bsize;
3407 class->interface_offsets_count = interface_offsets_count;
3408 class->interfaces_packed = mono_class_alloc (class, sizeof (MonoClass*) * interface_offsets_count);
3409 class->interface_offsets_packed = mono_class_alloc (class, sizeof (guint16) * interface_offsets_count);
3410 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
3411 #ifdef COMPRESSED_INTERFACE_BITMAP
3412 bitmap = g_malloc0 (bsize);
3413 #else
3414 bitmap = mono_class_alloc0 (class, bsize);
3415 #endif
3416 for (i = 0; i < interface_offsets_count; i++) {
3417 int id = interfaces_full [i]->interface_id;
3418 bitmap [id >> 3] |= (1 << (id & 7));
3419 class->interfaces_packed [i] = interfaces_full [i];
3420 class->interface_offsets_packed [i] = interface_offsets_full [i];
3421 /*if (num_array_interfaces)
3422 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]);*/
3424 #ifdef COMPRESSED_INTERFACE_BITMAP
3425 i = mono_compress_bitmap (NULL, bitmap, bsize);
3426 class->interface_bitmap = mono_class_alloc0 (class, i);
3427 mono_compress_bitmap (class->interface_bitmap, bitmap, bsize);
3428 g_free (bitmap);
3429 #else
3430 class->interface_bitmap = bitmap;
3431 #endif
3434 end:
3435 g_free (interfaces_full);
3436 g_free (interface_offsets_full);
3437 g_free (array_interfaces);
3438 for (i = 0; i < class->idepth; i++) {
3439 ifaces = ifaces_array [i];
3440 if (ifaces)
3441 g_ptr_array_free (ifaces, TRUE);
3443 g_free (ifaces_array);
3445 //printf ("JUST DONE: ");
3446 //print_implemented_interfaces (class);
3448 return cur_slot;
3452 * Setup interface offsets for interfaces.
3453 * Initializes:
3454 * - class->max_interface_id
3455 * - class->interface_offsets_count
3456 * - class->interfaces_packed
3457 * - class->interface_offsets_packed
3458 * - class->interface_bitmap
3460 * This function can fail @class.
3462 void
3463 mono_class_setup_interface_offsets (MonoClass *class)
3465 mono_loader_lock ();
3467 setup_interface_offsets (class, 0, FALSE);
3469 mono_loader_unlock ();
3472 /*Checks if @klass has @parent as one of it's parents type gtd
3474 * For example:
3475 * Foo<T>
3476 * Bar<T> : Foo<Bar<Bar<T>>>
3479 static gboolean
3480 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
3482 klass = mono_class_get_generic_type_definition (klass);
3483 parent = mono_class_get_generic_type_definition (parent);
3484 mono_class_setup_supertypes (klass);
3485 mono_class_setup_supertypes (parent);
3487 return klass->idepth >= parent->idepth &&
3488 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
3491 gboolean
3492 mono_class_check_vtable_constraints (MonoClass *class, GList *in_setup)
3494 MonoGenericInst *ginst;
3495 int i;
3496 if (!class->generic_class) {
3497 mono_class_setup_vtable_full (class, in_setup);
3498 return class->exception_type == 0;
3501 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (class), in_setup);
3502 if (class->generic_class->container_class->exception_type) {
3503 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to load generic definition vtable"));
3504 return FALSE;
3507 ginst = class->generic_class->context.class_inst;
3508 for (i = 0; i < ginst->type_argc; ++i) {
3509 MonoClass *arg;
3510 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
3511 continue;
3512 arg = mono_class_from_mono_type (ginst->type_argv [i]);
3513 /*Those 2 will be checked by mono_class_setup_vtable itself*/
3514 if (mono_class_has_gtd_parent (class, arg) || mono_class_has_gtd_parent (arg, class))
3515 continue;
3516 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
3517 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Failed to load generic parameter %d", i));
3518 return FALSE;
3521 return TRUE;
3525 * mono_class_setup_vtable:
3527 * Creates the generic vtable of CLASS.
3528 * Initializes the following fields in MonoClass:
3529 * - vtable
3530 * - vtable_size
3531 * Plus all the fields initialized by setup_interface_offsets ().
3532 * If there is an error during vtable construction, class->exception_type is set.
3534 * LOCKING: Acquires the loader lock.
3536 void
3537 mono_class_setup_vtable (MonoClass *class)
3539 mono_class_setup_vtable_full (class, NULL);
3542 static void
3543 mono_class_setup_vtable_full (MonoClass *class, GList *in_setup)
3545 MonoMethod **overrides;
3546 MonoGenericContext *context;
3547 guint32 type_token;
3548 int onum = 0;
3549 gboolean ok = TRUE;
3551 if (class->vtable)
3552 return;
3554 if (mono_debug_using_mono_debugger ())
3555 /* The debugger currently depends on this */
3556 mono_class_setup_methods (class);
3558 if (MONO_CLASS_IS_INTERFACE (class)) {
3559 /* This sets method->slot for all methods if this is an interface */
3560 mono_class_setup_methods (class);
3561 return;
3564 if (class->exception_type)
3565 return;
3567 if (g_list_find (in_setup, class))
3568 return;
3570 mono_loader_lock ();
3572 if (class->vtable) {
3573 mono_loader_unlock ();
3574 return;
3577 mono_stats.generic_vtable_count ++;
3578 in_setup = g_list_prepend (in_setup, class);
3580 if (class->generic_class) {
3581 if (!mono_class_check_vtable_constraints (class, in_setup)) {
3582 mono_loader_unlock ();
3583 g_list_remove (in_setup, class);
3584 return;
3587 context = mono_class_get_context (class);
3588 type_token = class->generic_class->container_class->type_token;
3589 } else {
3590 context = (MonoGenericContext *) class->generic_container;
3591 type_token = class->type_token;
3594 if (class->image->dynamic) {
3595 /* Generic instances can have zero method overrides without causing any harm.
3596 * This is true since we don't do layout all over again for them, we simply inflate
3597 * the layout of the parent.
3599 mono_reflection_get_dynamic_overrides (class, &overrides, &onum);
3600 } else {
3601 /* The following call fails if there are missing methods in the type */
3602 /* FIXME it's probably a good idea to avoid this for generic instances. */
3603 ok = mono_class_get_overrides_full (class->image, type_token, &overrides, &onum, context);
3606 if (ok)
3607 mono_class_setup_vtable_general (class, overrides, onum, in_setup);
3608 else
3609 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not load list of method overrides"));
3611 g_free (overrides);
3613 mono_loader_unlock ();
3614 g_list_remove (in_setup, class);
3616 return;
3619 #define DEBUG_INTERFACE_VTABLE_CODE 0
3620 #define TRACE_INTERFACE_VTABLE_CODE 0
3621 #define VERIFY_INTERFACE_VTABLE_CODE 0
3622 #define VTABLE_SELECTOR (1)
3624 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3625 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
3626 if (!(VTABLE_SELECTOR)) break; \
3627 stmt;\
3628 } while (0)
3629 #else
3630 #define DEBUG_INTERFACE_VTABLE(stmt)
3631 #endif
3633 #if TRACE_INTERFACE_VTABLE_CODE
3634 #define TRACE_INTERFACE_VTABLE(stmt) do {\
3635 if (!(VTABLE_SELECTOR)) break; \
3636 stmt;\
3637 } while (0)
3638 #else
3639 #define TRACE_INTERFACE_VTABLE(stmt)
3640 #endif
3642 #if VERIFY_INTERFACE_VTABLE_CODE
3643 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
3644 if (!(VTABLE_SELECTOR)) break; \
3645 stmt;\
3646 } while (0)
3647 #else
3648 #define VERIFY_INTERFACE_VTABLE(stmt)
3649 #endif
3652 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3653 static char*
3654 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
3656 int i;
3657 char *result;
3658 GString *res = g_string_new ("");
3660 g_string_append_c (res, '(');
3661 for (i = 0; i < sig->param_count; ++i) {
3662 if (i > 0)
3663 g_string_append_c (res, ',');
3664 mono_type_get_desc (res, sig->params [i], include_namespace);
3666 g_string_append (res, ")=>");
3667 if (sig->ret != NULL) {
3668 mono_type_get_desc (res, sig->ret, include_namespace);
3669 } else {
3670 g_string_append (res, "NULL");
3672 result = res->str;
3673 g_string_free (res, FALSE);
3674 return result;
3676 static void
3677 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
3678 char *im_sig = mono_signature_get_full_desc (mono_method_signature (im), TRUE);
3679 char *cm_sig = mono_signature_get_full_desc (mono_method_signature (cm), TRUE);
3680 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
3681 g_free (im_sig);
3682 g_free (cm_sig);
3686 #endif
3687 static gboolean
3688 is_wcf_hack_disabled (void)
3690 static gboolean disabled;
3691 static gboolean inited = FALSE;
3692 if (!inited) {
3693 disabled = g_getenv ("MONO_DISABLE_WCF_HACK") != NULL;
3694 inited = TRUE;
3696 return disabled;
3699 static gboolean
3700 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) {
3701 MonoMethodSignature *cmsig, *imsig;
3702 if (strcmp (im->name, cm->name) == 0) {
3703 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
3704 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
3705 return FALSE;
3707 if (! slot_is_empty) {
3708 if (require_newslot) {
3709 if (! interface_is_explicitly_implemented_by_class) {
3710 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
3711 return FALSE;
3713 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
3714 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
3715 return FALSE;
3717 } else {
3718 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
3721 cmsig = mono_method_signature (cm);
3722 imsig = mono_method_signature (im);
3723 if (!cmsig || !imsig) {
3724 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
3725 return FALSE;
3728 if (! mono_metadata_signature_equal (cmsig, imsig)) {
3729 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
3730 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
3731 TRACE_INTERFACE_VTABLE (printf ("]"));
3732 return FALSE;
3734 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
3735 /* CAS - SecurityAction.InheritanceDemand on interface */
3736 if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
3737 mono_secman_inheritancedemand_method (cm, im);
3740 if (mono_security_core_clr_enabled ())
3741 mono_security_core_clr_check_override (class, cm, im);
3743 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
3744 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
3745 char *body_name = mono_method_full_name (cm, TRUE);
3746 char *decl_name = mono_method_full_name (im, TRUE);
3747 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));
3748 g_free (body_name);
3749 g_free (decl_name);
3750 return FALSE;
3753 return TRUE;
3754 } else {
3755 MonoClass *ic = im->klass;
3756 const char *ic_name_space = ic->name_space;
3757 const char *ic_name = ic->name;
3758 char *subname;
3760 if (! require_newslot) {
3761 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
3762 return FALSE;
3764 if (cm->klass->rank == 0) {
3765 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
3766 return FALSE;
3768 cmsig = mono_method_signature (cm);
3769 imsig = mono_method_signature (im);
3770 if (!cmsig || !imsig) {
3771 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
3772 return FALSE;
3775 if (! mono_metadata_signature_equal (cmsig, imsig)) {
3776 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
3777 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
3778 TRACE_INTERFACE_VTABLE (printf ("]"));
3779 return FALSE;
3781 if (mono_class_get_image (ic) != mono_defaults.corlib) {
3782 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
3783 return FALSE;
3785 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
3786 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
3787 return FALSE;
3789 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))) {
3790 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
3791 return FALSE;
3794 subname = strstr (cm->name, ic_name_space);
3795 if (subname != cm->name) {
3796 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
3797 return FALSE;
3799 subname += strlen (ic_name_space);
3800 if (subname [0] != '.') {
3801 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
3802 return FALSE;
3804 subname ++;
3805 if (strstr (subname, ic_name) != subname) {
3806 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
3807 return FALSE;
3809 subname += strlen (ic_name);
3810 if (subname [0] != '.') {
3811 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
3812 return FALSE;
3814 subname ++;
3815 if (strcmp (subname, im->name) != 0) {
3816 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
3817 return FALSE;
3820 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
3821 /* CAS - SecurityAction.InheritanceDemand on interface */
3822 if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
3823 mono_secman_inheritancedemand_method (cm, im);
3826 if (mono_security_core_clr_enabled ())
3827 mono_security_core_clr_check_override (class, cm, im);
3829 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
3830 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
3831 char *body_name = mono_method_full_name (cm, TRUE);
3832 char *decl_name = mono_method_full_name (im, TRUE);
3833 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));
3834 g_free (body_name);
3835 g_free (decl_name);
3836 return FALSE;
3839 return TRUE;
3843 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3844 static void
3845 foreach_override (gpointer key, gpointer value, gpointer user_data) {
3846 MonoMethod *method = key;
3847 MonoMethod *override = value;
3848 MonoClass *method_class = mono_method_get_class (method);
3849 MonoClass *override_class = mono_method_get_class (override);
3851 printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
3852 mono_class_get_namespace (method_class), mono_class_get_name (method_class), mono_method_get_name (method),
3853 mono_class_get_namespace (override_class), mono_class_get_name (override_class), mono_method_get_name (override));
3855 static void
3856 print_overrides (GHashTable *override_map, const char *message) {
3857 if (override_map) {
3858 printf ("Override map \"%s\" START:\n", message);
3859 g_hash_table_foreach (override_map, foreach_override, NULL);
3860 printf ("Override map \"%s\" END.\n", message);
3861 } else {
3862 printf ("Override map \"%s\" EMPTY.\n", message);
3865 static void
3866 print_vtable_full (MonoClass *class, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
3867 char *full_name = mono_type_full_name (&class->byval_arg);
3868 int i;
3869 int parent_size;
3871 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
3873 if (print_interfaces) {
3874 print_implemented_interfaces (class);
3875 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
3878 if (class->parent) {
3879 parent_size = class->parent->vtable_size;
3880 } else {
3881 parent_size = 0;
3883 for (i = 0; i < size; ++i) {
3884 MonoMethod *cm = vtable [i];
3885 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
3886 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
3888 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
3889 g_free (cm_name);
3892 g_free (full_name);
3894 #endif
3896 #if VERIFY_INTERFACE_VTABLE_CODE
3897 static int
3898 mono_method_try_get_vtable_index (MonoMethod *method)
3900 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
3901 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
3902 if (imethod->declaring->is_generic)
3903 return imethod->declaring->slot;
3905 return method->slot;
3908 static void
3909 mono_class_verify_vtable (MonoClass *class)
3911 int i;
3912 char *full_name = mono_type_full_name (&class->byval_arg);
3914 printf ("*** Verifying VTable of class '%s' \n", full_name);
3915 g_free (full_name);
3916 full_name = NULL;
3918 if (!class->methods)
3919 return;
3921 for (i = 0; i < class->method.count; ++i) {
3922 MonoMethod *cm = class->methods [i];
3923 int slot;
3925 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
3926 continue;
3928 g_free (full_name);
3929 full_name = mono_method_full_name (cm, TRUE);
3931 slot = mono_method_try_get_vtable_index (cm);
3932 if (slot >= 0) {
3933 if (slot >= class->vtable_size) {
3934 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, class->vtable_size);
3935 continue;
3938 if (slot >= 0 && class->vtable [slot] != cm && (class->vtable [slot])) {
3939 char *other_name = class->vtable [slot] ? mono_method_full_name (class->vtable [slot], TRUE) : g_strdup ("[null value]");
3940 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
3941 g_free (other_name);
3943 } else
3944 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
3946 g_free (full_name);
3948 #endif
3950 static void
3951 print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) {
3952 int index;
3953 char *method_signature;
3954 char *type_name;
3956 for (index = 0; index < onum; ++index) {
3957 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name,
3958 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
3960 method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
3961 type_name = mono_type_full_name (&class->byval_arg);
3962 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s\n",
3963 mono_type_get_name (&ic->byval_arg), im->name, method_signature, type_name);
3964 g_free (method_signature);
3965 g_free (type_name);
3966 mono_class_setup_methods (class);
3967 if (class->exception_type) {
3968 char *name = mono_type_get_full_name (class);
3969 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods\n", name);
3970 g_free (name);
3971 return;
3973 for (index = 0; index < class->method.count; ++index) {
3974 MonoMethod *cm = class->methods [index];
3975 method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
3977 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)\n", cm->name, method_signature);
3978 g_free (method_signature);
3982 static MonoMethod*
3983 mono_method_get_method_definition (MonoMethod *method)
3985 while (method->is_inflated)
3986 method = ((MonoMethodInflated*)method)->declaring;
3987 return method;
3990 static gboolean
3991 verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum)
3993 int i;
3995 for (i = 0; i < onum; ++i) {
3996 MonoMethod *decl = overrides [i * 2];
3997 MonoMethod *body = overrides [i * 2 + 1];
3999 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (class)) {
4000 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method belongs to a different class than the declared one"));
4001 return FALSE;
4004 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
4005 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4006 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must not be static to override a base type"));
4007 else
4008 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must be virtual to override a base type"));
4009 return FALSE;
4012 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
4013 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4014 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type"));
4015 else
4016 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type"));
4017 return FALSE;
4020 if (!mono_class_is_assignable_from_slow (decl->klass, class)) {
4021 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that extended or implemented by this type"));
4022 return FALSE;
4025 body = mono_method_get_method_definition (body);
4026 decl = mono_method_get_method_definition (decl);
4028 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
4029 char *body_name = mono_method_full_name (body, TRUE);
4030 char *decl_name = mono_method_full_name (decl, TRUE);
4031 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));
4032 g_free (body_name);
4033 g_free (decl_name);
4034 return FALSE;
4037 return TRUE;
4040 static gboolean
4041 mono_class_need_stelemref_method (MonoClass *class)
4043 return class->rank == 1 && MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg);
4047 * LOCKING: this is supposed to be called with the loader lock held.
4049 void
4050 mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int onum, GList *in_setup)
4052 MonoError error;
4053 MonoClass *k, *ic;
4054 MonoMethod **vtable;
4055 int i, max_vtsize = 0, max_iid, cur_slot = 0;
4056 GPtrArray *ifaces = NULL;
4057 GHashTable *override_map = NULL;
4058 gboolean security_enabled = mono_security_enabled ();
4059 MonoMethod *cm;
4060 gpointer class_iter;
4061 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
4062 int first_non_interface_slot;
4063 #endif
4064 GSList *virt_methods = NULL, *l;
4065 int stelemref_slot = 0;
4067 if (class->vtable)
4068 return;
4070 if (overrides && !verify_class_overrides (class, overrides, onum))
4071 return;
4073 ifaces = mono_class_get_implemented_interfaces (class, &error);
4074 if (!mono_error_ok (&error)) {
4075 char *name = mono_type_get_full_name (class);
4076 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)));
4077 g_free (name);
4078 mono_error_cleanup (&error);
4079 return;
4080 } else if (ifaces) {
4081 for (i = 0; i < ifaces->len; i++) {
4082 MonoClass *ic = g_ptr_array_index (ifaces, i);
4083 max_vtsize += ic->method.count;
4085 g_ptr_array_free (ifaces, TRUE);
4086 ifaces = NULL;
4089 if (class->parent) {
4090 mono_class_init (class->parent);
4091 mono_class_setup_vtable_full (class->parent, in_setup);
4093 if (class->parent->exception_type) {
4094 char *name = mono_type_get_full_name (class->parent);
4095 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Parent %s failed to load", name));
4096 g_free (name);
4097 return;
4100 max_vtsize += class->parent->vtable_size;
4101 cur_slot = class->parent->vtable_size;
4104 max_vtsize += class->method.count;
4106 /*Array have a slot for stelemref*/
4107 if (mono_class_need_stelemref_method (class)) {
4108 stelemref_slot = cur_slot;
4109 ++max_vtsize;
4110 ++cur_slot;
4113 vtable = alloca (sizeof (gpointer) * max_vtsize);
4114 memset (vtable, 0, sizeof (gpointer) * max_vtsize);
4116 /* printf ("METAINIT %s.%s\n", class->name_space, class->name); */
4118 cur_slot = setup_interface_offsets (class, cur_slot, TRUE);
4119 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
4120 return;
4122 max_iid = class->max_interface_id;
4123 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
4125 /* Optimized version for generic instances */
4126 if (class->generic_class) {
4127 MonoError error;
4128 MonoClass *gklass = class->generic_class->container_class;
4129 MonoMethod **tmp;
4131 mono_class_setup_vtable_full (gklass, in_setup);
4132 if (gklass->exception_type != MONO_EXCEPTION_NONE) {
4133 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
4134 return;
4137 tmp = mono_class_alloc0 (class, sizeof (gpointer) * gklass->vtable_size);
4138 class->vtable_size = gklass->vtable_size;
4139 for (i = 0; i < gklass->vtable_size; ++i)
4140 if (gklass->vtable [i]) {
4141 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], class, mono_class_get_context (class), &error);
4142 if (!mono_error_ok (&error)) {
4143 char *err_msg = g_strdup_printf ("Could not inflate method due to %s", mono_error_get_message (&error));
4144 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
4145 g_free (err_msg);
4146 mono_error_cleanup (&error);
4147 return;
4149 tmp [i] = inflated;
4150 tmp [i]->slot = gklass->vtable [i]->slot;
4152 mono_memory_barrier ();
4153 class->vtable = tmp;
4155 /* Have to set method->slot for abstract virtual methods */
4156 if (class->methods && gklass->methods) {
4157 for (i = 0; i < class->method.count; ++i)
4158 if (class->methods [i]->slot == -1)
4159 class->methods [i]->slot = gklass->methods [i]->slot;
4162 return;
4165 if (class->parent && class->parent->vtable_size) {
4166 MonoClass *parent = class->parent;
4167 int i;
4169 memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
4171 // Also inherit parent interface vtables, just as a starting point.
4172 // This is needed otherwise bug-77127.exe fails when the property methods
4173 // have different names in the iterface and the class, because for child
4174 // classes the ".override" information is not used anymore.
4175 for (i = 0; i < parent->interface_offsets_count; i++) {
4176 MonoClass *parent_interface = parent->interfaces_packed [i];
4177 int interface_offset = mono_class_interface_offset (class, parent_interface);
4178 /*FIXME this is now dead code as this condition will never hold true.
4179 Since interface offsets are inherited then the offset of an interface implemented
4180 by a parent will never be the out of it's vtable boundary.
4182 if (interface_offset >= parent->vtable_size) {
4183 int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
4184 int j;
4186 mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
4187 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
4188 for (j = 0; j < parent_interface->method.count && !class->exception_type; j++) {
4189 vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
4190 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
4191 parent_interface_offset + j, parent_interface_offset, j,
4192 interface_offset + j, interface_offset, j));
4199 /*Array have a slot for stelemref*/
4200 if (mono_class_need_stelemref_method (class)) {
4201 MonoMethod *method = mono_marshal_get_virtual_stelemref (class);
4202 if (!method->slot)
4203 method->slot = stelemref_slot;
4204 else
4205 g_assert (method->slot == stelemref_slot);
4207 vtable [stelemref_slot] = method;
4210 TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
4211 /* override interface methods */
4212 for (i = 0; i < onum; i++) {
4213 MonoMethod *decl = overrides [i*2];
4214 if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
4215 int dslot;
4216 dslot = mono_method_get_vtable_slot (decl);
4217 if (dslot == -1) {
4218 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
4219 return;
4222 dslot += mono_class_interface_offset (class, decl->klass);
4223 vtable [dslot] = overrides [i*2 + 1];
4224 vtable [dslot]->slot = dslot;
4225 if (!override_map)
4226 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4228 g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
4230 if (mono_security_core_clr_enabled ())
4231 mono_security_core_clr_check_override (class, vtable [dslot], decl);
4234 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
4235 TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
4238 * Create a list of virtual methods to avoid calling
4239 * mono_class_get_virtual_methods () which is slow because of the metadata
4240 * optimization.
4243 gpointer iter = NULL;
4244 MonoMethod *cm;
4246 virt_methods = NULL;
4247 while ((cm = mono_class_get_virtual_methods (class, &iter))) {
4248 virt_methods = g_slist_prepend (virt_methods, cm);
4250 if (class->exception_type)
4251 goto fail;
4254 // Loop on all implemented interfaces...
4255 for (i = 0; i < class->interface_offsets_count; i++) {
4256 MonoClass *parent = class->parent;
4257 int ic_offset;
4258 gboolean interface_is_explicitly_implemented_by_class;
4259 int im_index;
4261 ic = class->interfaces_packed [i];
4262 ic_offset = mono_class_interface_offset (class, ic);
4264 mono_class_setup_methods (ic);
4265 if (ic->exception_type)
4266 goto fail;
4268 // Check if this interface is explicitly implemented (instead of just inherited)
4269 if (parent != NULL) {
4270 int implemented_interfaces_index;
4271 interface_is_explicitly_implemented_by_class = FALSE;
4272 for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) {
4273 if (ic == class->interfaces [implemented_interfaces_index]) {
4274 interface_is_explicitly_implemented_by_class = TRUE;
4275 break;
4278 } else {
4279 interface_is_explicitly_implemented_by_class = TRUE;
4282 // Loop on all interface methods...
4283 for (im_index = 0; im_index < ic->method.count; im_index++) {
4284 MonoMethod *im = ic->methods [im_index];
4285 int im_slot = ic_offset + im->slot;
4286 MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL;
4288 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4289 continue;
4291 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
4293 // If there is an explicit implementation, just use it right away,
4294 // otherwise look for a matching method
4295 if (override_im == NULL) {
4296 int cm_index;
4297 gpointer iter;
4298 MonoMethod *cm;
4300 // First look for a suitable method among the class methods
4301 iter = NULL;
4302 for (l = virt_methods; l; l = l->next) {
4303 cm = l->data;
4304 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)));
4305 if (check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) {
4306 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
4307 vtable [im_slot] = cm;
4308 /* Why do we need this? */
4309 if (cm->slot < 0) {
4310 cm->slot = im_slot;
4313 TRACE_INTERFACE_VTABLE (printf ("\n"));
4314 if (class->exception_type) /*Might be set by check_interface_method_override*/
4315 goto fail;
4318 // If the slot is still empty, look in all the inherited virtual methods...
4319 if ((vtable [im_slot] == NULL) && class->parent != NULL) {
4320 MonoClass *parent = class->parent;
4321 // Reverse order, so that last added methods are preferred
4322 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
4323 MonoMethod *cm = parent->vtable [cm_index];
4325 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));
4326 if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) {
4327 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
4328 vtable [im_slot] = cm;
4329 /* Why do we need this? */
4330 if (cm->slot < 0) {
4331 cm->slot = im_slot;
4333 break;
4335 if (class->exception_type) /*Might be set by check_interface_method_override*/
4336 goto fail;
4337 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
4340 } else {
4341 g_assert (vtable [im_slot] == override_im);
4346 // If the class is not abstract, check that all its interface slots are full.
4347 // The check is done here and not directly at the end of the loop above because
4348 // it can happen (for injected generic array interfaces) that the same slot is
4349 // processed multiple times (those interfaces have overlapping slots), and it
4350 // will not always be the first pass the one that fills the slot.
4351 if (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
4352 for (i = 0; i < class->interface_offsets_count; i++) {
4353 int ic_offset;
4354 int im_index;
4356 ic = class->interfaces_packed [i];
4357 ic_offset = mono_class_interface_offset (class, ic);
4359 for (im_index = 0; im_index < ic->method.count; im_index++) {
4360 MonoMethod *im = ic->methods [im_index];
4361 int im_slot = ic_offset + im->slot;
4363 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4364 continue;
4366 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
4367 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
4368 if (vtable [im_slot] == NULL) {
4369 print_unimplemented_interface_method_info (class, ic, im, im_slot, overrides, onum);
4370 goto fail;
4376 TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
4377 class_iter = NULL;
4378 for (l = virt_methods; l; l = l->next) {
4379 cm = l->data;
4381 * If the method is REUSE_SLOT, we must check in the
4382 * base class for a method to override.
4384 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
4385 int slot = -1;
4386 for (k = class->parent; k ; k = k->parent) {
4387 gpointer k_iter;
4388 MonoMethod *m1;
4390 k_iter = NULL;
4391 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
4392 MonoMethodSignature *cmsig, *m1sig;
4394 cmsig = mono_method_signature (cm);
4395 m1sig = mono_method_signature (m1);
4397 if (!cmsig || !m1sig) {
4398 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
4399 return;
4402 if (!strcmp(cm->name, m1->name) &&
4403 mono_metadata_signature_equal (cmsig, m1sig)) {
4405 /* CAS - SecurityAction.InheritanceDemand */
4406 if (security_enabled && (m1->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
4407 mono_secman_inheritancedemand_method (cm, m1);
4410 if (mono_security_core_clr_enabled ())
4411 mono_security_core_clr_check_override (class, cm, m1);
4413 slot = mono_method_get_vtable_slot (m1);
4414 if (slot == -1)
4415 goto fail;
4417 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
4418 char *body_name = mono_method_full_name (cm, TRUE);
4419 char *decl_name = mono_method_full_name (m1, TRUE);
4420 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));
4421 g_free (body_name);
4422 g_free (decl_name);
4423 goto fail;
4426 g_assert (cm->slot < max_vtsize);
4427 if (!override_map)
4428 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4429 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
4430 mono_method_full_name (m1, 1), m1,
4431 mono_method_full_name (cm, 1), cm));
4432 g_hash_table_insert (override_map, m1, cm);
4433 break;
4436 if (k->exception_type)
4437 goto fail;
4439 if (slot >= 0)
4440 break;
4442 if (slot >= 0)
4443 cm->slot = slot;
4446 /*Non final newslot methods must be given a non-interface vtable slot*/
4447 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
4448 cm->slot = -1;
4450 if (cm->slot < 0)
4451 cm->slot = cur_slot++;
4453 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
4454 vtable [cm->slot] = cm;
4457 /* override non interface methods */
4458 for (i = 0; i < onum; i++) {
4459 MonoMethod *decl = overrides [i*2];
4460 if (!MONO_CLASS_IS_INTERFACE (decl->klass)) {
4461 g_assert (decl->slot != -1);
4462 vtable [decl->slot] = overrides [i*2 + 1];
4463 overrides [i * 2 + 1]->slot = decl->slot;
4464 if (!override_map)
4465 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4466 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
4467 mono_method_full_name (decl, 1), decl,
4468 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
4469 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
4471 if (mono_security_core_clr_enabled ())
4472 mono_security_core_clr_check_override (class, vtable [decl->slot], decl);
4477 * If a method occupies more than one place in the vtable, and it is
4478 * overriden, then change the other occurances too.
4480 if (override_map) {
4481 MonoMethod *cm;
4483 for (i = 0; i < max_vtsize; ++i)
4484 if (vtable [i]) {
4485 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
4487 cm = g_hash_table_lookup (override_map, vtable [i]);
4488 if (cm)
4489 vtable [i] = cm;
4492 g_hash_table_destroy (override_map);
4493 override_map = NULL;
4496 g_slist_free (virt_methods);
4497 virt_methods = NULL;
4499 /* Ensure that all vtable slots are filled with concrete instance methods */
4500 if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
4501 for (i = 0; i < cur_slot; ++i) {
4502 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
4503 char *type_name = mono_type_get_full_name (class);
4504 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
4505 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));
4506 g_free (type_name);
4507 g_free (method_name);
4508 return;
4513 if (class->generic_class) {
4514 MonoClass *gklass = class->generic_class->container_class;
4516 mono_class_init (gklass);
4518 class->vtable_size = MAX (gklass->vtable_size, cur_slot);
4519 } else {
4520 /* Check that the vtable_size value computed in mono_class_init () is correct */
4521 if (class->vtable_size)
4522 g_assert (cur_slot == class->vtable_size);
4523 class->vtable_size = cur_slot;
4526 /* Try to share the vtable with our parent. */
4527 if (class->parent && (class->parent->vtable_size == class->vtable_size) && (memcmp (class->parent->vtable, vtable, sizeof (gpointer) * class->vtable_size) == 0)) {
4528 mono_memory_barrier ();
4529 class->vtable = class->parent->vtable;
4530 } else {
4531 MonoMethod **tmp = mono_class_alloc0 (class, sizeof (gpointer) * class->vtable_size);
4532 memcpy (tmp, vtable, sizeof (gpointer) * class->vtable_size);
4533 mono_memory_barrier ();
4534 class->vtable = tmp;
4537 DEBUG_INTERFACE_VTABLE (print_vtable_full (class, class->vtable, class->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
4538 if (mono_print_vtable) {
4539 int icount = 0;
4541 print_implemented_interfaces (class);
4543 for (i = 0; i <= max_iid; i++)
4544 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, i))
4545 icount++;
4547 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&class->byval_arg),
4548 class->vtable_size, icount);
4550 for (i = 0; i < cur_slot; ++i) {
4551 MonoMethod *cm;
4553 cm = vtable [i];
4554 if (cm) {
4555 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
4556 mono_method_full_name (cm, TRUE));
4561 if (icount) {
4562 printf ("Interfaces %s.%s (max_iid = %d)\n", class->name_space,
4563 class->name, max_iid);
4565 for (i = 0; i < class->interface_count; i++) {
4566 ic = class->interfaces [i];
4567 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
4568 mono_class_interface_offset (class, ic),
4569 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4572 for (k = class->parent; k ; k = k->parent) {
4573 for (i = 0; i < k->interface_count; i++) {
4574 ic = k->interfaces [i];
4575 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
4576 mono_class_interface_offset (class, ic),
4577 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4583 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (class));
4584 return;
4586 fail:
4588 char *name = mono_type_get_full_name (class);
4589 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("VTable setup of type %s failed", name));
4590 g_free (name);
4591 if (override_map)
4592 g_hash_table_destroy (override_map);
4593 if (virt_methods)
4594 g_slist_free (virt_methods);
4599 * mono_method_get_vtable_slot:
4601 * Returns method->slot, computing it if neccesary. Return -1 on failure.
4602 * LOCKING: Acquires the loader lock.
4604 * FIXME Use proper MonoError machinery here.
4607 mono_method_get_vtable_slot (MonoMethod *method)
4609 if (method->slot == -1) {
4610 mono_class_setup_vtable (method->klass);
4611 if (method->klass->exception_type)
4612 return -1;
4613 if (method->slot == -1) {
4614 MonoClass *gklass;
4615 int i;
4617 /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
4618 g_assert (method->klass->generic_class);
4619 gklass = method->klass->generic_class->container_class;
4620 mono_class_setup_methods (method->klass);
4621 g_assert (method->klass->methods);
4622 for (i = 0; i < method->klass->method.count; ++i) {
4623 if (method->klass->methods [i] == method)
4624 break;
4626 g_assert (i < method->klass->method.count);
4627 g_assert (gklass->methods);
4628 method->slot = gklass->methods [i]->slot;
4630 g_assert (method->slot != -1);
4632 return method->slot;
4636 * mono_method_get_vtable_index:
4637 * @method: a method
4639 * Returns the index into the runtime vtable to access the method or,
4640 * in the case of a virtual generic method, the virtual generic method
4641 * thunk. Returns -1 on failure.
4643 * FIXME Use proper MonoError machinery here.
4646 mono_method_get_vtable_index (MonoMethod *method)
4648 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
4649 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
4650 if (imethod->declaring->is_generic)
4651 return mono_method_get_vtable_slot (imethod->declaring);
4653 return mono_method_get_vtable_slot (method);
4656 static MonoMethod *default_ghc = NULL;
4657 static MonoMethod *default_finalize = NULL;
4658 static int finalize_slot = -1;
4659 static int ghc_slot = -1;
4661 static void
4662 initialize_object_slots (MonoClass *class)
4664 int i;
4665 if (default_ghc)
4666 return;
4667 if (class == mono_defaults.object_class) {
4668 mono_class_setup_vtable (class);
4669 for (i = 0; i < class->vtable_size; ++i) {
4670 MonoMethod *cm = class->vtable [i];
4672 if (!strcmp (cm->name, "GetHashCode"))
4673 ghc_slot = i;
4674 else if (!strcmp (cm->name, "Finalize"))
4675 finalize_slot = i;
4678 g_assert (ghc_slot > 0);
4679 default_ghc = class->vtable [ghc_slot];
4681 g_assert (finalize_slot > 0);
4682 default_finalize = class->vtable [finalize_slot];
4686 typedef struct {
4687 MonoMethod *array_method;
4688 char *name;
4689 } GenericArrayMethodInfo;
4691 static int generic_array_method_num = 0;
4692 static GenericArrayMethodInfo *generic_array_method_info = NULL;
4694 static int
4695 generic_array_methods (MonoClass *class)
4697 int i, count_generic = 0;
4698 GList *list = NULL, *tmp;
4699 if (generic_array_method_num)
4700 return generic_array_method_num;
4701 mono_class_setup_methods (class->parent); /*This is setting up System.Array*/
4702 g_assert (!class->parent->exception_type); /*So hitting this assert is a huge problem*/
4703 for (i = 0; i < class->parent->method.count; i++) {
4704 MonoMethod *m = class->parent->methods [i];
4705 if (!strncmp (m->name, "InternalArray__", 15)) {
4706 count_generic++;
4707 list = g_list_prepend (list, m);
4710 list = g_list_reverse (list);
4711 generic_array_method_info = mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
4712 i = 0;
4713 for (tmp = list; tmp; tmp = tmp->next) {
4714 const char *mname, *iname;
4715 gchar *name;
4716 MonoMethod *m = tmp->data;
4717 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
4718 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
4720 generic_array_method_info [i].array_method = m;
4721 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
4722 iname = "System.Collections.Generic.ICollection`1.";
4723 mname = m->name + 27;
4724 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
4725 iname = "System.Collections.Generic.IEnumerable`1.";
4726 mname = m->name + 27;
4727 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
4728 iname = "System.Collections.Generic.IReadOnlyList`1.";
4729 mname = m->name + strlen (ireadonlylist_prefix);
4730 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
4731 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
4732 mname = m->name + strlen (ireadonlycollection_prefix);
4733 } else if (!strncmp (m->name, "InternalArray__", 15)) {
4734 iname = "System.Collections.Generic.IList`1.";
4735 mname = m->name + 15;
4736 } else {
4737 g_assert_not_reached ();
4740 name = mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
4741 strcpy (name, iname);
4742 strcpy (name + strlen (iname), mname);
4743 generic_array_method_info [i].name = name;
4744 i++;
4746 /*g_print ("array generic methods: %d\n", count_generic);*/
4748 generic_array_method_num = count_generic;
4749 g_list_free (list);
4750 return generic_array_method_num;
4753 static void
4754 setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos)
4756 MonoGenericContext tmp_context;
4757 int i;
4759 tmp_context.class_inst = NULL;
4760 tmp_context.method_inst = iface->generic_class->context.class_inst;
4761 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
4763 for (i = 0; i < generic_array_method_num; i++) {
4764 MonoMethod *m = generic_array_method_info [i].array_method;
4765 MonoMethod *inflated;
4767 inflated = mono_class_inflate_generic_method (m, &tmp_context);
4768 methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, generic_array_method_info [i].name, inflated);
4772 static char*
4773 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
4775 int null_length = strlen ("(null)");
4776 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
4777 char *s = mono_image_alloc (image, len);
4778 int result;
4780 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
4781 g_assert (result == len - 1);
4783 return s;
4786 static void
4787 set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error)
4789 gpointer exception_data = NULL;
4791 switch (error->exception_type) {
4792 case MONO_EXCEPTION_TYPE_LOAD:
4793 exception_data = concat_two_strings_with_zero (class->image, error->class_name, error->assembly_name);
4794 break;
4796 case MONO_EXCEPTION_MISSING_METHOD:
4797 exception_data = concat_two_strings_with_zero (class->image, error->class_name, error->member_name);
4798 break;
4800 case MONO_EXCEPTION_MISSING_FIELD: {
4801 const char *name_space = error->klass->name_space ? error->klass->name_space : NULL;
4802 const char *class_name;
4804 if (name_space)
4805 class_name = g_strdup_printf ("%s.%s", name_space, error->klass->name);
4806 else
4807 class_name = error->klass->name;
4809 exception_data = concat_two_strings_with_zero (class->image, class_name, error->member_name);
4811 if (name_space)
4812 g_free ((void*)class_name);
4813 break;
4816 case MONO_EXCEPTION_FILE_NOT_FOUND: {
4817 const char *msg;
4819 if (error->ref_only)
4820 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.";
4821 else
4822 msg = "Could not load file or assembly '%s' or one of its dependencies.";
4824 exception_data = concat_two_strings_with_zero (class->image, msg, error->assembly_name);
4825 break;
4828 case MONO_EXCEPTION_BAD_IMAGE:
4829 exception_data = error->msg;
4830 break;
4832 default :
4833 g_assert_not_reached ();
4836 mono_class_set_failure (class, error->exception_type, exception_data);
4840 * mono_class_init:
4841 * @class: the class to initialize
4843 * Compute the instance_size, class_size and other infos that cannot be
4844 * computed at mono_class_get() time. Also compute vtable_size if possible.
4845 * Returns TRUE on success or FALSE if there was a problem in loading
4846 * the type (incorrect assemblies, missing assemblies, methods, etc).
4848 * LOCKING: Acquires the loader lock.
4850 gboolean
4851 mono_class_init (MonoClass *class)
4853 int i;
4854 MonoCachedClassInfo cached_info;
4855 gboolean has_cached_info;
4857 g_assert (class);
4859 /* Double-checking locking pattern */
4860 if (class->inited || class->exception_type)
4861 return class->exception_type == MONO_EXCEPTION_NONE;
4863 /*g_print ("Init class %s\n", mono_type_get_full_name (class));*/
4865 /* We do everything inside the lock to prevent races */
4866 mono_loader_lock ();
4868 if (class->inited || class->exception_type) {
4869 mono_loader_unlock ();
4870 /* Somebody might have gotten in before us */
4871 return class->exception_type == MONO_EXCEPTION_NONE;
4874 if (class->init_pending) {
4875 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Recursive type definition detected"));
4876 goto leave;
4879 class->init_pending = 1;
4881 if (mono_verifier_is_enabled_for_class (class) && !mono_verifier_verify_class (class)) {
4882 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, concat_two_strings_with_zero (class->image, class->name, class->image->assembly_name));
4883 goto leave;
4887 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
4888 MonoClass *element_class = class->element_class;
4889 if (!element_class->inited)
4890 mono_class_init (element_class);
4891 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
4892 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
4893 goto leave;
4897 /* CAS - SecurityAction.InheritanceDemand */
4898 if (mono_security_enabled () && class->parent && (class->parent->flags & TYPE_ATTRIBUTE_HAS_SECURITY)) {
4899 mono_secman_inheritancedemand_class (class, class->parent);
4902 mono_stats.initialized_class_count++;
4904 if (class->generic_class && !class->generic_class->is_dynamic) {
4905 MonoClass *gklass = class->generic_class->container_class;
4907 mono_stats.generic_class_count++;
4909 class->method = gklass->method;
4910 class->field = gklass->field;
4912 mono_class_init (gklass);
4913 // FIXME: Why is this needed ?
4914 if (!gklass->exception_type)
4915 mono_class_setup_methods (gklass);
4916 if (gklass->exception_type) {
4917 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic Type Defintion failed to init"));
4918 goto leave;
4921 if (MONO_CLASS_IS_INTERFACE (class))
4922 class->interface_id = mono_get_unique_iid (class);
4925 if (class->parent && !class->parent->inited)
4926 mono_class_init (class->parent);
4928 has_cached_info = mono_class_get_cached_class_info (class, &cached_info);
4930 if (class->generic_class || class->image->dynamic || !class->type_token || (has_cached_info && !cached_info.has_nested_classes))
4931 class->nested_classes_inited = TRUE;
4934 * Computes the size used by the fields, and their locations
4936 if (has_cached_info) {
4937 class->instance_size = cached_info.instance_size;
4938 class->sizes.class_size = cached_info.class_size;
4939 class->packing_size = cached_info.packing_size;
4940 class->min_align = cached_info.min_align;
4941 class->blittable = cached_info.blittable;
4942 class->has_references = cached_info.has_references;
4943 class->has_static_refs = cached_info.has_static_refs;
4944 class->no_special_static_fields = cached_info.no_special_static_fields;
4946 else
4947 if (!class->size_inited){
4948 mono_class_setup_fields (class);
4949 if (class->exception_type || mono_loader_get_last_error ())
4950 goto leave;
4953 /* Initialize arrays */
4954 if (class->rank) {
4955 class->method.count = 3 + (class->rank > 1? 2: 1);
4957 if (class->interface_count) {
4958 int count_generic = generic_array_methods (class);
4959 class->method.count += class->interface_count * count_generic;
4963 mono_class_setup_supertypes (class);
4965 if (!default_ghc)
4966 initialize_object_slots (class);
4969 * Initialize the rest of the data without creating a generic vtable if possible.
4970 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
4971 * also avoid computing a generic vtable.
4973 if (has_cached_info) {
4974 /* AOT case */
4975 class->vtable_size = cached_info.vtable_size;
4976 class->has_finalize = cached_info.has_finalize;
4977 class->has_finalize_inited = TRUE;
4978 class->ghcimpl = cached_info.ghcimpl;
4979 class->has_cctor = cached_info.has_cctor;
4980 } else if (class->rank == 1 && class->byval_arg.type == MONO_TYPE_SZARRAY) {
4981 /* SZARRAY can have 2 vtable layouts, with and without the stelemref method.
4982 * The first slot if for array with.
4984 static int szarray_vtable_size[2] = { 0 };
4986 int slot = MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg) ? 0 : 1;
4988 /* SZARRAY case */
4989 if (!szarray_vtable_size [slot]) {
4990 mono_class_setup_vtable (class);
4991 szarray_vtable_size [slot] = class->vtable_size;
4992 } else {
4993 class->vtable_size = szarray_vtable_size[slot];
4995 class->has_finalize_inited = TRUE;
4996 } else if (class->generic_class && !MONO_CLASS_IS_INTERFACE (class)) {
4997 MonoClass *gklass = class->generic_class->container_class;
4999 /* Generic instance case */
5000 class->ghcimpl = gklass->ghcimpl;
5001 class->has_finalize = mono_class_has_finalizer (gklass);
5002 class->has_finalize_inited = TRUE;
5003 class->has_cctor = gklass->has_cctor;
5005 mono_class_setup_vtable (gklass);
5006 if (gklass->exception_type) {
5007 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5008 goto leave;
5011 class->vtable_size = gklass->vtable_size;
5012 } else {
5013 /* General case */
5015 /* ghcimpl is not currently used
5016 class->ghcimpl = 1;
5017 if (class->parent) {
5018 MonoMethod *cmethod = class->vtable [ghc_slot];
5019 if (cmethod->is_inflated)
5020 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5021 if (cmethod == default_ghc) {
5022 class->ghcimpl = 0;
5027 /* C# doesn't allow interfaces to have cctors */
5028 if (!MONO_CLASS_IS_INTERFACE (class) || class->image != mono_defaults.corlib) {
5029 MonoMethod *cmethod = NULL;
5031 if (class->type_token) {
5032 cmethod = find_method_in_metadata (class, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
5033 /* The find_method function ignores the 'flags' argument */
5034 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
5035 class->has_cctor = 1;
5036 } else {
5037 mono_class_setup_methods (class);
5038 if (class->exception_type)
5039 goto leave;
5041 for (i = 0; i < class->method.count; ++i) {
5042 MonoMethod *method = class->methods [i];
5043 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
5044 (strcmp (".cctor", method->name) == 0)) {
5045 class->has_cctor = 1;
5046 break;
5053 if (class->parent) {
5054 int first_iface_slot;
5055 /* This will compute class->parent->vtable_size for some classes */
5056 mono_class_init (class->parent);
5057 if (class->parent->exception_type) {
5058 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5059 goto leave;
5061 if (mono_loader_get_last_error ())
5062 goto leave;
5063 if (!class->parent->vtable_size) {
5064 /* FIXME: Get rid of this somehow */
5065 mono_class_setup_vtable (class->parent);
5066 if (class->parent->exception_type) {
5067 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5068 goto leave;
5070 if (mono_loader_get_last_error ())
5071 goto leave;
5073 first_iface_slot = class->parent->vtable_size;
5074 if (mono_class_need_stelemref_method (class))
5075 ++first_iface_slot;
5076 setup_interface_offsets (class, first_iface_slot, TRUE);
5077 } else {
5078 setup_interface_offsets (class, 0, TRUE);
5081 if (mono_security_core_clr_enabled ())
5082 mono_security_core_clr_check_inheritance (class);
5084 if (mono_loader_get_last_error ()) {
5085 if (class->exception_type == MONO_EXCEPTION_NONE) {
5086 set_failure_from_loader_error (class, mono_loader_get_last_error ());
5088 mono_loader_clear_error ();
5091 if (class->generic_class && !mono_verifier_class_is_valid_generic_instantiation (class))
5092 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Invalid generic instantiation"));
5094 goto leave;
5096 leave:
5097 /* Because of the double-checking locking pattern */
5098 mono_memory_barrier ();
5099 class->inited = 1;
5100 class->init_pending = 0;
5102 mono_loader_unlock ();
5104 if (mono_debugger_class_init_func)
5105 mono_debugger_class_init_func (class);
5107 return class->exception_type == MONO_EXCEPTION_NONE;
5111 * mono_class_has_finalizer:
5113 * Return whenever KLASS has a finalizer, initializing klass->has_finalizer in the
5114 * process.
5116 gboolean
5117 mono_class_has_finalizer (MonoClass *klass)
5119 if (!klass->has_finalize_inited) {
5120 MonoClass *class = klass;
5122 mono_loader_lock ();
5124 /* Interfaces and valuetypes are not supposed to have finalizers */
5125 if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) {
5126 MonoMethod *cmethod = NULL;
5128 if (class->parent && class->parent->has_finalize) {
5129 class->has_finalize = 1;
5130 } else {
5131 if (class->parent) {
5133 * Can't search in metadata for a method named Finalize, because that
5134 * ignores overrides.
5136 mono_class_setup_vtable (class);
5137 if (class->exception_type || mono_loader_get_last_error ())
5138 goto leave;
5139 cmethod = class->vtable [finalize_slot];
5142 if (cmethod) {
5143 g_assert (class->vtable_size > finalize_slot);
5145 class->has_finalize = 0;
5146 if (class->parent) {
5147 if (cmethod->is_inflated)
5148 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5149 if (cmethod != default_finalize) {
5150 class->has_finalize = 1;
5157 mono_memory_barrier ();
5158 klass->has_finalize_inited = TRUE;
5160 mono_loader_unlock ();
5163 return klass->has_finalize;
5165 leave:
5166 mono_loader_unlock ();
5167 return FALSE;
5170 gboolean
5171 mono_is_corlib_image (MonoImage *image)
5173 /* FIXME: allow the dynamic case for our compilers and with full trust */
5174 if (image->dynamic)
5175 return image->assembly && !strcmp (image->assembly->aname.name, "mscorlib");
5176 else
5177 return image == mono_defaults.corlib;
5181 * LOCKING: this assumes the loader lock is held
5183 void
5184 mono_class_setup_mono_type (MonoClass *class)
5186 const char *name = class->name;
5187 const char *nspace = class->name_space;
5188 gboolean is_corlib = mono_is_corlib_image (class->image);
5190 class->this_arg.byref = 1;
5191 class->this_arg.data.klass = class;
5192 class->this_arg.type = MONO_TYPE_CLASS;
5193 class->byval_arg.data.klass = class;
5194 class->byval_arg.type = MONO_TYPE_CLASS;
5196 if (is_corlib && !strcmp (nspace, "System")) {
5197 if (!strcmp (name, "ValueType")) {
5199 * do not set the valuetype bit for System.ValueType.
5200 * class->valuetype = 1;
5202 class->blittable = TRUE;
5203 } else if (!strcmp (name, "Enum")) {
5205 * do not set the valuetype bit for System.Enum.
5206 * class->valuetype = 1;
5208 class->valuetype = 0;
5209 class->enumtype = 0;
5210 } else if (!strcmp (name, "Object")) {
5211 class->this_arg.type = class->byval_arg.type = MONO_TYPE_OBJECT;
5212 } else if (!strcmp (name, "String")) {
5213 class->this_arg.type = class->byval_arg.type = MONO_TYPE_STRING;
5214 } else if (!strcmp (name, "TypedReference")) {
5215 class->this_arg.type = class->byval_arg.type = MONO_TYPE_TYPEDBYREF;
5219 if (class->valuetype) {
5220 int t = MONO_TYPE_VALUETYPE;
5222 if (is_corlib && !strcmp (nspace, "System")) {
5223 switch (*name) {
5224 case 'B':
5225 if (!strcmp (name, "Boolean")) {
5226 t = MONO_TYPE_BOOLEAN;
5227 } else if (!strcmp(name, "Byte")) {
5228 t = MONO_TYPE_U1;
5229 class->blittable = TRUE;
5231 break;
5232 case 'C':
5233 if (!strcmp (name, "Char")) {
5234 t = MONO_TYPE_CHAR;
5236 break;
5237 case 'D':
5238 if (!strcmp (name, "Double")) {
5239 t = MONO_TYPE_R8;
5240 class->blittable = TRUE;
5242 break;
5243 case 'I':
5244 if (!strcmp (name, "Int32")) {
5245 t = MONO_TYPE_I4;
5246 class->blittable = TRUE;
5247 } else if (!strcmp(name, "Int16")) {
5248 t = MONO_TYPE_I2;
5249 class->blittable = TRUE;
5250 } else if (!strcmp(name, "Int64")) {
5251 t = MONO_TYPE_I8;
5252 class->blittable = TRUE;
5253 } else if (!strcmp(name, "IntPtr")) {
5254 t = MONO_TYPE_I;
5255 class->blittable = TRUE;
5257 break;
5258 case 'S':
5259 if (!strcmp (name, "Single")) {
5260 t = MONO_TYPE_R4;
5261 class->blittable = TRUE;
5262 } else if (!strcmp(name, "SByte")) {
5263 t = MONO_TYPE_I1;
5264 class->blittable = TRUE;
5266 break;
5267 case 'U':
5268 if (!strcmp (name, "UInt32")) {
5269 t = MONO_TYPE_U4;
5270 class->blittable = TRUE;
5271 } else if (!strcmp(name, "UInt16")) {
5272 t = MONO_TYPE_U2;
5273 class->blittable = TRUE;
5274 } else if (!strcmp(name, "UInt64")) {
5275 t = MONO_TYPE_U8;
5276 class->blittable = TRUE;
5277 } else if (!strcmp(name, "UIntPtr")) {
5278 t = MONO_TYPE_U;
5279 class->blittable = TRUE;
5281 break;
5282 case 'T':
5283 if (!strcmp (name, "TypedReference")) {
5284 t = MONO_TYPE_TYPEDBYREF;
5285 class->blittable = TRUE;
5287 break;
5288 case 'V':
5289 if (!strcmp (name, "Void")) {
5290 t = MONO_TYPE_VOID;
5292 break;
5293 default:
5294 break;
5297 class->this_arg.type = class->byval_arg.type = t;
5300 if (MONO_CLASS_IS_INTERFACE (class))
5301 class->interface_id = mono_get_unique_iid (class);
5305 #ifndef DISABLE_COM
5307 * COM initialization (using mono_init_com_types) is delayed until needed.
5308 * However when a [ComImport] attribute is present on a type it will trigger
5309 * the initialization. This is not a problem unless the BCL being executed
5310 * lacks the types that COM depends on (e.g. Variant on Silverlight).
5312 static void
5313 init_com_from_comimport (MonoClass *class)
5315 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
5316 if (mono_security_core_clr_enabled ()) {
5317 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
5318 if (!mono_security_core_clr_determine_platform_image (class->image)) {
5319 /* but it can not be made available for application (i.e. user code) since all COM calls
5320 * are considered native calls. In this case we fail with a TypeLoadException (just like
5321 * Silverlight 2 does */
5322 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5323 return;
5327 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
5328 mono_init_com_types ();
5330 #endif /*DISABLE_COM*/
5333 * LOCKING: this assumes the loader lock is held
5335 void
5336 mono_class_setup_parent (MonoClass *class, MonoClass *parent)
5338 gboolean system_namespace;
5339 gboolean is_corlib = mono_is_corlib_image (class->image);
5341 system_namespace = !strcmp (class->name_space, "System") && is_corlib;
5343 /* if root of the hierarchy */
5344 if (system_namespace && !strcmp (class->name, "Object")) {
5345 class->parent = NULL;
5346 class->instance_size = sizeof (MonoObject);
5347 return;
5349 if (!strcmp (class->name, "<Module>")) {
5350 class->parent = NULL;
5351 class->instance_size = 0;
5352 return;
5355 if (!MONO_CLASS_IS_INTERFACE (class)) {
5356 /* Imported COM Objects always derive from __ComObject. */
5357 #ifndef DISABLE_COM
5358 if (MONO_CLASS_IS_IMPORT (class)) {
5359 init_com_from_comimport (class);
5360 if (parent == mono_defaults.object_class)
5361 parent = mono_defaults.com_object_class;
5363 #endif
5364 if (!parent) {
5365 /* set the parent to something useful and safe, but mark the type as broken */
5366 parent = mono_defaults.object_class;
5367 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5370 class->parent = parent;
5372 if (parent->generic_class && !parent->name) {
5374 * If the parent is a generic instance, we may get
5375 * called before it is fully initialized, especially
5376 * before it has its name.
5378 return;
5381 #ifndef DISABLE_REMOTING
5382 class->marshalbyref = parent->marshalbyref;
5383 class->contextbound = parent->contextbound;
5384 #endif
5386 class->delegate = parent->delegate;
5388 if (MONO_CLASS_IS_IMPORT (class) || mono_class_is_com_object (parent))
5389 mono_class_set_is_com_object (class);
5391 if (system_namespace) {
5392 #ifndef DISABLE_REMOTING
5393 if (*class->name == 'M' && !strcmp (class->name, "MarshalByRefObject"))
5394 class->marshalbyref = 1;
5396 if (*class->name == 'C' && !strcmp (class->name, "ContextBoundObject"))
5397 class->contextbound = 1;
5398 #endif
5399 if (*class->name == 'D' && !strcmp (class->name, "Delegate"))
5400 class->delegate = 1;
5403 if (class->parent->enumtype || (mono_is_corlib_image (class->parent->image) && (strcmp (class->parent->name, "ValueType") == 0) &&
5404 (strcmp (class->parent->name_space, "System") == 0)))
5405 class->valuetype = 1;
5406 if (mono_is_corlib_image (class->parent->image) && ((strcmp (class->parent->name, "Enum") == 0) && (strcmp (class->parent->name_space, "System") == 0))) {
5407 class->valuetype = class->enumtype = 1;
5409 /*class->enumtype = class->parent->enumtype; */
5410 } else {
5411 /* initialize com types if COM interfaces are present */
5412 #ifndef DISABLE_COM
5413 if (MONO_CLASS_IS_IMPORT (class))
5414 init_com_from_comimport (class);
5415 #endif
5416 class->parent = NULL;
5422 * mono_class_setup_supertypes:
5423 * @class: a class
5425 * Build the data structure needed to make fast type checks work.
5426 * This currently sets two fields in @class:
5427 * - idepth: distance between @class and System.Object in the type
5428 * hierarchy + 1
5429 * - supertypes: array of classes: each element has a class in the hierarchy
5430 * starting from @class up to System.Object
5432 * LOCKING: this assumes the loader lock is held
5434 void
5435 mono_class_setup_supertypes (MonoClass *class)
5437 int ms;
5438 MonoClass **supertypes;
5440 if (class->supertypes)
5441 return;
5443 if (class->parent && !class->parent->supertypes)
5444 mono_class_setup_supertypes (class->parent);
5445 if (class->parent)
5446 class->idepth = class->parent->idepth + 1;
5447 else
5448 class->idepth = 1;
5450 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, class->idepth);
5451 supertypes = mono_class_alloc0 (class, sizeof (MonoClass *) * ms);
5453 if (class->parent) {
5454 supertypes [class->idepth - 1] = class;
5455 memcpy (supertypes, class->parent->supertypes, class->parent->idepth * sizeof (gpointer));
5456 } else {
5457 supertypes [0] = class;
5460 mono_atomic_store_release (&class->supertypes, supertypes);
5463 static gboolean
5464 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
5466 MonoClass *gtd = (MonoClass*)user_data;
5467 /* Only try to fix generic instances of @gtd */
5468 if (gclass->generic_class->container_class != gtd)
5469 return FALSE;
5471 /* Check if the generic instance has no parent. */
5472 if (gtd->parent && !gclass->parent)
5473 mono_generic_class_setup_parent (gclass, gtd);
5475 return TRUE;
5479 * mono_class_create_from_typedef:
5480 * @image: image where the token is valid
5481 * @type_token: typedef token
5483 * Create the MonoClass* representing the specified type token.
5484 * @type_token must be a TypeDef token.
5486 * FIXME: don't return NULL on failure, just the the caller figure it out.
5488 static MonoClass *
5489 mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
5491 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
5492 MonoClass *class, *parent = NULL;
5493 guint32 cols [MONO_TYPEDEF_SIZE];
5494 guint32 cols_next [MONO_TYPEDEF_SIZE];
5495 guint tidx = mono_metadata_token_index (type_token);
5496 MonoGenericContext *context = NULL;
5497 const char *name, *nspace;
5498 guint icount = 0;
5499 MonoClass **interfaces;
5500 guint32 field_last, method_last;
5501 guint32 nesting_tokeen;
5503 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows)
5504 return NULL;
5506 mono_loader_lock ();
5508 if ((class = mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
5509 mono_loader_unlock ();
5510 return class;
5513 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
5515 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
5516 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
5518 class = mono_image_alloc0 (image, sizeof (MonoClass));
5520 class->name = name;
5521 class->name_space = nspace;
5523 mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
5525 class->image = image;
5526 class->type_token = type_token;
5527 class->flags = cols [MONO_TYPEDEF_FLAGS];
5529 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), class);
5531 classes_size += sizeof (MonoClass);
5534 * Check whether we're a generic type definition.
5536 class->generic_container = mono_metadata_load_generic_params (image, class->type_token, NULL);
5537 if (class->generic_container) {
5538 class->is_generic = 1;
5539 class->generic_container->owner.klass = class;
5540 context = &class->generic_container->context;
5543 if (class->generic_container)
5544 enable_gclass_recording ();
5546 if (cols [MONO_TYPEDEF_EXTENDS]) {
5547 MonoClass *tmp;
5548 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
5550 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
5551 /*WARNING: this must satisfy mono_metadata_type_hash*/
5552 class->this_arg.byref = 1;
5553 class->this_arg.data.klass = class;
5554 class->this_arg.type = MONO_TYPE_CLASS;
5555 class->byval_arg.data.klass = class;
5556 class->byval_arg.type = MONO_TYPE_CLASS;
5558 parent = mono_class_get_full (image, parent_token, context);
5560 if (parent == NULL){
5561 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not load parent type"));
5562 mono_loader_clear_error ();
5563 goto parent_failure;
5566 for (tmp = parent; tmp; tmp = tmp->parent) {
5567 if (tmp == class) {
5568 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cycle found while resolving parent"));
5569 goto parent_failure;
5571 if (class->generic_container && tmp->generic_class && tmp->generic_class->container_class == class) {
5572 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Parent extends generic instance of this type"));
5573 goto parent_failure;
5578 mono_class_setup_parent (class, parent);
5580 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
5581 mono_class_setup_mono_type (class);
5583 if (class->generic_container)
5584 disable_gclass_recording (fix_gclass_incomplete_instantiation, class);
5587 * This might access class->byval_arg for recursion generated by generic constraints,
5588 * so it has to come after setup_mono_type ().
5590 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
5591 class->nested_in = mono_class_create_from_typedef (image, nesting_tokeen);
5592 if (!class->nested_in) {
5593 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not load nestedin type"));
5594 mono_loader_unlock ();
5595 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5596 return NULL;
5600 if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
5601 class->unicode = 1;
5603 #ifdef HOST_WIN32
5604 if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
5605 class->unicode = 1;
5606 #endif
5608 class->cast_class = class->element_class = class;
5610 if (!class->enumtype) {
5611 if (!mono_metadata_interfaces_from_typedef_full (
5612 image, type_token, &interfaces, &icount, FALSE, context)){
5613 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not load interfaces"));
5614 mono_loader_unlock ();
5615 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5616 return NULL;
5619 class->interfaces = interfaces;
5620 class->interface_count = icount;
5621 class->interfaces_inited = 1;
5624 /*g_print ("Load class %s\n", name);*/
5627 * Compute the field and method lists
5629 class->field.first = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
5630 class->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
5632 if (tt->rows > tidx){
5633 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
5634 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
5635 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
5636 } else {
5637 field_last = image->tables [MONO_TABLE_FIELD].rows;
5638 method_last = image->tables [MONO_TABLE_METHOD].rows;
5641 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
5642 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
5643 class->field.count = field_last - class->field.first;
5644 else
5645 class->field.count = 0;
5647 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
5648 class->method.count = method_last - class->method.first;
5649 else
5650 class->method.count = 0;
5652 /* reserve space to store vector pointer in arrays */
5653 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
5654 class->instance_size += 2 * sizeof (gpointer);
5655 g_assert (class->field.count == 0);
5658 if (class->enumtype) {
5659 MonoType *enum_basetype = mono_class_find_enum_basetype (class);
5660 if (!enum_basetype) {
5661 /*set it to a default value as the whole runtime can't handle this to be null*/
5662 class->cast_class = class->element_class = mono_defaults.int32_class;
5663 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
5664 mono_loader_unlock ();
5665 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5666 return NULL;
5668 class->cast_class = class->element_class = mono_class_from_mono_type (enum_basetype);
5672 * If we're a generic type definition, load the constraints.
5673 * We must do this after the class has been constructed to make certain recursive scenarios
5674 * work.
5676 if (class->generic_container && !mono_metadata_load_generic_param_constraints_full (image, type_token, class->generic_container)){
5677 char *class_name = g_strdup_printf("%s.%s", class->name_space, class->name);
5678 char *error = concat_two_strings_with_zero (class->image, class_name, class->image->assembly_name);
5679 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, error);
5680 g_free (class_name);
5681 mono_loader_unlock ();
5682 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5683 return NULL;
5686 if (class->image->assembly_name && !strcmp (class->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
5687 if (!strncmp (name, "Vector", 6))
5688 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");
5691 mono_loader_unlock ();
5693 mono_profiler_class_loaded (class, MONO_PROFILE_OK);
5695 return class;
5697 parent_failure:
5698 mono_class_setup_mono_type (class);
5699 mono_loader_unlock ();
5700 mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
5701 return NULL;
5705 /** is klass Nullable<T>? */
5706 gboolean
5707 mono_class_is_nullable (MonoClass *klass)
5709 return klass->generic_class != NULL &&
5710 klass->generic_class->container_class == mono_defaults.generic_nullable_class;
5714 /** if klass is T? return T */
5715 MonoClass*
5716 mono_class_get_nullable_param (MonoClass *klass)
5718 g_assert (mono_class_is_nullable (klass));
5719 return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
5722 static void
5723 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
5725 if (gtd->parent) {
5726 MonoError error;
5727 MonoGenericClass *gclass = klass->generic_class;
5729 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
5730 if (!mono_error_ok (&error)) {
5731 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
5732 klass->parent = mono_defaults.object_class;
5733 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
5734 mono_error_cleanup (&error);
5737 if (klass->parent)
5738 mono_class_setup_parent (klass, klass->parent);
5740 if (klass->enumtype) {
5741 klass->cast_class = gtd->cast_class;
5742 klass->element_class = gtd->element_class;
5748 * Create the `MonoClass' for an instantiation of a generic type.
5749 * We only do this if we actually need it.
5751 MonoClass*
5752 mono_generic_class_get_class (MonoGenericClass *gclass)
5754 MonoClass *klass, *gklass;
5756 if (gclass->cached_class)
5757 return gclass->cached_class;
5759 mono_loader_lock ();
5760 if (gclass->cached_class) {
5761 mono_loader_unlock ();
5762 return gclass->cached_class;
5765 klass = mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
5767 gklass = gclass->container_class;
5769 if (record_gclass_instantiation > 0)
5770 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
5772 if (gklass->nested_in) {
5773 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
5774 klass->nested_in = gklass->nested_in;
5777 klass->name = gklass->name;
5778 klass->name_space = gklass->name_space;
5780 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
5782 klass->image = gklass->image;
5783 klass->flags = gklass->flags;
5784 klass->type_token = gklass->type_token;
5785 klass->field.count = gklass->field.count;
5787 klass->is_inflated = 1;
5788 klass->generic_class = gclass;
5790 klass->this_arg.type = klass->byval_arg.type = MONO_TYPE_GENERICINST;
5791 klass->this_arg.data.generic_class = klass->byval_arg.data.generic_class = gclass;
5792 klass->this_arg.byref = TRUE;
5793 klass->enumtype = gklass->enumtype;
5794 klass->valuetype = gklass->valuetype;
5796 klass->cast_class = klass->element_class = klass;
5798 if (mono_class_is_nullable (klass))
5799 klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
5802 * We're not interested in the nested classes of a generic instance.
5803 * We use the generic type definition to look for nested classes.
5806 mono_generic_class_setup_parent (klass, gklass);
5808 if (gclass->is_dynamic) {
5809 klass->inited = 1;
5811 mono_class_setup_supertypes (klass);
5813 if (klass->enumtype) {
5815 * For enums, gklass->fields might not been set, but instance_size etc. is
5816 * already set in mono_reflection_create_internal_class (). For non-enums,
5817 * these will be computed normally in mono_class_layout_fields ().
5819 klass->instance_size = gklass->instance_size;
5820 klass->sizes.class_size = gklass->sizes.class_size;
5821 mono_memory_barrier ();
5822 klass->size_inited = 1;
5826 mono_memory_barrier ();
5827 gclass->cached_class = klass;
5829 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
5831 inflated_classes ++;
5832 inflated_classes_size += sizeof (MonoClass);
5834 mono_loader_unlock ();
5836 return klass;
5839 static MonoClass*
5840 make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is_mvar, MonoGenericParamInfo *pinfo)
5842 MonoClass *klass, **ptr;
5843 int count, pos, i;
5844 MonoGenericContainer *container = mono_generic_param_owner (param);
5846 if (!image)
5847 /* FIXME: */
5848 image = mono_defaults.corlib;
5850 klass = mono_image_alloc0 (image, sizeof (MonoClass));
5851 classes_size += sizeof (MonoClass);
5853 if (pinfo) {
5854 klass->name = pinfo->name;
5855 } else {
5856 int n = mono_generic_param_num (param);
5857 klass->name = mono_image_alloc0 (image, 16);
5858 sprintf ((char*)klass->name, "%d", n);
5861 if (container) {
5862 if (is_mvar) {
5863 MonoMethod *omethod = container->owner.method;
5864 klass->name_space = (omethod && omethod->klass) ? omethod->klass->name_space : "";
5865 } else {
5866 MonoClass *oklass = container->owner.klass;
5867 klass->name_space = oklass ? oklass->name_space : "";
5869 } else {
5870 klass->name_space = "";
5873 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
5875 count = 0;
5876 if (pinfo)
5877 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
5880 pos = 0;
5881 if ((count > 0) && !MONO_CLASS_IS_INTERFACE (pinfo->constraints [0])) {
5882 klass->parent = pinfo->constraints [0];
5883 pos++;
5884 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
5885 klass->parent = mono_class_from_name (mono_defaults.corlib, "System", "ValueType");
5886 else
5887 klass->parent = mono_defaults.object_class;
5890 if (count - pos > 0) {
5891 klass->interface_count = count - pos;
5892 klass->interfaces = mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos));
5893 klass->interfaces_inited = TRUE;
5894 for (i = pos; i < count; i++)
5895 klass->interfaces [i - pos] = pinfo->constraints [i];
5898 klass->image = image;
5900 klass->inited = TRUE;
5901 klass->cast_class = klass->element_class = klass;
5902 klass->flags = TYPE_ATTRIBUTE_PUBLIC;
5904 klass->this_arg.type = klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
5905 klass->this_arg.data.generic_param = klass->byval_arg.data.generic_param = param;
5906 klass->this_arg.byref = TRUE;
5908 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
5909 klass->sizes.generic_param_token = pinfo ? pinfo->token : 0;
5911 /*Init these fields to sane values*/
5912 klass->min_align = 1;
5913 klass->instance_size = sizeof (gpointer);
5914 mono_memory_barrier ();
5915 klass->size_inited = 1;
5917 mono_class_setup_supertypes (klass);
5919 if (count - pos > 0) {
5920 mono_class_setup_vtable (klass->parent);
5921 if (klass->parent->exception_type)
5922 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to setup parent interfaces"));
5923 else
5924 setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
5927 return klass;
5930 #define FAST_CACHE_SIZE 16
5932 static MonoClass *
5933 get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar)
5935 int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
5936 MonoImage *image = param->image;
5937 GHashTable *ht;
5939 g_assert (image);
5941 if (n < FAST_CACHE_SIZE) {
5942 if (is_mvar)
5943 return image->mvar_cache_fast ? image->mvar_cache_fast [n] : NULL;
5944 else
5945 return image->var_cache_fast ? image->var_cache_fast [n] : NULL;
5946 } else {
5947 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
5948 return ht ? g_hash_table_lookup (ht, GINT_TO_POINTER (n)) : NULL;
5953 * LOCKING: Acquires the loader lock.
5955 static void
5956 set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
5958 int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
5959 MonoImage *image = param->image;
5960 GHashTable *ht;
5962 g_assert (image);
5964 if (n < FAST_CACHE_SIZE) {
5965 if (is_mvar) {
5966 /* No locking needed */
5967 if (!image->mvar_cache_fast)
5968 image->mvar_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
5969 image->mvar_cache_fast [n] = klass;
5970 } else {
5971 if (!image->var_cache_fast)
5972 image->var_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
5973 image->var_cache_fast [n] = klass;
5975 return;
5977 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
5978 if (!ht) {
5979 mono_loader_lock ();
5980 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
5981 if (!ht) {
5982 ht = g_hash_table_new (NULL, NULL);
5983 mono_memory_barrier ();
5984 if (is_mvar)
5985 image->mvar_cache_slow = ht;
5986 else
5987 image->var_cache_slow = ht;
5989 mono_loader_unlock ();
5992 g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
5996 * LOCKING: Acquires the loader lock.
5998 MonoClass *
5999 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar)
6001 MonoGenericContainer *container = mono_generic_param_owner (param);
6002 MonoGenericParamInfo *pinfo;
6003 MonoClass *klass;
6005 mono_loader_lock ();
6007 if (container) {
6008 pinfo = mono_generic_param_info (param);
6009 if (pinfo->pklass) {
6010 mono_loader_unlock ();
6011 return pinfo->pklass;
6013 } else {
6014 pinfo = NULL;
6015 image = NULL;
6017 klass = get_anon_gparam_class (param, is_mvar);
6018 if (klass) {
6019 mono_loader_unlock ();
6020 return klass;
6024 if (!image && container) {
6025 if (is_mvar) {
6026 MonoMethod *method = container->owner.method;
6027 image = (method && method->klass) ? method->klass->image : NULL;
6028 } else {
6029 MonoClass *klass = container->owner.klass;
6030 // FIXME: 'klass' should not be null
6031 // But, monodis creates GenericContainers without associating a owner to it
6032 image = klass ? klass->image : NULL;
6036 klass = make_generic_param_class (param, image, is_mvar, pinfo);
6038 mono_memory_barrier ();
6040 if (container)
6041 pinfo->pklass = klass;
6042 else
6043 set_anon_gparam_class (param, is_mvar, klass);
6045 mono_loader_unlock ();
6047 /* FIXME: Should this go inside 'make_generic_param_klass'? */
6048 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6050 return klass;
6053 MonoClass *
6054 mono_ptr_class_get (MonoType *type)
6056 MonoClass *result;
6057 MonoClass *el_class;
6058 MonoImage *image;
6059 char *name;
6061 el_class = mono_class_from_mono_type (type);
6062 image = el_class->image;
6064 mono_loader_lock ();
6066 if (!image->ptr_cache)
6067 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6069 if ((result = g_hash_table_lookup (image->ptr_cache, el_class))) {
6070 mono_loader_unlock ();
6071 return result;
6073 result = mono_image_alloc0 (image, sizeof (MonoClass));
6075 classes_size += sizeof (MonoClass);
6077 result->parent = NULL; /* no parent for PTR types */
6078 result->name_space = el_class->name_space;
6079 name = g_strdup_printf ("%s*", el_class->name);
6080 result->name = mono_image_strdup (image, name);
6081 g_free (name);
6083 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6085 result->image = el_class->image;
6086 result->inited = TRUE;
6087 result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
6088 /* Can pointers get boxed? */
6089 result->instance_size = sizeof (gpointer);
6090 result->cast_class = result->element_class = el_class;
6091 result->blittable = TRUE;
6093 result->this_arg.type = result->byval_arg.type = MONO_TYPE_PTR;
6094 result->this_arg.data.type = result->byval_arg.data.type = &result->element_class->byval_arg;
6095 result->this_arg.byref = TRUE;
6097 mono_class_setup_supertypes (result);
6099 g_hash_table_insert (image->ptr_cache, el_class, result);
6101 mono_loader_unlock ();
6103 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6105 return result;
6108 static MonoClass *
6109 mono_fnptr_class_get (MonoMethodSignature *sig)
6111 MonoClass *result;
6112 static GHashTable *ptr_hash = NULL;
6114 /* FIXME: These should be allocate from a mempool as well, but which one ? */
6116 mono_loader_lock ();
6118 if (!ptr_hash)
6119 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
6121 if ((result = g_hash_table_lookup (ptr_hash, sig))) {
6122 mono_loader_unlock ();
6123 return result;
6125 result = g_new0 (MonoClass, 1);
6127 result->parent = NULL; /* no parent for PTR types */
6128 result->name_space = "System";
6129 result->name = "MonoFNPtrFakeClass";
6131 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6133 result->image = mono_defaults.corlib; /* need to fix... */
6134 result->inited = TRUE;
6135 result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */
6136 /* Can pointers get boxed? */
6137 result->instance_size = sizeof (gpointer);
6138 result->cast_class = result->element_class = result;
6139 result->blittable = TRUE;
6141 result->this_arg.type = result->byval_arg.type = MONO_TYPE_FNPTR;
6142 result->this_arg.data.method = result->byval_arg.data.method = sig;
6143 result->this_arg.byref = TRUE;
6144 result->blittable = TRUE;
6146 mono_class_setup_supertypes (result);
6148 g_hash_table_insert (ptr_hash, sig, result);
6150 mono_loader_unlock ();
6152 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6154 return result;
6157 MonoClass *
6158 mono_class_from_mono_type (MonoType *type)
6160 switch (type->type) {
6161 case MONO_TYPE_OBJECT:
6162 return type->data.klass? type->data.klass: mono_defaults.object_class;
6163 case MONO_TYPE_VOID:
6164 return type->data.klass? type->data.klass: mono_defaults.void_class;
6165 case MONO_TYPE_BOOLEAN:
6166 return type->data.klass? type->data.klass: mono_defaults.boolean_class;
6167 case MONO_TYPE_CHAR:
6168 return type->data.klass? type->data.klass: mono_defaults.char_class;
6169 case MONO_TYPE_I1:
6170 return type->data.klass? type->data.klass: mono_defaults.sbyte_class;
6171 case MONO_TYPE_U1:
6172 return type->data.klass? type->data.klass: mono_defaults.byte_class;
6173 case MONO_TYPE_I2:
6174 return type->data.klass? type->data.klass: mono_defaults.int16_class;
6175 case MONO_TYPE_U2:
6176 return type->data.klass? type->data.klass: mono_defaults.uint16_class;
6177 case MONO_TYPE_I4:
6178 return type->data.klass? type->data.klass: mono_defaults.int32_class;
6179 case MONO_TYPE_U4:
6180 return type->data.klass? type->data.klass: mono_defaults.uint32_class;
6181 case MONO_TYPE_I:
6182 return type->data.klass? type->data.klass: mono_defaults.int_class;
6183 case MONO_TYPE_U:
6184 return type->data.klass? type->data.klass: mono_defaults.uint_class;
6185 case MONO_TYPE_I8:
6186 return type->data.klass? type->data.klass: mono_defaults.int64_class;
6187 case MONO_TYPE_U8:
6188 return type->data.klass? type->data.klass: mono_defaults.uint64_class;
6189 case MONO_TYPE_R4:
6190 return type->data.klass? type->data.klass: mono_defaults.single_class;
6191 case MONO_TYPE_R8:
6192 return type->data.klass? type->data.klass: mono_defaults.double_class;
6193 case MONO_TYPE_STRING:
6194 return type->data.klass? type->data.klass: mono_defaults.string_class;
6195 case MONO_TYPE_TYPEDBYREF:
6196 return type->data.klass? type->data.klass: mono_defaults.typed_reference_class;
6197 case MONO_TYPE_ARRAY:
6198 return mono_bounded_array_class_get (type->data.array->eklass, type->data.array->rank, TRUE);
6199 case MONO_TYPE_PTR:
6200 return mono_ptr_class_get (type->data.type);
6201 case MONO_TYPE_FNPTR:
6202 return mono_fnptr_class_get (type->data.method);
6203 case MONO_TYPE_SZARRAY:
6204 return mono_array_class_get (type->data.klass, 1);
6205 case MONO_TYPE_CLASS:
6206 case MONO_TYPE_VALUETYPE:
6207 return type->data.klass;
6208 case MONO_TYPE_GENERICINST:
6209 return mono_generic_class_get_class (type->data.generic_class);
6210 case MONO_TYPE_VAR:
6211 return mono_class_from_generic_parameter (type->data.generic_param, NULL, FALSE);
6212 case MONO_TYPE_MVAR:
6213 return mono_class_from_generic_parameter (type->data.generic_param, NULL, TRUE);
6214 default:
6215 g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
6216 g_assert_not_reached ();
6219 return NULL;
6223 * mono_type_retrieve_from_typespec
6224 * @image: context where the image is created
6225 * @type_spec: typespec token
6226 * @context: the generic context used to evaluate generic instantiations in
6228 static MonoType *
6229 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
6231 MonoType *t = mono_type_create_from_typespec (image, type_spec);
6233 mono_error_init (error);
6234 *did_inflate = FALSE;
6236 if (!t) {
6237 char *name = mono_class_name_from_token (image, type_spec);
6238 char *assembly = mono_assembly_name_from_token (image, type_spec);
6239 mono_error_set_type_load_name (error, name, assembly, "Could not resolve typespec token %08x", type_spec);
6240 return NULL;
6243 if (context && (context->class_inst || context->method_inst)) {
6244 MonoType *inflated = inflate_generic_type (NULL, t, context, error);
6246 if (!mono_error_ok (error))
6247 return NULL;
6249 if (inflated) {
6250 t = inflated;
6251 *did_inflate = TRUE;
6254 return t;
6258 * mono_class_create_from_typespec
6259 * @image: context where the image is created
6260 * @type_spec: typespec token
6261 * @context: the generic context used to evaluate generic instantiations in
6263 static MonoClass *
6264 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
6266 MonoClass *ret;
6267 gboolean inflated = FALSE;
6268 MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
6269 if (!mono_error_ok (error))
6270 return NULL;
6271 ret = mono_class_from_mono_type (t);
6272 if (inflated)
6273 mono_metadata_free_type (t);
6274 return ret;
6278 * mono_bounded_array_class_get:
6279 * @element_class: element class
6280 * @rank: the dimension of the array class
6281 * @bounded: whenever the array has non-zero bounds
6283 * Returns: a class object describing the array with element type @element_type and
6284 * dimension @rank.
6286 MonoClass *
6287 mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
6289 MonoImage *image;
6290 MonoClass *class;
6291 MonoClass *parent = NULL;
6292 GSList *list, *rootlist = NULL;
6293 int nsize;
6294 char *name;
6295 gboolean corlib_type = FALSE;
6297 g_assert (rank <= 255);
6299 if (rank > 1)
6300 /* bounded only matters for one-dimensional arrays */
6301 bounded = FALSE;
6303 image = eclass->image;
6305 if (rank == 1 && !bounded) {
6307 * This case is very frequent not just during compilation because of calls
6308 * from mono_class_from_mono_type (), mono_array_new (),
6309 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
6311 EnterCriticalSection (&image->szarray_cache_lock);
6312 if (!image->szarray_cache)
6313 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6314 class = g_hash_table_lookup (image->szarray_cache, eclass);
6315 LeaveCriticalSection (&image->szarray_cache_lock);
6316 if (class)
6317 return class;
6319 mono_loader_lock ();
6320 } else {
6321 mono_loader_lock ();
6323 if (!image->array_cache)
6324 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6326 if ((rootlist = list = g_hash_table_lookup (image->array_cache, eclass))) {
6327 for (; list; list = list->next) {
6328 class = list->data;
6329 if ((class->rank == rank) && (class->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
6330 mono_loader_unlock ();
6331 return class;
6337 /* for the building corlib use System.Array from it */
6338 if (image->assembly && image->assembly->dynamic && image->assembly_name && strcmp (image->assembly_name, "mscorlib") == 0) {
6339 parent = mono_class_from_name (image, "System", "Array");
6340 corlib_type = TRUE;
6341 } else {
6342 parent = mono_defaults.array_class;
6343 if (!parent->inited)
6344 mono_class_init (parent);
6347 class = mono_image_alloc0 (image, sizeof (MonoClass));
6349 class->image = image;
6350 class->name_space = eclass->name_space;
6351 nsize = strlen (eclass->name);
6352 name = g_malloc (nsize + 2 + rank + 1);
6353 memcpy (name, eclass->name, nsize);
6354 name [nsize] = '[';
6355 if (rank > 1)
6356 memset (name + nsize + 1, ',', rank - 1);
6357 if (bounded)
6358 name [nsize + rank] = '*';
6359 name [nsize + rank + bounded] = ']';
6360 name [nsize + rank + bounded + 1] = 0;
6361 class->name = mono_image_strdup (image, name);
6362 g_free (name);
6364 mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
6366 classes_size += sizeof (MonoClass);
6368 class->type_token = 0;
6369 /* all arrays are marked serializable and sealed, bug #42779 */
6370 class->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC;
6371 class->parent = parent;
6372 class->instance_size = mono_class_instance_size (class->parent);
6374 if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
6375 /*Arrays of those two types are invalid.*/
6376 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
6377 } else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
6378 if (!eclass->ref_info_handle || eclass->wastypebuilder) {
6379 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
6380 g_assert (eclass->ref_info_handle && !eclass->wastypebuilder);
6382 /* element_size -1 is ok as this is not an instantitable type*/
6383 class->sizes.element_size = -1;
6384 } else
6385 class->sizes.element_size = mono_class_array_element_size (eclass);
6387 mono_class_setup_supertypes (class);
6389 if (eclass->generic_class)
6390 mono_class_init (eclass);
6391 if (!eclass->size_inited)
6392 mono_class_setup_fields (eclass);
6393 if (eclass->exception_type) /*FIXME we fail the array type, but we have to let other fields be set.*/
6394 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
6396 class->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
6398 class->rank = rank;
6400 if (eclass->enumtype)
6401 class->cast_class = eclass->element_class;
6402 else
6403 class->cast_class = eclass;
6405 switch (class->cast_class->byval_arg.type) {
6406 case MONO_TYPE_I1:
6407 class->cast_class = mono_defaults.byte_class;
6408 break;
6409 case MONO_TYPE_U2:
6410 class->cast_class = mono_defaults.int16_class;
6411 break;
6412 case MONO_TYPE_U4:
6413 #if SIZEOF_VOID_P == 4
6414 case MONO_TYPE_I:
6415 case MONO_TYPE_U:
6416 #endif
6417 class->cast_class = mono_defaults.int32_class;
6418 break;
6419 case MONO_TYPE_U8:
6420 #if SIZEOF_VOID_P == 8
6421 case MONO_TYPE_I:
6422 case MONO_TYPE_U:
6423 #endif
6424 class->cast_class = mono_defaults.int64_class;
6425 break;
6428 class->element_class = eclass;
6430 if ((rank > 1) || bounded) {
6431 MonoArrayType *at = mono_image_alloc0 (image, sizeof (MonoArrayType));
6432 class->byval_arg.type = MONO_TYPE_ARRAY;
6433 class->byval_arg.data.array = at;
6434 at->eklass = eclass;
6435 at->rank = rank;
6436 /* FIXME: complete.... */
6437 } else {
6438 class->byval_arg.type = MONO_TYPE_SZARRAY;
6439 class->byval_arg.data.klass = eclass;
6441 class->this_arg = class->byval_arg;
6442 class->this_arg.byref = 1;
6443 if (corlib_type) {
6444 class->inited = 1;
6447 class->generic_container = eclass->generic_container;
6449 if (rank == 1 && !bounded) {
6450 MonoClass *prev_class;
6452 EnterCriticalSection (&image->szarray_cache_lock);
6453 prev_class = g_hash_table_lookup (image->szarray_cache, eclass);
6454 if (prev_class)
6455 /* Someone got in before us */
6456 class = prev_class;
6457 else
6458 g_hash_table_insert (image->szarray_cache, eclass, class);
6459 LeaveCriticalSection (&image->szarray_cache_lock);
6460 } else {
6461 list = g_slist_append (rootlist, class);
6462 g_hash_table_insert (image->array_cache, eclass, list);
6465 mono_loader_unlock ();
6467 mono_profiler_class_loaded (class, MONO_PROFILE_OK);
6469 return class;
6473 * mono_array_class_get:
6474 * @element_class: element class
6475 * @rank: the dimension of the array class
6477 * Returns: a class object describing the array with element type @element_type and
6478 * dimension @rank.
6480 MonoClass *
6481 mono_array_class_get (MonoClass *eclass, guint32 rank)
6483 return mono_bounded_array_class_get (eclass, rank, FALSE);
6487 * mono_class_instance_size:
6488 * @klass: a class
6490 * Returns: the size of an object instance
6492 gint32
6493 mono_class_instance_size (MonoClass *klass)
6495 if (!klass->size_inited)
6496 mono_class_init (klass);
6498 return klass->instance_size;
6502 * mono_class_min_align:
6503 * @klass: a class
6505 * Returns: minimm alignment requirements
6507 gint32
6508 mono_class_min_align (MonoClass *klass)
6510 if (!klass->size_inited)
6511 mono_class_init (klass);
6513 return klass->min_align;
6517 * mono_class_value_size:
6518 * @klass: a class
6520 * This function is used for value types, and return the
6521 * space and the alignment to store that kind of value object.
6523 * Returns: the size of a value of kind @klass
6525 gint32
6526 mono_class_value_size (MonoClass *klass, guint32 *align)
6528 gint32 size;
6530 /* fixme: check disable, because we still have external revereces to
6531 * mscorlib and Dummy Objects
6533 /*g_assert (klass->valuetype);*/
6535 size = mono_class_instance_size (klass) - sizeof (MonoObject);
6537 if (align)
6538 *align = klass->min_align;
6540 return size;
6544 * mono_class_data_size:
6545 * @klass: a class
6547 * Returns: the size of the static class data
6549 gint32
6550 mono_class_data_size (MonoClass *klass)
6552 if (!klass->inited)
6553 mono_class_init (klass);
6555 /* in arrays, sizes.class_size is unioned with element_size
6556 * and arrays have no static fields
6558 if (klass->rank)
6559 return 0;
6560 return klass->sizes.class_size;
6564 * Auxiliary routine to mono_class_get_field
6566 * Takes a field index instead of a field token.
6568 static MonoClassField *
6569 mono_class_get_field_idx (MonoClass *class, int idx)
6571 mono_class_setup_fields_locking (class);
6572 if (class->exception_type)
6573 return NULL;
6575 while (class) {
6576 if (class->image->uncompressed_metadata) {
6578 * class->field.first points to the FieldPtr table, while idx points into the
6579 * Field table, so we have to do a search.
6581 /*FIXME this is broken for types with multiple fields with the same name.*/
6582 const char *name = mono_metadata_string_heap (class->image, mono_metadata_decode_row_col (&class->image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
6583 int i;
6585 for (i = 0; i < class->field.count; ++i)
6586 if (mono_field_get_name (&class->fields [i]) == name)
6587 return &class->fields [i];
6588 g_assert_not_reached ();
6589 } else {
6590 if (class->field.count) {
6591 if ((idx >= class->field.first) && (idx < class->field.first + class->field.count)){
6592 return &class->fields [idx - class->field.first];
6596 class = class->parent;
6598 return NULL;
6602 * mono_class_get_field:
6603 * @class: the class to lookup the field.
6604 * @field_token: the field token
6606 * Returns: A MonoClassField representing the type and offset of
6607 * the field, or a NULL value if the field does not belong to this
6608 * class.
6610 MonoClassField *
6611 mono_class_get_field (MonoClass *class, guint32 field_token)
6613 int idx = mono_metadata_token_index (field_token);
6615 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
6617 return mono_class_get_field_idx (class, idx - 1);
6621 * mono_class_get_field_from_name:
6622 * @klass: the class to lookup the field.
6623 * @name: the field name
6625 * Search the class @klass and it's parents for a field with the name @name.
6627 * Returns: the MonoClassField pointer of the named field or NULL
6629 MonoClassField *
6630 mono_class_get_field_from_name (MonoClass *klass, const char *name)
6632 return mono_class_get_field_from_name_full (klass, name, NULL);
6636 * mono_class_get_field_from_name_full:
6637 * @klass: the class to lookup the field.
6638 * @name: the field name
6639 * @type: the type of the fields. This optional.
6641 * Search the class @klass and it's parents for a field with the name @name and type @type.
6643 * If @klass is an inflated generic type, the type comparison is done with the equivalent field
6644 * of its generic type definition.
6646 * Returns: the MonoClassField pointer of the named field or NULL
6648 MonoClassField *
6649 mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
6651 int i;
6653 mono_class_setup_fields_locking (klass);
6654 if (klass->exception_type)
6655 return NULL;
6657 while (klass) {
6658 for (i = 0; i < klass->field.count; ++i) {
6659 MonoClassField *field = &klass->fields [i];
6661 if (strcmp (name, mono_field_get_name (field)) != 0)
6662 continue;
6664 if (type) {
6665 MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
6666 if (!mono_metadata_type_equal_full (type, field_type, TRUE))
6667 continue;
6669 return field;
6671 klass = klass->parent;
6673 return NULL;
6677 * mono_class_get_field_token:
6678 * @field: the field we need the token of
6680 * Get the token of a field. Note that the tokesn is only valid for the image
6681 * the field was loaded from. Don't use this function for fields in dynamic types.
6683 * Returns: the token representing the field in the image it was loaded from.
6685 guint32
6686 mono_class_get_field_token (MonoClassField *field)
6688 MonoClass *klass = field->parent;
6689 int i;
6691 mono_class_setup_fields_locking (klass);
6693 while (klass) {
6694 if (!klass->fields)
6695 return 0;
6696 for (i = 0; i < klass->field.count; ++i) {
6697 if (&klass->fields [i] == field) {
6698 int idx = klass->field.first + i + 1;
6700 if (klass->image->uncompressed_metadata)
6701 idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx);
6702 return mono_metadata_make_token (MONO_TABLE_FIELD, idx);
6705 klass = klass->parent;
6708 g_assert_not_reached ();
6709 return 0;
6712 static int
6713 mono_field_get_index (MonoClassField *field)
6715 int index = field - field->parent->fields;
6717 g_assert (index >= 0 && index < field->parent->field.count);
6719 return index;
6723 * mono_class_get_field_default_value:
6725 * Return the default value of the field as a pointer into the metadata blob.
6727 const char*
6728 mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
6730 guint32 cindex;
6731 guint32 constant_cols [MONO_CONSTANT_SIZE];
6732 int field_index;
6733 MonoClass *klass = field->parent;
6735 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
6737 if (!klass->ext || !klass->ext->field_def_values) {
6738 mono_loader_lock ();
6739 mono_class_alloc_ext (klass);
6740 if (!klass->ext->field_def_values)
6741 klass->ext->field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
6742 mono_loader_unlock ();
6745 field_index = mono_field_get_index (field);
6747 if (!klass->ext->field_def_values [field_index].data) {
6748 cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
6749 if (!cindex)
6750 return NULL;
6752 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
6754 mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
6755 klass->ext->field_def_values [field_index].def_type = constant_cols [MONO_CONSTANT_TYPE];
6756 klass->ext->field_def_values [field_index].data = (gpointer)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
6759 *def_type = klass->ext->field_def_values [field_index].def_type;
6760 return klass->ext->field_def_values [field_index].data;
6763 static int
6764 mono_property_get_index (MonoProperty *prop)
6766 int index = prop - prop->parent->ext->properties;
6768 g_assert (index >= 0 && index < prop->parent->ext->property.count);
6770 return index;
6774 * mono_class_get_property_default_value:
6776 * Return the default value of the field as a pointer into the metadata blob.
6778 const char*
6779 mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type)
6781 guint32 cindex;
6782 guint32 constant_cols [MONO_CONSTANT_SIZE];
6783 MonoClass *klass = property->parent;
6785 g_assert (property->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT);
6787 * We don't cache here because it is not used by C# so it's quite rare, but
6788 * we still do the lookup in klass->ext because that is where the data
6789 * is stored for dynamic assemblies.
6792 if (klass->image->dynamic) {
6793 int prop_index = mono_property_get_index (property);
6794 if (klass->ext->prop_def_values && klass->ext->prop_def_values [prop_index].data) {
6795 *def_type = klass->ext->prop_def_values [prop_index].def_type;
6796 return klass->ext->prop_def_values [prop_index].data;
6798 return NULL;
6800 cindex = mono_metadata_get_constant_index (klass->image, mono_class_get_property_token (property), 0);
6801 if (!cindex)
6802 return NULL;
6804 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
6805 *def_type = constant_cols [MONO_CONSTANT_TYPE];
6806 return (gpointer)mono_metadata_blob_heap (klass->image, constant_cols [MONO_CONSTANT_VALUE]);
6809 guint32
6810 mono_class_get_event_token (MonoEvent *event)
6812 MonoClass *klass = event->parent;
6813 int i;
6815 while (klass) {
6816 if (klass->ext) {
6817 for (i = 0; i < klass->ext->event.count; ++i) {
6818 if (&klass->ext->events [i] == event)
6819 return mono_metadata_make_token (MONO_TABLE_EVENT, klass->ext->event.first + i + 1);
6822 klass = klass->parent;
6825 g_assert_not_reached ();
6826 return 0;
6829 MonoProperty*
6830 mono_class_get_property_from_name (MonoClass *klass, const char *name)
6832 while (klass) {
6833 MonoProperty* p;
6834 gpointer iter = NULL;
6835 while ((p = mono_class_get_properties (klass, &iter))) {
6836 if (! strcmp (name, p->name))
6837 return p;
6839 klass = klass->parent;
6841 return NULL;
6844 guint32
6845 mono_class_get_property_token (MonoProperty *prop)
6847 MonoClass *klass = prop->parent;
6848 while (klass) {
6849 MonoProperty* p;
6850 int i = 0;
6851 gpointer iter = NULL;
6852 while ((p = mono_class_get_properties (klass, &iter))) {
6853 if (&klass->ext->properties [i] == prop)
6854 return mono_metadata_make_token (MONO_TABLE_PROPERTY, klass->ext->property.first + i + 1);
6856 i ++;
6858 klass = klass->parent;
6861 g_assert_not_reached ();
6862 return 0;
6865 char *
6866 mono_class_name_from_token (MonoImage *image, guint32 type_token)
6868 const char *name, *nspace;
6869 if (image->dynamic)
6870 return g_strdup_printf ("DynamicType 0x%08x", type_token);
6872 switch (type_token & 0xff000000){
6873 case MONO_TOKEN_TYPE_DEF: {
6874 guint32 cols [MONO_TYPEDEF_SIZE];
6875 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
6876 guint tidx = mono_metadata_token_index (type_token);
6878 if (tidx > tt->rows)
6879 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
6881 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
6882 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
6883 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
6884 if (strlen (nspace) == 0)
6885 return g_strdup_printf ("%s", name);
6886 else
6887 return g_strdup_printf ("%s.%s", nspace, name);
6890 case MONO_TOKEN_TYPE_REF: {
6891 MonoError error;
6892 guint32 cols [MONO_TYPEREF_SIZE];
6893 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
6894 guint tidx = mono_metadata_token_index (type_token);
6896 if (tidx > t->rows)
6897 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
6899 if (!mono_verifier_verify_typeref_row (image, tidx - 1, &error)) {
6900 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
6901 mono_error_cleanup (&error);
6902 return msg;
6905 mono_metadata_decode_row (t, tidx-1, cols, MONO_TYPEREF_SIZE);
6906 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
6907 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
6908 if (strlen (nspace) == 0)
6909 return g_strdup_printf ("%s", name);
6910 else
6911 return g_strdup_printf ("%s.%s", nspace, name);
6914 case MONO_TOKEN_TYPE_SPEC:
6915 return g_strdup_printf ("Typespec 0x%08x", type_token);
6916 default:
6917 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
6921 static char *
6922 mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
6924 if (image->dynamic)
6925 return g_strdup_printf ("DynamicAssembly %s", image->name);
6927 switch (type_token & 0xff000000){
6928 case MONO_TOKEN_TYPE_DEF:
6929 if (image->assembly)
6930 return mono_stringify_assembly_name (&image->assembly->aname);
6931 else if (image->assembly_name)
6932 return g_strdup (image->assembly_name);
6933 return g_strdup_printf ("%s", image->name ? image->name : "[Could not resolve assembly name");
6934 case MONO_TOKEN_TYPE_REF: {
6935 MonoError error;
6936 MonoAssemblyName aname;
6937 guint32 cols [MONO_TYPEREF_SIZE];
6938 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
6939 guint32 idx = mono_metadata_token_index (type_token);
6941 if (idx > t->rows)
6942 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
6944 if (!mono_verifier_verify_typeref_row (image, idx - 1, &error)) {
6945 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
6946 mono_error_cleanup (&error);
6947 return msg;
6949 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
6951 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLTION_SCOPE_BITS;
6952 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLTION_SCOPE_MASK) {
6953 case MONO_RESOLTION_SCOPE_MODULE:
6954 /* FIXME: */
6955 return g_strdup ("");
6956 case MONO_RESOLTION_SCOPE_MODULEREF:
6957 /* FIXME: */
6958 return g_strdup ("");
6959 case MONO_RESOLTION_SCOPE_TYPEREF:
6960 /* FIXME: */
6961 return g_strdup ("");
6962 case MONO_RESOLTION_SCOPE_ASSEMBLYREF:
6963 mono_assembly_get_assemblyref (image, idx - 1, &aname);
6964 return mono_stringify_assembly_name (&aname);
6965 default:
6966 g_assert_not_reached ();
6968 break;
6970 case MONO_TOKEN_TYPE_SPEC:
6971 /* FIXME: */
6972 return g_strdup ("");
6973 default:
6974 g_assert_not_reached ();
6977 return NULL;
6981 * mono_class_get_full:
6982 * @image: the image where the class resides
6983 * @type_token: the token for the class
6984 * @context: the generic context used to evaluate generic instantiations in
6986 * Returns: the MonoClass that represents @type_token in @image
6988 MonoClass *
6989 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
6991 MonoError error;
6992 MonoClass *class = NULL;
6994 if (image->dynamic) {
6995 int table = mono_metadata_token_table (type_token);
6997 if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
6998 mono_loader_set_error_bad_image (g_strdup ("Bad type token."));
6999 return NULL;
7001 return mono_lookup_dynamic_token (image, type_token, context);
7004 switch (type_token & 0xff000000){
7005 case MONO_TOKEN_TYPE_DEF:
7006 class = mono_class_create_from_typedef (image, type_token);
7007 break;
7008 case MONO_TOKEN_TYPE_REF:
7009 class = mono_class_from_typeref (image, type_token);
7010 break;
7011 case MONO_TOKEN_TYPE_SPEC:
7012 class = mono_class_create_from_typespec (image, type_token, context, &error);
7013 if (!mono_error_ok (&error)) {
7014 /*FIXME don't swallow the error message*/
7015 mono_error_cleanup (&error);
7017 break;
7018 default:
7019 g_warning ("unknown token type %x", type_token & 0xff000000);
7020 g_assert_not_reached ();
7023 if (!class){
7024 char *name = mono_class_name_from_token (image, type_token);
7025 char *assembly = mono_assembly_name_from_token (image, type_token);
7026 mono_loader_set_error_type_load (name, assembly);
7027 g_free (name);
7028 g_free (assembly);
7031 return class;
7036 * mono_type_get_full:
7037 * @image: the image where the type resides
7038 * @type_token: the token for the type
7039 * @context: the generic context used to evaluate generic instantiations in
7041 * This functions exists to fullfill the fact that sometimes it's desirable to have access to the
7043 * Returns: the MonoType that represents @type_token in @image
7045 MonoType *
7046 mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
7048 MonoError error;
7049 MonoType *type = NULL;
7050 gboolean inflated = FALSE;
7052 //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
7053 if (image->dynamic)
7054 return mono_class_get_type (mono_lookup_dynamic_token (image, type_token, context));
7056 if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
7057 MonoClass *class = mono_class_get_full (image, type_token, context);
7058 return class ? mono_class_get_type (class) : NULL;
7061 type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, &error);
7063 if (!mono_error_ok (&error)) {
7064 /*FIXME don't swalloc the error message.*/
7065 char *name = mono_class_name_from_token (image, type_token);
7066 char *assembly = mono_assembly_name_from_token (image, type_token);
7068 g_warning ("Error loading type %s from %s due to %s", name, assembly, mono_error_get_message (&error));
7070 mono_error_cleanup (&error);
7071 mono_loader_set_error_type_load (name, assembly);
7072 return NULL;
7075 if (inflated) {
7076 MonoType *tmp = type;
7077 type = mono_class_get_type (mono_class_from_mono_type (type));
7078 /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
7079 * A MonoClass::byval_arg of a generic type definion has type CLASS.
7080 * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with byval_arg.
7082 * The long term solution is to chaise this places and make then set MonoType::type correctly.
7083 * */
7084 if (type->type != tmp->type)
7085 type = tmp;
7086 else
7087 mono_metadata_free_type (tmp);
7089 return type;
7093 MonoClass *
7094 mono_class_get (MonoImage *image, guint32 type_token)
7096 return mono_class_get_full (image, type_token, NULL);
7100 * mono_image_init_name_cache:
7102 * Initializes the class name cache stored in image->name_cache.
7104 * LOCKING: Acquires the corresponding image lock.
7106 void
7107 mono_image_init_name_cache (MonoImage *image)
7109 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7110 guint32 cols [MONO_TYPEDEF_SIZE];
7111 const char *name;
7112 const char *nspace;
7113 guint32 i, visib, nspace_index;
7114 GHashTable *name_cache2, *nspace_table;
7116 mono_image_lock (image);
7118 if (image->name_cache) {
7119 mono_image_unlock (image);
7120 return;
7123 image->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
7125 if (image->dynamic) {
7126 mono_image_unlock (image);
7127 return;
7130 /* Temporary hash table to avoid lookups in the nspace_table */
7131 name_cache2 = g_hash_table_new (NULL, NULL);
7133 for (i = 1; i <= t->rows; ++i) {
7134 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7135 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7137 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7138 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7140 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7141 continue;
7142 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7143 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7145 nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
7146 nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7147 if (!nspace_table) {
7148 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7149 g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
7150 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7151 nspace_table);
7153 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
7156 /* Load type names from EXPORTEDTYPES table */
7158 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7159 guint32 cols [MONO_EXP_TYPE_SIZE];
7160 int i;
7162 for (i = 0; i < t->rows; ++i) {
7163 mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
7164 name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
7165 nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
7167 nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
7168 nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7169 if (!nspace_table) {
7170 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7171 g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
7172 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7173 nspace_table);
7175 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
7179 g_hash_table_destroy (name_cache2);
7180 mono_image_unlock (image);
7183 /*FIXME Only dynamic assemblies should allow this operation.*/
7184 void
7185 mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
7186 const char *name, guint32 index)
7188 GHashTable *nspace_table;
7189 GHashTable *name_cache;
7190 guint32 old_index;
7192 mono_image_lock (image);
7194 if (!image->name_cache)
7195 mono_image_init_name_cache (image);
7197 name_cache = image->name_cache;
7198 if (!(nspace_table = g_hash_table_lookup (name_cache, nspace))) {
7199 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7200 g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
7203 if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
7204 g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
7206 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
7208 mono_image_unlock (image);
7211 typedef struct {
7212 gconstpointer key;
7213 gpointer value;
7214 } FindUserData;
7216 static void
7217 find_nocase (gpointer key, gpointer value, gpointer user_data)
7219 char *name = (char*)key;
7220 FindUserData *data = (FindUserData*)user_data;
7222 if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
7223 data->value = value;
7227 * mono_class_from_name_case:
7228 * @image: The MonoImage where the type is looked up in
7229 * @name_space: the type namespace
7230 * @name: the type short name.
7232 * Obtains a MonoClass with a given namespace and a given name which
7233 * is located in the given MonoImage. The namespace and name
7234 * lookups are case insensitive.
7236 MonoClass *
7237 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
7239 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7240 guint32 cols [MONO_TYPEDEF_SIZE];
7241 const char *n;
7242 const char *nspace;
7243 guint32 i, visib;
7245 if (image->dynamic) {
7246 guint32 token = 0;
7247 FindUserData user_data;
7249 mono_image_lock (image);
7251 if (!image->name_cache)
7252 mono_image_init_name_cache (image);
7254 user_data.key = name_space;
7255 user_data.value = NULL;
7256 g_hash_table_foreach (image->name_cache, find_nocase, &user_data);
7258 if (user_data.value) {
7259 GHashTable *nspace_table = (GHashTable*)user_data.value;
7261 user_data.key = name;
7262 user_data.value = NULL;
7264 g_hash_table_foreach (nspace_table, find_nocase, &user_data);
7266 if (user_data.value)
7267 token = GPOINTER_TO_UINT (user_data.value);
7270 mono_image_unlock (image);
7272 if (token)
7273 return mono_class_get (image, MONO_TOKEN_TYPE_DEF | token);
7274 else
7275 return NULL;
7279 /* add a cache if needed */
7280 for (i = 1; i <= t->rows; ++i) {
7281 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7282 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7284 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7285 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7287 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7288 continue;
7289 n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7290 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7291 if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
7292 return mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
7294 return NULL;
7297 static MonoClass*
7298 return_nested_in (MonoClass *class, char *nested)
7300 MonoClass *found;
7301 char *s = strchr (nested, '/');
7302 gpointer iter = NULL;
7304 if (s) {
7305 *s = 0;
7306 s++;
7309 while ((found = mono_class_get_nested_types (class, &iter))) {
7310 if (strcmp (found->name, nested) == 0) {
7311 if (s)
7312 return return_nested_in (found, s);
7313 return found;
7316 return NULL;
7319 static MonoClass*
7320 search_modules (MonoImage *image, const char *name_space, const char *name)
7322 MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
7323 MonoImage *file_image;
7324 MonoClass *class;
7325 int i;
7328 * The EXPORTEDTYPES table only contains public types, so have to search the
7329 * modules as well.
7330 * Note: image->modules contains the contents of the MODULEREF table, while
7331 * the real module list is in the FILE table.
7333 for (i = 0; i < file_table->rows; i++) {
7334 guint32 cols [MONO_FILE_SIZE];
7335 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
7336 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
7337 continue;
7339 file_image = mono_image_load_file_for_image (image, i + 1);
7340 if (file_image) {
7341 class = mono_class_from_name (file_image, name_space, name);
7342 if (class)
7343 return class;
7347 return NULL;
7351 * mono_class_from_name:
7352 * @image: The MonoImage where the type is looked up in
7353 * @name_space: the type namespace
7354 * @name: the type short name.
7356 * Obtains a MonoClass with a given namespace and a given name which
7357 * is located in the given MonoImage.
7359 MonoClass *
7360 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
7362 GHashTable *nspace_table;
7363 MonoImage *loaded_image;
7364 guint32 token = 0;
7365 int i;
7366 MonoClass *class;
7367 char *nested;
7368 char buf [1024];
7370 if ((nested = strchr (name, '/'))) {
7371 int pos = nested - name;
7372 int len = strlen (name);
7373 if (len > 1023)
7374 return NULL;
7375 memcpy (buf, name, len + 1);
7376 buf [pos] = 0;
7377 nested = buf + pos + 1;
7378 name = buf;
7381 /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */
7382 if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
7383 gboolean res = get_class_from_name (image, name_space, name, &class);
7384 if (res) {
7385 if (!class)
7386 class = search_modules (image, name_space, name);
7387 if (nested)
7388 return class ? return_nested_in (class, nested) : NULL;
7389 else
7390 return class;
7394 mono_image_lock (image);
7396 if (!image->name_cache)
7397 mono_image_init_name_cache (image);
7399 nspace_table = g_hash_table_lookup (image->name_cache, name_space);
7401 if (nspace_table)
7402 token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
7404 mono_image_unlock (image);
7406 if (!token && image->dynamic && image->modules) {
7407 /* Search modules as well */
7408 for (i = 0; i < image->module_count; ++i) {
7409 MonoImage *module = image->modules [i];
7411 class = mono_class_from_name (module, name_space, name);
7412 if (class)
7413 return class;
7417 if (!token) {
7418 class = search_modules (image, name_space, name);
7419 if (class)
7420 return class;
7423 if (!token)
7424 return NULL;
7426 if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
7427 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7428 guint32 cols [MONO_EXP_TYPE_SIZE];
7429 guint32 idx, impl;
7431 idx = mono_metadata_token_index (token);
7433 mono_metadata_decode_row (t, idx - 1, cols, MONO_EXP_TYPE_SIZE);
7435 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
7436 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
7437 loaded_image = mono_assembly_load_module (image->assembly, impl >> MONO_IMPLEMENTATION_BITS);
7438 if (!loaded_image)
7439 return NULL;
7440 class = mono_class_from_name (loaded_image, name_space, name);
7441 if (nested)
7442 return return_nested_in (class, nested);
7443 return class;
7444 } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
7445 guint32 assembly_idx;
7447 assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
7449 mono_assembly_load_reference (image, assembly_idx - 1);
7450 g_assert (image->references [assembly_idx - 1]);
7451 if (image->references [assembly_idx - 1] == (gpointer)-1)
7452 return NULL;
7453 else
7454 /* FIXME: Cycle detection */
7455 return mono_class_from_name (image->references [assembly_idx - 1]->image, name_space, name);
7456 } else {
7457 g_error ("not yet implemented");
7461 token = MONO_TOKEN_TYPE_DEF | token;
7463 class = mono_class_get (image, token);
7464 if (nested)
7465 return return_nested_in (class, nested);
7466 return class;
7469 /*FIXME test for interfaces with variant generic arguments*/
7470 gboolean
7471 mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
7472 gboolean check_interfaces)
7474 if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
7475 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
7476 return TRUE;
7477 } else if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && MONO_CLASS_IS_INTERFACE (klass)) {
7478 int i;
7480 for (i = 0; i < klass->interface_count; i ++) {
7481 MonoClass *ic = klass->interfaces [i];
7482 if (ic == klassc)
7483 return TRUE;
7485 } else {
7486 if (!MONO_CLASS_IS_INTERFACE (klass) && mono_class_has_parent (klass, klassc))
7487 return TRUE;
7491 * MS.NET thinks interfaces are a subclass of Object, so we think it as
7492 * well.
7494 if (klassc == mono_defaults.object_class)
7495 return TRUE;
7497 return FALSE;
7500 static gboolean
7501 mono_type_is_generic_argument (MonoType *type)
7503 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
7506 gboolean
7507 mono_class_has_variant_generic_params (MonoClass *klass)
7509 int i;
7510 MonoGenericContainer *container;
7512 if (!klass->generic_class)
7513 return FALSE;
7515 container = klass->generic_class->container_class->generic_container;
7517 for (i = 0; i < container->type_argc; ++i)
7518 if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
7519 return TRUE;
7521 return FALSE;
7524 static gboolean
7525 mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
7527 if (target == candidate)
7528 return TRUE;
7530 if (check_for_reference_conv &&
7531 mono_type_is_generic_argument (&target->byval_arg) &&
7532 mono_type_is_generic_argument (&candidate->byval_arg)) {
7533 MonoGenericParam *gparam = candidate->byval_arg.data.generic_param;
7534 MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
7536 if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
7537 return FALSE;
7539 if (!mono_class_is_assignable_from (target, candidate))
7540 return FALSE;
7541 return TRUE;
7545 * @container the generic container from the GTD
7546 * @klass: the class to be assigned to
7547 * @oklass: the source class
7549 * Both klass and oklass must be instances of the same generic interface.
7550 * Return true if @klass can be assigned to a @klass variable
7552 gboolean
7553 mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
7555 int j;
7556 MonoType **klass_argv, **oklass_argv;
7557 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
7558 MonoGenericContainer *container = klass_gtd->generic_container;
7560 if (klass == oklass)
7561 return TRUE;
7563 /*Viable candidates are instances of the same generic interface*/
7564 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
7565 return FALSE;
7567 klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
7568 oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
7570 for (j = 0; j < container->type_argc; ++j) {
7571 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
7572 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
7574 if (param1_class->valuetype != param2_class->valuetype || (param1_class->valuetype && param1_class != param2_class))
7575 return FALSE;
7578 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
7579 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
7581 if (param1_class != param2_class) {
7582 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
7583 if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
7584 return FALSE;
7585 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
7586 if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
7587 return FALSE;
7588 } else
7589 return FALSE;
7592 return TRUE;
7595 static gboolean
7596 mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
7598 MonoGenericParam *gparam, *ogparam;
7599 MonoGenericParamInfo *tinfo, *cinfo;
7600 MonoClass **candidate_class;
7601 gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
7602 int tmask, cmask;
7604 if (target == candidate)
7605 return TRUE;
7606 if (target->byval_arg.type != candidate->byval_arg.type)
7607 return FALSE;
7609 gparam = target->byval_arg.data.generic_param;
7610 ogparam = candidate->byval_arg.data.generic_param;
7611 tinfo = mono_generic_param_info (gparam);
7612 cinfo = mono_generic_param_info (ogparam);
7614 class_constraint_satisfied = FALSE;
7615 valuetype_constraint_satisfied = FALSE;
7617 /*candidate must have a super set of target's special constraints*/
7618 tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
7619 cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
7621 if (cinfo->constraints) {
7622 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
7623 MonoClass *cc = *candidate_class;
7625 if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
7626 class_constraint_satisfied = TRUE;
7627 else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
7628 valuetype_constraint_satisfied = TRUE;
7631 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
7632 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
7634 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
7635 return FALSE;
7636 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
7637 return FALSE;
7638 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
7639 valuetype_constraint_satisfied)) {
7640 return FALSE;
7644 /*candidate type constraints must be a superset of target's*/
7645 if (tinfo->constraints) {
7646 MonoClass **target_class;
7647 for (target_class = tinfo->constraints; *target_class; ++target_class) {
7648 MonoClass *tc = *target_class;
7651 * A constraint from @target might inflate into @candidate itself and in that case we don't need
7652 * check it's constraints since it satisfy the constraint by itself.
7654 if (mono_metadata_type_equal (&tc->byval_arg, &candidate->byval_arg))
7655 continue;
7657 if (!cinfo->constraints)
7658 return FALSE;
7660 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
7661 MonoClass *cc = *candidate_class;
7663 if (mono_class_is_assignable_from (tc, cc))
7664 break;
7667 * This happens when we have the following:
7669 * Bar<K> where K : IFace
7670 * Foo<T, U> where T : U where U : IFace
7671 * ...
7672 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
7675 if (mono_type_is_generic_argument (&cc->byval_arg)) {
7676 if (mono_gparam_is_assignable_from (target, cc))
7677 break;
7680 if (!*candidate_class)
7681 return FALSE;
7685 /*candidate itself must have a constraint that satisfy target*/
7686 if (cinfo->constraints) {
7687 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
7688 MonoClass *cc = *candidate_class;
7689 if (mono_class_is_assignable_from (target, cc))
7690 return TRUE;
7693 return FALSE;
7697 * mono_class_is_assignable_from:
7698 * @klass: the class to be assigned to
7699 * @oklass: the source class
7701 * Return: true if an instance of object oklass can be assigned to an
7702 * instance of object @klass
7704 gboolean
7705 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
7707 /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
7708 if (!klass->inited)
7709 mono_class_init (klass);
7711 if (!oklass->inited)
7712 mono_class_init (oklass);
7714 if (klass->exception_type || oklass->exception_type)
7715 return FALSE;
7717 if (mono_type_is_generic_argument (&klass->byval_arg)) {
7718 if (!mono_type_is_generic_argument (&oklass->byval_arg))
7719 return FALSE;
7720 return mono_gparam_is_assignable_from (klass, oklass);
7723 if (MONO_CLASS_IS_INTERFACE (klass)) {
7724 if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
7725 MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
7726 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
7727 int i;
7729 if (constraints) {
7730 for (i = 0; constraints [i]; ++i) {
7731 if (mono_class_is_assignable_from (klass, constraints [i]))
7732 return TRUE;
7736 return FALSE;
7739 /* interface_offsets might not be set for dynamic classes */
7740 if (oklass->ref_info_handle && !oklass->interface_bitmap)
7742 * oklass might be a generic type parameter but they have
7743 * interface_offsets set.
7745 return mono_reflection_call_is_assignable_to (oklass, klass);
7746 if (!oklass->interface_bitmap)
7747 /* Happens with generic instances of not-yet created dynamic types */
7748 return FALSE;
7749 if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
7750 return TRUE;
7752 if (mono_class_has_variant_generic_params (klass)) {
7753 MonoError error;
7754 int i;
7755 mono_class_setup_interfaces (oklass, &error);
7756 if (!mono_error_ok (&error)) {
7757 mono_error_cleanup (&error);
7758 return FALSE;
7761 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
7762 for (i = 0; i < oklass->interface_offsets_count; ++i) {
7763 MonoClass *iface = oklass->interfaces_packed [i];
7765 if (mono_class_is_variant_compatible (klass, iface, FALSE))
7766 return TRUE;
7769 return FALSE;
7770 } else if (klass->delegate) {
7771 if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE))
7772 return TRUE;
7773 }else if (klass->rank) {
7774 MonoClass *eclass, *eoclass;
7776 if (oklass->rank != klass->rank)
7777 return FALSE;
7779 /* vectors vs. one dimensional arrays */
7780 if (oklass->byval_arg.type != klass->byval_arg.type)
7781 return FALSE;
7783 eclass = klass->cast_class;
7784 eoclass = oklass->cast_class;
7787 * a is b does not imply a[] is b[] when a is a valuetype, and
7788 * b is a reference type.
7791 if (eoclass->valuetype) {
7792 if ((eclass == mono_defaults.enum_class) ||
7793 (eclass == mono_defaults.enum_class->parent) ||
7794 (eclass == mono_defaults.object_class))
7795 return FALSE;
7798 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
7799 } else if (mono_class_is_nullable (klass)) {
7800 if (mono_class_is_nullable (oklass))
7801 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
7802 else
7803 return mono_class_is_assignable_from (klass->cast_class, oklass);
7804 } else if (klass == mono_defaults.object_class)
7805 return TRUE;
7807 return mono_class_has_parent (oklass, klass);
7810 /*Check if @oklass is variant compatible with @klass.*/
7811 static gboolean
7812 mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
7814 int j;
7815 MonoType **klass_argv, **oklass_argv;
7816 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
7817 MonoGenericContainer *container = klass_gtd->generic_container;
7819 /*Viable candidates are instances of the same generic interface*/
7820 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
7821 return FALSE;
7823 klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
7824 oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
7826 for (j = 0; j < container->type_argc; ++j) {
7827 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
7828 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
7830 if (param1_class->valuetype != param2_class->valuetype)
7831 return FALSE;
7834 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
7835 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
7837 if (param1_class != param2_class) {
7838 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
7839 if (!mono_class_is_assignable_from_slow (param1_class, param2_class))
7840 return FALSE;
7841 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
7842 if (!mono_class_is_assignable_from_slow (param2_class, param1_class))
7843 return FALSE;
7844 } else
7845 return FALSE;
7848 return TRUE;
7850 /*Check if @candidate implements the interface @target*/
7851 static gboolean
7852 mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
7854 MonoError error;
7855 int i;
7856 gboolean is_variant = mono_class_has_variant_generic_params (target);
7858 if (is_variant && MONO_CLASS_IS_INTERFACE (candidate)) {
7859 if (mono_class_is_variant_compatible_slow (target, candidate))
7860 return TRUE;
7863 do {
7864 if (candidate == target)
7865 return TRUE;
7867 /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
7868 if (candidate->image->dynamic && !candidate->wastypebuilder) {
7869 MonoReflectionTypeBuilder *tb = mono_class_get_ref_info (candidate);
7870 int j;
7871 if (tb && tb->interfaces) {
7872 for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
7873 MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
7874 MonoClass *iface_class;
7876 /* we can't realize the type here since it can do pretty much anything. */
7877 if (!iface->type)
7878 continue;
7879 iface_class = mono_class_from_mono_type (iface->type);
7880 if (iface_class == target)
7881 return TRUE;
7882 if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class))
7883 return TRUE;
7884 if (mono_class_implement_interface_slow (target, iface_class))
7885 return TRUE;
7888 } else {
7889 /*setup_interfaces don't mono_class_init anything*/
7890 mono_class_setup_interfaces (candidate, &error);
7891 if (!mono_error_ok (&error)) {
7892 mono_error_cleanup (&error);
7893 return FALSE;
7896 for (i = 0; i < candidate->interface_count; ++i) {
7897 if (candidate->interfaces [i] == target)
7898 return TRUE;
7900 if (is_variant && mono_class_is_variant_compatible_slow (target, candidate->interfaces [i]))
7901 return TRUE;
7903 if (mono_class_implement_interface_slow (target, candidate->interfaces [i]))
7904 return TRUE;
7907 candidate = candidate->parent;
7908 } while (candidate);
7910 return FALSE;
7914 * Check if @oklass can be assigned to @klass.
7915 * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context.
7917 gboolean
7918 mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
7920 if (candidate == target)
7921 return TRUE;
7922 if (target == mono_defaults.object_class)
7923 return TRUE;
7925 if (mono_class_has_parent (candidate, target))
7926 return TRUE;
7928 /*If target is not an interface there is no need to check them.*/
7929 if (MONO_CLASS_IS_INTERFACE (target))
7930 return mono_class_implement_interface_slow (target, candidate);
7932 if (target->delegate && mono_class_has_variant_generic_params (target))
7933 return mono_class_is_variant_compatible (target, candidate, FALSE);
7935 /*FIXME properly handle nullables and arrays */
7936 /*FIXME properly handle (M)VAR */
7937 return FALSE;
7941 * mono_class_get_cctor:
7942 * @klass: A MonoClass pointer
7944 * Returns: the static constructor of @klass if it exists, NULL otherwise.
7946 MonoMethod*
7947 mono_class_get_cctor (MonoClass *klass)
7949 MonoCachedClassInfo cached_info;
7951 if (klass->image->dynamic) {
7953 * has_cctor is not set for these classes because mono_class_init () is
7954 * not run for them.
7956 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
7959 if (!klass->has_cctor)
7960 return NULL;
7962 if (mono_class_get_cached_class_info (klass, &cached_info))
7963 return mono_get_method (klass->image, cached_info.cctor_token, klass);
7965 if (klass->generic_class && !klass->methods)
7966 return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class));
7968 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
7972 * mono_class_get_finalizer:
7973 * @klass: The MonoClass pointer
7975 * Returns: the finalizer method of @klass if it exists, NULL otherwise.
7977 MonoMethod*
7978 mono_class_get_finalizer (MonoClass *klass)
7980 MonoCachedClassInfo cached_info;
7982 if (!klass->inited)
7983 mono_class_init (klass);
7984 if (!mono_class_has_finalizer (klass))
7985 return NULL;
7987 if (mono_class_get_cached_class_info (klass, &cached_info))
7988 return mono_get_method (cached_info.finalize_image, cached_info.finalize_token, NULL);
7989 else {
7990 mono_class_setup_vtable (klass);
7991 return klass->vtable [finalize_slot];
7996 * mono_class_needs_cctor_run:
7997 * @klass: the MonoClass pointer
7998 * @caller: a MonoMethod describing the caller
8000 * Determines whenever the class has a static constructor and whenever it
8001 * needs to be called when executing CALLER.
8003 gboolean
8004 mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
8006 MonoMethod *method;
8008 method = mono_class_get_cctor (klass);
8009 if (method)
8010 return (method == caller) ? FALSE : TRUE;
8011 else
8012 return FALSE;
8016 * mono_class_array_element_size:
8017 * @klass:
8019 * Returns: the number of bytes an element of type @klass
8020 * uses when stored into an array.
8022 gint32
8023 mono_class_array_element_size (MonoClass *klass)
8025 MonoType *type = &klass->byval_arg;
8027 handle_enum:
8028 switch (type->type) {
8029 case MONO_TYPE_I1:
8030 case MONO_TYPE_U1:
8031 case MONO_TYPE_BOOLEAN:
8032 return 1;
8033 case MONO_TYPE_I2:
8034 case MONO_TYPE_U2:
8035 case MONO_TYPE_CHAR:
8036 return 2;
8037 case MONO_TYPE_I4:
8038 case MONO_TYPE_U4:
8039 case MONO_TYPE_R4:
8040 return 4;
8041 case MONO_TYPE_I:
8042 case MONO_TYPE_U:
8043 case MONO_TYPE_PTR:
8044 case MONO_TYPE_CLASS:
8045 case MONO_TYPE_STRING:
8046 case MONO_TYPE_OBJECT:
8047 case MONO_TYPE_SZARRAY:
8048 case MONO_TYPE_ARRAY:
8049 case MONO_TYPE_VAR:
8050 case MONO_TYPE_MVAR:
8051 return sizeof (gpointer);
8052 case MONO_TYPE_I8:
8053 case MONO_TYPE_U8:
8054 case MONO_TYPE_R8:
8055 return 8;
8056 case MONO_TYPE_VALUETYPE:
8057 if (type->data.klass->enumtype) {
8058 type = mono_class_enum_basetype (type->data.klass);
8059 klass = klass->element_class;
8060 goto handle_enum;
8062 return mono_class_instance_size (klass) - sizeof (MonoObject);
8063 case MONO_TYPE_GENERICINST:
8064 type = &type->data.generic_class->container_class->byval_arg;
8065 goto handle_enum;
8067 case MONO_TYPE_VOID:
8068 return 0;
8070 default:
8071 g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
8073 return -1;
8077 * mono_array_element_size:
8078 * @ac: pointer to a #MonoArrayClass
8080 * Returns: the size of single array element.
8082 gint32
8083 mono_array_element_size (MonoClass *ac)
8085 g_assert (ac->rank);
8086 return ac->sizes.element_size;
8089 gpointer
8090 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
8091 MonoGenericContext *context)
8093 if (image->dynamic) {
8094 MonoClass *tmp_handle_class;
8095 gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context);
8097 g_assert (tmp_handle_class);
8098 if (handle_class)
8099 *handle_class = tmp_handle_class;
8101 if (tmp_handle_class == mono_defaults.typehandle_class)
8102 return &((MonoClass*)obj)->byval_arg;
8103 else
8104 return obj;
8107 switch (token & 0xff000000) {
8108 case MONO_TOKEN_TYPE_DEF:
8109 case MONO_TOKEN_TYPE_REF:
8110 case MONO_TOKEN_TYPE_SPEC: {
8111 MonoType *type;
8112 if (handle_class)
8113 *handle_class = mono_defaults.typehandle_class;
8114 type = mono_type_get_full (image, token, context);
8115 if (!type)
8116 return NULL;
8117 mono_class_init (mono_class_from_mono_type (type));
8118 /* We return a MonoType* as handle */
8119 return type;
8121 case MONO_TOKEN_FIELD_DEF: {
8122 MonoClass *class;
8123 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
8124 if (!type)
8125 return NULL;
8126 if (handle_class)
8127 *handle_class = mono_defaults.fieldhandle_class;
8128 class = mono_class_get_full (image, MONO_TOKEN_TYPE_DEF | type, context);
8129 if (!class)
8130 return NULL;
8131 mono_class_init (class);
8132 return mono_class_get_field (class, token);
8134 case MONO_TOKEN_METHOD_DEF:
8135 case MONO_TOKEN_METHOD_SPEC: {
8136 MonoMethod *meth;
8137 meth = mono_get_method_full (image, token, NULL, context);
8138 if (handle_class)
8139 *handle_class = mono_defaults.methodhandle_class;
8140 return meth;
8142 case MONO_TOKEN_MEMBER_REF: {
8143 guint32 cols [MONO_MEMBERREF_SIZE];
8144 const char *sig;
8145 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE);
8146 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
8147 mono_metadata_decode_blob_size (sig, &sig);
8148 if (*sig == 0x6) { /* it's a field */
8149 MonoClass *klass;
8150 MonoClassField *field;
8151 field = mono_field_from_token (image, token, &klass, context);
8152 if (handle_class)
8153 *handle_class = mono_defaults.fieldhandle_class;
8154 return field;
8155 } else {
8156 MonoMethod *meth;
8157 meth = mono_get_method_full (image, token, NULL, context);
8158 if (handle_class)
8159 *handle_class = mono_defaults.methodhandle_class;
8160 return meth;
8163 default:
8164 g_warning ("Unknown token 0x%08x in ldtoken", token);
8165 break;
8167 return NULL;
8171 * This function might need to call runtime functions so it can't be part
8172 * of the metadata library.
8174 static MonoLookupDynamicToken lookup_dynamic = NULL;
8176 void
8177 mono_install_lookup_dynamic_token (MonoLookupDynamicToken func)
8179 lookup_dynamic = func;
8182 gpointer
8183 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
8185 MonoClass *handle_class;
8187 return lookup_dynamic (image, token, TRUE, &handle_class, context);
8190 gpointer
8191 mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
8193 return lookup_dynamic (image, token, valid_token, handle_class, context);
8196 static MonoGetCachedClassInfo get_cached_class_info = NULL;
8198 void
8199 mono_install_get_cached_class_info (MonoGetCachedClassInfo func)
8201 get_cached_class_info = func;
8204 static gboolean
8205 mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
8207 if (!get_cached_class_info)
8208 return FALSE;
8209 else
8210 return get_cached_class_info (klass, res);
8213 void
8214 mono_install_get_class_from_name (MonoGetClassFromName func)
8216 get_class_from_name = func;
8219 MonoImage*
8220 mono_class_get_image (MonoClass *klass)
8222 return klass->image;
8226 * mono_class_get_element_class:
8227 * @klass: the MonoClass to act on
8229 * Returns: the element class of an array or an enumeration.
8231 MonoClass*
8232 mono_class_get_element_class (MonoClass *klass)
8234 return klass->element_class;
8238 * mono_class_is_valuetype:
8239 * @klass: the MonoClass to act on
8241 * Returns: true if the MonoClass represents a ValueType.
8243 gboolean
8244 mono_class_is_valuetype (MonoClass *klass)
8246 return klass->valuetype;
8250 * mono_class_is_enum:
8251 * @klass: the MonoClass to act on
8253 * Returns: true if the MonoClass represents an enumeration.
8255 gboolean
8256 mono_class_is_enum (MonoClass *klass)
8258 return klass->enumtype;
8262 * mono_class_enum_basetype:
8263 * @klass: the MonoClass to act on
8265 * Returns: the underlying type representation for an enumeration.
8267 MonoType*
8268 mono_class_enum_basetype (MonoClass *klass)
8270 if (klass->element_class == klass)
8271 /* SRE or broken types */
8272 return NULL;
8273 else
8274 return &klass->element_class->byval_arg;
8278 * mono_class_get_parent
8279 * @klass: the MonoClass to act on
8281 * Returns: the parent class for this class.
8283 MonoClass*
8284 mono_class_get_parent (MonoClass *klass)
8286 return klass->parent;
8290 * mono_class_get_nesting_type;
8291 * @klass: the MonoClass to act on
8293 * Returns: the container type where this type is nested or NULL if this type is not a nested type.
8295 MonoClass*
8296 mono_class_get_nesting_type (MonoClass *klass)
8298 return klass->nested_in;
8302 * mono_class_get_rank:
8303 * @klass: the MonoClass to act on
8305 * Returns: the rank for the array (the number of dimensions).
8308 mono_class_get_rank (MonoClass *klass)
8310 return klass->rank;
8314 * mono_class_get_flags:
8315 * @klass: the MonoClass to act on
8317 * The type flags from the TypeDef table from the metadata.
8318 * see the TYPE_ATTRIBUTE_* definitions on tabledefs.h for the
8319 * different values.
8321 * Returns: the flags from the TypeDef table.
8323 guint32
8324 mono_class_get_flags (MonoClass *klass)
8326 return klass->flags;
8330 * mono_class_get_name
8331 * @klass: the MonoClass to act on
8333 * Returns: the name of the class.
8335 const char*
8336 mono_class_get_name (MonoClass *klass)
8338 return klass->name;
8342 * mono_class_get_namespace:
8343 * @klass: the MonoClass to act on
8345 * Returns: the namespace of the class.
8347 const char*
8348 mono_class_get_namespace (MonoClass *klass)
8350 return klass->name_space;
8354 * mono_class_get_type:
8355 * @klass: the MonoClass to act on
8357 * This method returns the internal Type representation for the class.
8359 * Returns: the MonoType from the class.
8361 MonoType*
8362 mono_class_get_type (MonoClass *klass)
8364 return &klass->byval_arg;
8368 * mono_class_get_type_token
8369 * @klass: the MonoClass to act on
8371 * This method returns type token for the class.
8373 * Returns: the type token for the class.
8375 guint32
8376 mono_class_get_type_token (MonoClass *klass)
8378 return klass->type_token;
8382 * mono_class_get_byref_type:
8383 * @klass: the MonoClass to act on
8387 MonoType*
8388 mono_class_get_byref_type (MonoClass *klass)
8390 return &klass->this_arg;
8394 * mono_class_num_fields:
8395 * @klass: the MonoClass to act on
8397 * Returns: the number of static and instance fields in the class.
8400 mono_class_num_fields (MonoClass *klass)
8402 return klass->field.count;
8406 * mono_class_num_methods:
8407 * @klass: the MonoClass to act on
8409 * Returns: the number of methods in the class.
8412 mono_class_num_methods (MonoClass *klass)
8414 return klass->method.count;
8418 * mono_class_num_properties
8419 * @klass: the MonoClass to act on
8421 * Returns: the number of properties in the class.
8424 mono_class_num_properties (MonoClass *klass)
8426 mono_class_setup_properties (klass);
8428 return klass->ext->property.count;
8432 * mono_class_num_events:
8433 * @klass: the MonoClass to act on
8435 * Returns: the number of events in the class.
8438 mono_class_num_events (MonoClass *klass)
8440 mono_class_setup_events (klass);
8442 return klass->ext->event.count;
8446 * mono_class_get_fields:
8447 * @klass: the MonoClass to act on
8449 * This routine is an iterator routine for retrieving the fields in a class.
8451 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8452 * iterate over all of the elements. When no more values are
8453 * available, the return value is NULL.
8455 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
8457 MonoClassField*
8458 mono_class_get_fields (MonoClass* klass, gpointer *iter)
8460 MonoClassField* field;
8461 if (!iter)
8462 return NULL;
8463 if (!*iter) {
8464 mono_class_setup_fields_locking (klass);
8465 if (klass->exception_type)
8466 return NULL;
8467 /* start from the first */
8468 if (klass->field.count) {
8469 return *iter = &klass->fields [0];
8470 } else {
8471 /* no fields */
8472 return NULL;
8475 field = *iter;
8476 field++;
8477 if (field < &klass->fields [klass->field.count]) {
8478 return *iter = field;
8480 return NULL;
8484 * mono_class_get_methods
8485 * @klass: the MonoClass to act on
8487 * This routine is an iterator routine for retrieving the fields in a class.
8489 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8490 * iterate over all of the elements. When no more values are
8491 * available, the return value is NULL.
8493 * Returns: a MonoMethod on each iteration or NULL when no more methods are available.
8495 MonoMethod*
8496 mono_class_get_methods (MonoClass* klass, gpointer *iter)
8498 MonoMethod** method;
8499 if (!iter)
8500 return NULL;
8501 if (!*iter) {
8502 mono_class_setup_methods (klass);
8505 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
8506 * FIXME we should better report this error to the caller
8508 if (!klass->methods)
8509 return NULL;
8510 /* start from the first */
8511 if (klass->method.count) {
8512 *iter = &klass->methods [0];
8513 return klass->methods [0];
8514 } else {
8515 /* no method */
8516 return NULL;
8519 method = *iter;
8520 method++;
8521 if (method < &klass->methods [klass->method.count]) {
8522 *iter = method;
8523 return *method;
8525 return NULL;
8529 * mono_class_get_virtual_methods:
8531 * Iterate over the virtual methods of KLASS.
8533 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
8535 static MonoMethod*
8536 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
8538 MonoMethod** method;
8539 if (!iter)
8540 return NULL;
8541 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass) || mono_debug_using_mono_debugger ()) {
8542 if (!*iter) {
8543 mono_class_setup_methods (klass);
8545 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
8546 * FIXME we should better report this error to the caller
8548 if (!klass->methods)
8549 return NULL;
8550 /* start from the first */
8551 method = &klass->methods [0];
8552 } else {
8553 method = *iter;
8554 method++;
8556 while (method < &klass->methods [klass->method.count]) {
8557 if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
8558 break;
8559 method ++;
8561 if (method < &klass->methods [klass->method.count]) {
8562 *iter = method;
8563 return *method;
8564 } else {
8565 return NULL;
8567 } else {
8568 /* Search directly in metadata to avoid calling setup_methods () */
8569 MonoMethod *res = NULL;
8570 int i, start_index;
8572 if (!*iter) {
8573 start_index = 0;
8574 } else {
8575 start_index = GPOINTER_TO_UINT (*iter);
8578 for (i = start_index; i < klass->method.count; ++i) {
8579 guint32 flags;
8581 /* class->method.first points into the methodptr table */
8582 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
8584 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
8585 break;
8588 if (i < klass->method.count) {
8589 res = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass);
8590 /* Add 1 here so the if (*iter) check fails */
8591 *iter = GUINT_TO_POINTER (i + 1);
8592 return res;
8593 } else {
8594 return NULL;
8600 * mono_class_get_properties:
8601 * @klass: the MonoClass to act on
8603 * This routine is an iterator routine for retrieving the properties in a class.
8605 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8606 * iterate over all of the elements. When no more values are
8607 * available, the return value is NULL.
8609 * Returns: a @MonoProperty* on each invocation, or NULL when no more are available.
8611 MonoProperty*
8612 mono_class_get_properties (MonoClass* klass, gpointer *iter)
8614 MonoProperty* property;
8615 if (!iter)
8616 return NULL;
8617 if (!*iter) {
8618 mono_class_setup_properties (klass);
8619 /* start from the first */
8620 if (klass->ext->property.count) {
8621 return *iter = &klass->ext->properties [0];
8622 } else {
8623 /* no fields */
8624 return NULL;
8627 property = *iter;
8628 property++;
8629 if (property < &klass->ext->properties [klass->ext->property.count]) {
8630 return *iter = property;
8632 return NULL;
8636 * mono_class_get_events:
8637 * @klass: the MonoClass to act on
8639 * This routine is an iterator routine for retrieving the properties in a class.
8641 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8642 * iterate over all of the elements. When no more values are
8643 * available, the return value is NULL.
8645 * Returns: a @MonoEvent* on each invocation, or NULL when no more are available.
8647 MonoEvent*
8648 mono_class_get_events (MonoClass* klass, gpointer *iter)
8650 MonoEvent* event;
8651 if (!iter)
8652 return NULL;
8653 if (!*iter) {
8654 mono_class_setup_events (klass);
8655 /* start from the first */
8656 if (klass->ext->event.count) {
8657 return *iter = &klass->ext->events [0];
8658 } else {
8659 /* no fields */
8660 return NULL;
8663 event = *iter;
8664 event++;
8665 if (event < &klass->ext->events [klass->ext->event.count]) {
8666 return *iter = event;
8668 return NULL;
8672 * mono_class_get_interfaces
8673 * @klass: the MonoClass to act on
8675 * This routine is an iterator routine for retrieving the interfaces implemented by this class.
8677 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8678 * iterate over all of the elements. When no more values are
8679 * available, the return value is NULL.
8681 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
8683 MonoClass*
8684 mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
8686 MonoError error;
8687 MonoClass** iface;
8688 if (!iter)
8689 return NULL;
8690 if (!*iter) {
8691 if (!klass->inited)
8692 mono_class_init (klass);
8693 if (!klass->interfaces_inited) {
8694 mono_class_setup_interfaces (klass, &error);
8695 if (!mono_error_ok (&error)) {
8696 mono_error_cleanup (&error);
8697 return NULL;
8700 /* start from the first */
8701 if (klass->interface_count) {
8702 *iter = &klass->interfaces [0];
8703 return klass->interfaces [0];
8704 } else {
8705 /* no interface */
8706 return NULL;
8709 iface = *iter;
8710 iface++;
8711 if (iface < &klass->interfaces [klass->interface_count]) {
8712 *iter = iface;
8713 return *iface;
8715 return NULL;
8719 * mono_class_get_nested_types
8720 * @klass: the MonoClass to act on
8722 * This routine is an iterator routine for retrieving the nested types of a class.
8723 * This works only if @klass is non-generic, or a generic type definition.
8725 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8726 * iterate over all of the elements. When no more values are
8727 * available, the return value is NULL.
8729 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
8731 MonoClass*
8732 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
8734 GList *item;
8735 int i;
8737 if (!iter)
8738 return NULL;
8739 if (!klass->nested_classes_inited) {
8740 if (!klass->type_token)
8741 klass->nested_classes_inited = TRUE;
8742 mono_loader_lock ();
8743 if (!klass->nested_classes_inited) {
8744 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
8745 while (i) {
8746 MonoClass* nclass;
8747 guint32 cols [MONO_NESTED_CLASS_SIZE];
8748 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
8749 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]);
8750 if (!nclass) {
8751 mono_loader_clear_error ();
8752 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
8753 continue;
8755 mono_class_alloc_ext (klass);
8756 klass->ext->nested_classes = g_list_prepend_image (klass->image, klass->ext->nested_classes, nclass);
8758 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
8761 mono_memory_barrier ();
8762 klass->nested_classes_inited = TRUE;
8763 mono_loader_unlock ();
8766 if (!*iter) {
8767 /* start from the first */
8768 if (klass->ext && klass->ext->nested_classes) {
8769 *iter = klass->ext->nested_classes;
8770 return klass->ext->nested_classes->data;
8771 } else {
8772 /* no nested types */
8773 return NULL;
8776 item = *iter;
8777 item = item->next;
8778 if (item) {
8779 *iter = item;
8780 return item->data;
8782 return NULL;
8786 * mono_field_get_name:
8787 * @field: the MonoClassField to act on
8789 * Returns: the name of the field.
8791 const char*
8792 mono_field_get_name (MonoClassField *field)
8794 return field->name;
8798 * mono_field_get_type:
8799 * @field: the MonoClassField to act on
8801 * Returns: MonoType of the field.
8803 MonoType*
8804 mono_field_get_type (MonoClassField *field)
8806 MonoError error;
8807 MonoType *type = mono_field_get_type_checked (field, &error);
8808 if (!mono_error_ok (&error)) {
8809 mono_trace_warning (MONO_TRACE_TYPE, "Could not load field's type due to %s", mono_error_get_message (&error));
8810 mono_error_cleanup (&error);
8812 return type;
8817 * mono_field_get_type_checked:
8818 * @field: the MonoClassField to act on
8819 * @error: used to return any erro found while retrieving @field type
8821 * Returns: MonoType of the field.
8823 MonoType*
8824 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
8826 mono_error_init (error);
8827 if (!field->type)
8828 mono_field_resolve_type (field, error);
8829 return field->type;
8833 * mono_field_get_parent:
8834 * @field: the MonoClassField to act on
8836 * Returns: MonoClass where the field was defined.
8838 MonoClass*
8839 mono_field_get_parent (MonoClassField *field)
8841 return field->parent;
8845 * mono_field_get_flags;
8846 * @field: the MonoClassField to act on
8848 * The metadata flags for a field are encoded using the
8849 * FIELD_ATTRIBUTE_* constants. See the tabledefs.h file for details.
8851 * Returns: the flags for the field.
8853 guint32
8854 mono_field_get_flags (MonoClassField *field)
8856 if (!field->type)
8857 return mono_field_resolve_flags (field);
8858 return field->type->attrs;
8862 * mono_field_get_offset;
8863 * @field: the MonoClassField to act on
8865 * Returns: the field offset.
8867 guint32
8868 mono_field_get_offset (MonoClassField *field)
8870 return field->offset;
8873 static const char *
8874 mono_field_get_rva (MonoClassField *field)
8876 guint32 rva;
8877 int field_index;
8878 MonoClass *klass = field->parent;
8880 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
8882 if (!klass->ext || !klass->ext->field_def_values) {
8883 mono_loader_lock ();
8884 mono_class_alloc_ext (klass);
8885 if (!klass->ext->field_def_values)
8886 klass->ext->field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
8887 mono_loader_unlock ();
8890 field_index = mono_field_get_index (field);
8892 if (!klass->ext->field_def_values [field_index].data && !klass->image->dynamic) {
8893 mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL);
8894 if (!rva)
8895 g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
8896 klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
8899 return klass->ext->field_def_values [field_index].data;
8903 * mono_field_get_data;
8904 * @field: the MonoClassField to act on
8906 * Returns: pointer to the metadata constant value or to the field
8907 * data if it has an RVA flag.
8909 const char *
8910 mono_field_get_data (MonoClassField *field)
8912 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
8913 MonoTypeEnum def_type;
8915 return mono_class_get_field_default_value (field, &def_type);
8916 } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
8917 return mono_field_get_rva (field);
8918 } else {
8919 return NULL;
8924 * mono_property_get_name:
8925 * @prop: the MonoProperty to act on
8927 * Returns: the name of the property
8929 const char*
8930 mono_property_get_name (MonoProperty *prop)
8932 return prop->name;
8936 * mono_property_get_set_method
8937 * @prop: the MonoProperty to act on.
8939 * Returns: the setter method of the property (A MonoMethod)
8941 MonoMethod*
8942 mono_property_get_set_method (MonoProperty *prop)
8944 return prop->set;
8948 * mono_property_get_get_method
8949 * @prop: the MonoProperty to act on.
8951 * Returns: the setter method of the property (A MonoMethod)
8953 MonoMethod*
8954 mono_property_get_get_method (MonoProperty *prop)
8956 return prop->get;
8960 * mono_property_get_parent:
8961 * @prop: the MonoProperty to act on.
8963 * Returns: the MonoClass where the property was defined.
8965 MonoClass*
8966 mono_property_get_parent (MonoProperty *prop)
8968 return prop->parent;
8972 * mono_property_get_flags:
8973 * @prop: the MonoProperty to act on.
8975 * The metadata flags for a property are encoded using the
8976 * PROPERTY_ATTRIBUTE_* constants. See the tabledefs.h file for details.
8978 * Returns: the flags for the property.
8980 guint32
8981 mono_property_get_flags (MonoProperty *prop)
8983 return prop->attrs;
8987 * mono_event_get_name:
8988 * @event: the MonoEvent to act on
8990 * Returns: the name of the event.
8992 const char*
8993 mono_event_get_name (MonoEvent *event)
8995 return event->name;
8999 * mono_event_get_add_method:
9000 * @event: The MonoEvent to act on.
9002 * Returns: the @add' method for the event (a MonoMethod).
9004 MonoMethod*
9005 mono_event_get_add_method (MonoEvent *event)
9007 return event->add;
9011 * mono_event_get_remove_method:
9012 * @event: The MonoEvent to act on.
9014 * Returns: the @remove method for the event (a MonoMethod).
9016 MonoMethod*
9017 mono_event_get_remove_method (MonoEvent *event)
9019 return event->remove;
9023 * mono_event_get_raise_method:
9024 * @event: The MonoEvent to act on.
9026 * Returns: the @raise method for the event (a MonoMethod).
9028 MonoMethod*
9029 mono_event_get_raise_method (MonoEvent *event)
9031 return event->raise;
9035 * mono_event_get_parent:
9036 * @event: the MonoEvent to act on.
9038 * Returns: the MonoClass where the event is defined.
9040 MonoClass*
9041 mono_event_get_parent (MonoEvent *event)
9043 return event->parent;
9047 * mono_event_get_flags
9048 * @event: the MonoEvent to act on.
9050 * The metadata flags for an event are encoded using the
9051 * EVENT_* constants. See the tabledefs.h file for details.
9053 * Returns: the flags for the event.
9055 guint32
9056 mono_event_get_flags (MonoEvent *event)
9058 return event->attrs;
9062 * mono_class_get_method_from_name:
9063 * @klass: where to look for the method
9064 * @name_space: name of the method
9065 * @param_count: number of parameters. -1 for any number.
9067 * Obtains a MonoMethod with a given name and number of parameters.
9068 * It only works if there are no multiple signatures for any given method name.
9070 MonoMethod *
9071 mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_count)
9073 return mono_class_get_method_from_name_flags (klass, name, param_count, 0);
9076 static MonoMethod*
9077 find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
9079 MonoMethod *res = NULL;
9080 int i;
9082 /* Search directly in the metadata to avoid calling setup_methods () */
9083 for (i = 0; i < klass->method.count; ++i) {
9084 guint32 cols [MONO_METHOD_SIZE];
9085 MonoMethod *method;
9086 MonoMethodSignature *sig;
9088 /* class->method.first points into the methodptr table */
9089 mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE);
9091 if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
9092 method = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass);
9093 if (param_count == -1) {
9094 res = method;
9095 break;
9097 sig = mono_method_signature (method);
9098 if (sig && sig->param_count == param_count) {
9099 res = method;
9100 break;
9105 return res;
9109 * mono_class_get_method_from_name_flags:
9110 * @klass: where to look for the method
9111 * @name_space: name of the method
9112 * @param_count: number of parameters. -1 for any number.
9113 * @flags: flags which must be set in the method
9115 * Obtains a MonoMethod with a given name and number of parameters.
9116 * It only works if there are no multiple signatures for any given method name.
9118 MonoMethod *
9119 mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int param_count, int flags)
9121 MonoMethod *res = NULL;
9122 int i;
9124 mono_class_init (klass);
9126 if (klass->generic_class && !klass->methods) {
9127 res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags);
9128 if (res)
9129 res = mono_class_inflate_generic_method_full (res, klass, mono_class_get_context (klass));
9130 return res;
9133 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
9134 mono_class_setup_methods (klass);
9136 We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9137 See mono/tests/array_load_exception.il
9138 FIXME we should better report this error to the caller
9140 if (!klass->methods)
9141 return NULL;
9142 for (i = 0; i < klass->method.count; ++i) {
9143 MonoMethod *method = klass->methods [i];
9145 if (method->name[0] == name [0] &&
9146 !strcmp (name, method->name) &&
9147 (param_count == -1 || mono_method_signature (method)->param_count == param_count) &&
9148 ((method->flags & flags) == flags)) {
9149 res = method;
9150 break;
9154 else {
9155 res = find_method_in_metadata (klass, name, param_count, flags);
9158 return res;
9162 * mono_class_set_failure:
9163 * @klass: class in which the failure was detected
9164 * @ex_type: the kind of exception/error to be thrown (later)
9165 * @ex_data: exception data (specific to each type of exception/error)
9167 * Keep a detected failure informations in the class for later processing.
9168 * Note that only the first failure is kept.
9170 * LOCKING: Acquires the loader lock.
9172 gboolean
9173 mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
9175 if (klass->exception_type)
9176 return FALSE;
9178 mono_loader_lock ();
9179 klass->exception_type = ex_type;
9180 if (ex_data)
9181 mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
9182 mono_loader_unlock ();
9184 return TRUE;
9188 * mono_class_get_exception_data:
9190 * Return the exception_data property of KLASS.
9192 * LOCKING: Acquires the loader lock.
9194 gpointer
9195 mono_class_get_exception_data (MonoClass *klass)
9197 return mono_image_property_lookup (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA);
9201 * mono_classes_init:
9203 * Initialize the resources used by this module.
9205 void
9206 mono_classes_init (void)
9208 mono_counters_register ("Inflated methods size",
9209 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
9210 mono_counters_register ("Inflated classes",
9211 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes);
9212 mono_counters_register ("Inflated classes size",
9213 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
9214 mono_counters_register ("MonoClass size",
9215 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
9216 mono_counters_register ("MonoClassExt size",
9217 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size);
9221 * mono_classes_cleanup:
9223 * Free the resources used by this module.
9225 void
9226 mono_classes_cleanup (void)
9228 if (global_interface_bitset)
9229 mono_bitset_free (global_interface_bitset);
9230 global_interface_bitset = NULL;
9234 * mono_class_get_exception_for_failure:
9235 * @klass: class in which the failure was detected
9237 * Return a constructed MonoException than the caller can then throw
9238 * using mono_raise_exception - or NULL if no failure is present (or
9239 * doesn't result in an exception).
9241 MonoException*
9242 mono_class_get_exception_for_failure (MonoClass *klass)
9244 gpointer exception_data = mono_class_get_exception_data (klass);
9246 switch (klass->exception_type) {
9247 #ifndef DISABLE_SECURITY
9248 case MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND: {
9249 MonoDomain *domain = mono_domain_get ();
9250 MonoSecurityManager* secman = mono_security_manager_get_methods ();
9251 MonoMethod *method = exception_data;
9252 guint32 error = (method) ? MONO_METADATA_INHERITANCEDEMAND_METHOD : MONO_METADATA_INHERITANCEDEMAND_CLASS;
9253 MonoObject *exc = NULL;
9254 gpointer args [4];
9256 args [0] = &error;
9257 args [1] = mono_assembly_get_object (domain, mono_image_get_assembly (klass->image));
9258 args [2] = mono_type_get_object (domain, &klass->byval_arg);
9259 args [3] = (method) ? mono_method_get_object (domain, method, NULL) : NULL;
9261 mono_runtime_invoke (secman->inheritsecurityexception, NULL, args, &exc);
9262 return (MonoException*) exc;
9264 #endif
9265 case MONO_EXCEPTION_TYPE_LOAD: {
9266 MonoString *name;
9267 MonoException *ex;
9268 char *str = mono_type_get_full_name (klass);
9269 char *astr = klass->image->assembly? mono_stringify_assembly_name (&klass->image->assembly->aname): NULL;
9270 name = mono_string_new (mono_domain_get (), str);
9271 g_free (str);
9272 ex = mono_get_exception_type_load (name, astr);
9273 g_free (astr);
9274 return ex;
9276 case MONO_EXCEPTION_MISSING_METHOD: {
9277 char *class_name = exception_data;
9278 char *assembly_name = class_name + strlen (class_name) + 1;
9280 return mono_get_exception_missing_method (class_name, assembly_name);
9282 case MONO_EXCEPTION_MISSING_FIELD: {
9283 char *class_name = exception_data;
9284 char *member_name = class_name + strlen (class_name) + 1;
9286 return mono_get_exception_missing_field (class_name, member_name);
9288 case MONO_EXCEPTION_FILE_NOT_FOUND: {
9289 char *msg_format = exception_data;
9290 char *assembly_name = msg_format + strlen (msg_format) + 1;
9291 char *msg = g_strdup_printf (msg_format, assembly_name);
9292 MonoException *ex;
9294 ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), assembly_name));
9296 g_free (msg);
9298 return ex;
9300 case MONO_EXCEPTION_BAD_IMAGE: {
9301 return mono_get_exception_bad_image_format (exception_data);
9303 default: {
9304 MonoLoaderError *error;
9305 MonoException *ex;
9307 error = mono_loader_get_last_error ();
9308 if (error != NULL){
9309 ex = mono_loader_error_prepare_exception (error);
9310 return ex;
9313 /* TODO - handle other class related failures */
9314 return NULL;
9319 static gboolean
9320 is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
9322 outer_klass = mono_class_get_generic_type_definition (outer_klass);
9323 inner_klass = mono_class_get_generic_type_definition (inner_klass);
9324 do {
9325 if (outer_klass == inner_klass)
9326 return TRUE;
9327 inner_klass = inner_klass->nested_in;
9328 } while (inner_klass);
9329 return FALSE;
9332 MonoClass *
9333 mono_class_get_generic_type_definition (MonoClass *klass)
9335 return klass->generic_class ? klass->generic_class->container_class : klass;
9339 * Check if @klass is a subtype of @parent ignoring generic instantiations.
9341 * Generic instantiations are ignored for all super types of @klass.
9343 * Visibility checks ignoring generic instantiations.
9345 gboolean
9346 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
9348 int i;
9349 klass = mono_class_get_generic_type_definition (klass);
9350 parent = mono_class_get_generic_type_definition (parent);
9351 mono_class_setup_supertypes (klass);
9353 for (i = 0; i < klass->idepth; ++i) {
9354 if (parent == mono_class_get_generic_type_definition (klass->supertypes [i]))
9355 return TRUE;
9357 return FALSE;
9360 * Subtype can only access parent members with family protection if the site object
9361 * is subclass of Subtype. For example:
9362 * class A { protected int x; }
9363 * class B : A {
9364 * void valid_access () {
9365 * B b;
9366 * b.x = 0;
9368 * void invalid_access () {
9369 * A a;
9370 * a.x = 0;
9373 * */
9374 static gboolean
9375 is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
9377 if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
9378 return FALSE;
9380 if (context_klass == NULL)
9381 return TRUE;
9382 /*if access_klass is not member_klass context_klass must be type compat*/
9383 if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
9384 return FALSE;
9385 return TRUE;
9388 static gboolean
9389 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
9391 GSList *tmp;
9392 if (accessing == accessed)
9393 return TRUE;
9394 if (!accessed || !accessing)
9395 return FALSE;
9397 /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
9398 * anywhere so untrusted friends are not safe to access platform's code internals */
9399 if (mono_security_core_clr_enabled ()) {
9400 if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
9401 return FALSE;
9404 mono_assembly_load_friends (accessed);
9405 for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
9406 MonoAssemblyName *friend = tmp->data;
9407 /* Be conservative with checks */
9408 if (!friend->name)
9409 continue;
9410 if (strcmp (accessing->aname.name, friend->name))
9411 continue;
9412 if (friend->public_key_token [0]) {
9413 if (!accessing->aname.public_key_token [0])
9414 continue;
9415 if (!mono_public_tokens_are_equal (friend->public_key_token, accessing->aname.public_key_token))
9416 continue;
9418 return TRUE;
9420 return FALSE;
9424 * If klass is a generic type or if it is derived from a generic type, return the
9425 * MonoClass of the generic definition
9426 * Returns NULL if not found
9428 static MonoClass*
9429 get_generic_definition_class (MonoClass *klass)
9431 while (klass) {
9432 if (klass->generic_class && klass->generic_class->container_class)
9433 return klass->generic_class->container_class;
9434 klass = klass->parent;
9436 return NULL;
9439 static gboolean
9440 can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
9442 int i;
9443 for (i = 0; i < ginst->type_argc; ++i) {
9444 MonoType *type = ginst->type_argv[i];
9445 switch (type->type) {
9446 case MONO_TYPE_SZARRAY:
9447 if (!can_access_type (access_klass, type->data.klass))
9448 return FALSE;
9449 break;
9450 case MONO_TYPE_ARRAY:
9451 if (!can_access_type (access_klass, type->data.array->eklass))
9452 return FALSE;
9453 break;
9454 case MONO_TYPE_PTR:
9455 if (!can_access_type (access_klass, mono_class_from_mono_type (type->data.type)))
9456 return FALSE;
9457 break;
9458 case MONO_TYPE_CLASS:
9459 case MONO_TYPE_VALUETYPE:
9460 case MONO_TYPE_GENERICINST:
9461 if (!can_access_type (access_klass, mono_class_from_mono_type (type)))
9462 return FALSE;
9465 return TRUE;
9468 static gboolean
9469 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
9471 int access_level;
9473 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
9474 return TRUE;
9476 if (access_klass->element_class && !access_klass->enumtype)
9477 access_klass = access_klass->element_class;
9479 if (member_klass->element_class && !member_klass->enumtype)
9480 member_klass = member_klass->element_class;
9482 access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
9484 if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
9485 return TRUE;
9487 if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst))
9488 return FALSE;
9490 if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
9491 return TRUE;
9493 if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
9494 return FALSE;
9496 /*Non nested type with nested visibility. We just fail it.*/
9497 if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL)
9498 return FALSE;
9500 switch (access_level) {
9501 case TYPE_ATTRIBUTE_NOT_PUBLIC:
9502 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
9504 case TYPE_ATTRIBUTE_PUBLIC:
9505 return TRUE;
9507 case TYPE_ATTRIBUTE_NESTED_PUBLIC:
9508 return TRUE;
9510 case TYPE_ATTRIBUTE_NESTED_PRIVATE:
9511 return is_nesting_type (member_klass, access_klass);
9513 case TYPE_ATTRIBUTE_NESTED_FAMILY:
9514 return mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
9516 case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
9517 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
9519 case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
9520 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) &&
9521 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
9523 case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
9524 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) ||
9525 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
9527 return FALSE;
9530 /* FIXME: check visibility of type, too */
9531 static gboolean
9532 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
9534 MonoClass *member_generic_def;
9535 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
9536 return TRUE;
9538 if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
9539 access_klass->generic_container) &&
9540 (member_generic_def = get_generic_definition_class (member_klass))) {
9541 MonoClass *access_container;
9543 if (access_klass->generic_container)
9544 access_container = access_klass;
9545 else
9546 access_container = access_klass->generic_class->container_class;
9548 if (can_access_member (access_container, member_generic_def, context_klass, access_level))
9549 return TRUE;
9552 /* Partition I 8.5.3.2 */
9553 /* the access level values are the same for fields and methods */
9554 switch (access_level) {
9555 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
9556 /* same compilation unit */
9557 return access_klass->image == member_klass->image;
9558 case FIELD_ATTRIBUTE_PRIVATE:
9559 return access_klass == member_klass;
9560 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
9561 if (is_valid_family_access (access_klass, member_klass, context_klass) &&
9562 can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
9563 return TRUE;
9564 return FALSE;
9565 case FIELD_ATTRIBUTE_ASSEMBLY:
9566 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
9567 case FIELD_ATTRIBUTE_FAMILY:
9568 if (is_valid_family_access (access_klass, member_klass, context_klass))
9569 return TRUE;
9570 return FALSE;
9571 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
9572 if (is_valid_family_access (access_klass, member_klass, context_klass))
9573 return TRUE;
9574 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
9575 case FIELD_ATTRIBUTE_PUBLIC:
9576 return TRUE;
9578 return FALSE;
9581 gboolean
9582 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
9584 /* FIXME: check all overlapping fields */
9585 int can = can_access_member (method->klass, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
9586 if (!can) {
9587 MonoClass *nested = method->klass->nested_in;
9588 while (nested) {
9589 can = can_access_member (nested, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
9590 if (can)
9591 return TRUE;
9592 nested = nested->nested_in;
9595 return can;
9598 gboolean
9599 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
9601 int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
9602 if (!can) {
9603 MonoClass *nested = method->klass->nested_in;
9604 while (nested) {
9605 can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
9606 if (can)
9607 return TRUE;
9608 nested = nested->nested_in;
9612 * FIXME:
9613 * with generics calls to explicit interface implementations can be expressed
9614 * directly: the method is private, but we must allow it. This may be opening
9615 * a hole or the generics code should handle this differently.
9616 * Maybe just ensure the interface type is public.
9618 if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
9619 return TRUE;
9620 return can;
9624 * mono_method_can_access_method_full:
9625 * @method: The caller method
9626 * @called: The called method
9627 * @context_klass: The static type on stack of the owner @called object used
9629 * This function must be used with instance calls, as they have more strict family accessibility.
9630 * It can be used with static methods, but context_klass should be NULL.
9632 * Returns: TRUE if caller have proper visibility and acessibility to @called
9634 gboolean
9635 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
9637 MonoClass *access_class = method->klass;
9638 MonoClass *member_class = called->klass;
9639 int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
9640 if (!can) {
9641 MonoClass *nested = access_class->nested_in;
9642 while (nested) {
9643 can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
9644 if (can)
9645 break;
9646 nested = nested->nested_in;
9650 if (!can)
9651 return FALSE;
9653 can = can_access_type (access_class, member_class);
9654 if (!can) {
9655 MonoClass *nested = access_class->nested_in;
9656 while (nested) {
9657 can = can_access_type (nested, member_class);
9658 if (can)
9659 break;
9660 nested = nested->nested_in;
9664 if (!can)
9665 return FALSE;
9667 if (called->is_inflated) {
9668 MonoMethodInflated * infl = (MonoMethodInflated*)called;
9669 if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
9670 return FALSE;
9673 return TRUE;
9678 * mono_method_can_access_field_full:
9679 * @method: The caller method
9680 * @field: The accessed field
9681 * @context_klass: The static type on stack of the owner @field object used
9683 * This function must be used with instance fields, as they have more strict family accessibility.
9684 * It can be used with static fields, but context_klass should be NULL.
9686 * Returns: TRUE if caller have proper visibility and acessibility to @field
9688 gboolean
9689 mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
9691 MonoClass *access_class = method->klass;
9692 MonoClass *member_class = field->parent;
9693 /* FIXME: check all overlapping fields */
9694 int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
9695 if (!can) {
9696 MonoClass *nested = access_class->nested_in;
9697 while (nested) {
9698 can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
9699 if (can)
9700 break;
9701 nested = nested->nested_in;
9705 if (!can)
9706 return FALSE;
9708 can = can_access_type (access_class, member_class);
9709 if (!can) {
9710 MonoClass *nested = access_class->nested_in;
9711 while (nested) {
9712 can = can_access_type (nested, member_class);
9713 if (can)
9714 break;
9715 nested = nested->nested_in;
9719 if (!can)
9720 return FALSE;
9721 return TRUE;
9725 * mono_class_can_access_class:
9726 * @source_class: The source class
9727 * @target_class: The accessed class
9729 * This function returns is @target_class is visible to @source_class
9731 * Returns: TRUE if source have proper visibility and acessibility to target
9733 gboolean
9734 mono_class_can_access_class (MonoClass *source_class, MonoClass *target_class)
9736 return can_access_type (source_class, target_class);
9740 * mono_type_is_valid_enum_basetype:
9741 * @type: The MonoType to check
9743 * Returns: TRUE if the type can be used as the basetype of an enum
9745 gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
9746 switch (type->type) {
9747 case MONO_TYPE_I1:
9748 case MONO_TYPE_U1:
9749 case MONO_TYPE_BOOLEAN:
9750 case MONO_TYPE_I2:
9751 case MONO_TYPE_U2:
9752 case MONO_TYPE_CHAR:
9753 case MONO_TYPE_I4:
9754 case MONO_TYPE_U4:
9755 case MONO_TYPE_I8:
9756 case MONO_TYPE_U8:
9757 case MONO_TYPE_I:
9758 case MONO_TYPE_U:
9759 return TRUE;
9761 return FALSE;
9765 * mono_class_is_valid_enum:
9766 * @klass: An enum class to be validated
9768 * This method verify the required properties an enum should have.
9770 * Returns: TRUE if the informed enum class is valid
9772 * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
9773 * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
9774 * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
9776 gboolean mono_class_is_valid_enum (MonoClass *klass) {
9777 MonoClassField * field;
9778 gpointer iter = NULL;
9779 gboolean found_base_field = FALSE;
9781 g_assert (klass->enumtype);
9782 /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
9783 if (!klass->parent || strcmp (klass->parent->name, "Enum") || strcmp (klass->parent->name_space, "System") ) {
9784 return FALSE;
9787 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)
9788 return FALSE;
9790 while ((field = mono_class_get_fields (klass, &iter))) {
9791 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
9792 if (found_base_field)
9793 return FALSE;
9794 found_base_field = TRUE;
9795 if (!mono_type_is_valid_enum_basetype (field->type))
9796 return FALSE;
9800 if (!found_base_field)
9801 return FALSE;
9803 if (klass->method.count > 0)
9804 return FALSE;
9806 return TRUE;
9809 gboolean
9810 mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
9812 return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
9816 * mono_class_setup_interface_id:
9818 * Initializes MonoClass::interface_id if required.
9820 * LOCKING: Acquires the loader lock.
9822 void
9823 mono_class_setup_interface_id (MonoClass *class)
9825 mono_loader_lock ();
9826 if (MONO_CLASS_IS_INTERFACE (class) && !class->interface_id)
9827 class->interface_id = mono_get_unique_iid (class);
9828 mono_loader_unlock ();
9832 * mono_class_alloc_ext:
9834 * Allocate klass->ext if not already done.
9835 * LOCKING: Assumes the loader lock is held.
9837 void
9838 mono_class_alloc_ext (MonoClass *klass)
9840 if (!klass->ext) {
9841 klass->ext = mono_class_alloc0 (klass, sizeof (MonoClassExt));
9842 class_ext_size += sizeof (MonoClassExt);
9847 * mono_class_setup_interfaces:
9849 * Initialize class->interfaces/interfaces_count.
9850 * LOCKING: Acquires the loader lock.
9851 * This function can fail the type.
9853 void
9854 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
9856 int i;
9858 mono_error_init (error);
9860 if (klass->interfaces_inited)
9861 return;
9863 mono_loader_lock ();
9865 if (klass->interfaces_inited) {
9866 mono_loader_unlock ();
9867 return;
9870 if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY) {
9871 MonoType *args [1];
9873 /* generic IList, ICollection, IEnumerable */
9874 klass->interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
9875 klass->interfaces = mono_image_alloc0 (klass->image, sizeof (MonoClass*) * klass->interface_count);
9877 args [0] = &klass->element_class->byval_arg;
9878 klass->interfaces [0] = mono_class_bind_generic_parameters (
9879 mono_defaults.generic_ilist_class, 1, args, FALSE);
9880 if (klass->interface_count > 1)
9881 klass->interfaces [1] = mono_class_bind_generic_parameters (
9882 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
9883 } else if (klass->generic_class) {
9884 MonoClass *gklass = klass->generic_class->container_class;
9886 klass->interface_count = gklass->interface_count;
9887 klass->interfaces = mono_class_new0 (klass, MonoClass *, klass->interface_count);
9888 for (i = 0; i < klass->interface_count; i++) {
9889 klass->interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error);
9890 if (!mono_error_ok (error)) {
9891 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
9892 klass->interfaces = NULL;
9893 return;
9898 mono_memory_barrier ();
9900 klass->interfaces_inited = TRUE;
9902 mono_loader_unlock ();
9905 static void
9906 mono_field_resolve_type (MonoClassField *field, MonoError *error)
9908 MonoClass *class = field->parent;
9909 MonoImage *image = class->image;
9910 MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
9911 int field_idx = field - class->fields;
9913 mono_error_init (error);
9915 if (gtd) {
9916 MonoClassField *gfield = &gtd->fields [field_idx];
9917 MonoType *gtype = mono_field_get_type_checked (gfield, error);
9918 if (!mono_error_ok (error)) {
9919 char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
9920 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
9921 g_free (err_msg);
9924 field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (class), error);
9925 if (!mono_error_ok (error)) {
9926 char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
9927 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
9928 g_free (err_msg);
9930 } else {
9931 const char *sig;
9932 guint32 cols [MONO_FIELD_SIZE];
9933 MonoGenericContainer *container = NULL;
9934 int idx = class->field.first + field_idx;
9936 /*FIXME, in theory we do not lazy load SRE fields*/
9937 g_assert (!image->dynamic);
9939 if (class->generic_container) {
9940 container = class->generic_container;
9941 } else if (gtd) {
9942 container = gtd->generic_container;
9943 g_assert (container);
9946 /* class->field.first and idx points into the fieldptr table */
9947 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
9949 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) {
9950 mono_error_set_type_load_class (error, class, "Could not verify field %s signature", field->name);
9951 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
9952 return;
9955 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
9957 mono_metadata_decode_value (sig, &sig);
9958 /* FIELD signature == 0x06 */
9959 g_assert (*sig == 0x06);
9960 field->type = mono_metadata_parse_type_full (image, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
9961 if (!field->type) {
9962 MonoLoaderError *lerror = mono_loader_get_last_error ();
9964 mono_error_set_type_load_class (error, class, "Could not load field %s type", field->name);
9965 if (lerror)
9966 set_failure_from_loader_error (class, lerror);
9967 else
9968 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
9969 mono_loader_clear_error ();
9974 static guint32
9975 mono_field_resolve_flags (MonoClassField *field)
9977 MonoClass *class = field->parent;
9978 MonoImage *image = class->image;
9979 MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL;
9980 int field_idx = field - class->fields;
9983 if (gtd) {
9984 MonoClassField *gfield = &gtd->fields [field_idx];
9985 return mono_field_get_flags (gfield);
9986 } else {
9987 int idx = class->field.first + field_idx;
9989 /*FIXME, in theory we do not lazy load SRE fields*/
9990 g_assert (!image->dynamic);
9992 return mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_FLAGS);
9997 * mono_class_setup_basic_field_info:
9998 * @class: The class to initialize
10000 * Initializes the class->fields array of fields.
10001 * Aquires the loader lock.
10003 static void
10004 mono_class_setup_basic_field_info_locking (MonoClass *class)
10006 mono_loader_lock ();
10007 mono_class_setup_basic_field_info (class);
10008 mono_loader_unlock ();
10012 * mono_class_get_fields_lazy:
10013 * @klass: the MonoClass to act on
10015 * This routine is an iterator routine for retrieving the fields in a class.
10016 * Only minimal information about fields are loaded. Accessors must be used
10017 * for all MonoClassField returned.
10019 * You must pass a gpointer that points to zero and is treated as an opaque handle to
10020 * iterate over all of the elements. When no more values are
10021 * available, the return value is NULL.
10023 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
10025 MonoClassField*
10026 mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
10028 MonoClassField* field;
10029 if (!iter)
10030 return NULL;
10031 if (!*iter) {
10032 mono_class_setup_basic_field_info_locking (klass);
10033 if (!klass->fields)
10034 return NULL;
10035 /* start from the first */
10036 if (klass->field.count) {
10037 return *iter = &klass->fields [0];
10038 } else {
10039 /* no fields */
10040 return NULL;
10043 field = *iter;
10044 field++;
10045 if (field < &klass->fields [klass->field.count]) {
10046 return *iter = field;
10048 return NULL;
10051 char*
10052 mono_class_full_name (MonoClass *klass)
10054 return mono_type_full_name (&klass->byval_arg);