1 /**
2 * \file
3 * Class management for the Mono runtime
4 *
5 * Author:
6 * Miguel de Icaza (miguel@ximian.com)
7 *
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12 */
13 #include <config.h>
14 #ifdef HAVE_ALLOCA_H
15 #include <alloca.h>
16 #endif
17 #include <glib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <mono/metadata/image.h>
22 #include <mono/metadata/image-internals.h>
23 #include <mono/metadata/assembly.h>
24 #include <mono/metadata/assembly-internals.h>
25 #include <mono/metadata/metadata.h>
26 #include <mono/metadata/metadata-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/tabledefs.h>
29 #include <mono/metadata/tokentype.h>
30 #include <mono/metadata/class-internals.h>
31 #include <mono/metadata/object.h>
32 #include <mono/metadata/appdomain.h>
33 #include <mono/metadata/mono-endian.h>
34 #include <mono/metadata/debug-helpers.h>
35 #include <mono/metadata/reflection.h>
36 #include <mono/metadata/exception.h>
37 #include <mono/metadata/security-manager.h>
38 #include <mono/metadata/security-core-clr.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/gc-internals.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/metadata/mono-debug.h>
43 #include <mono/metadata/custom-attrs-internals.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-string.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/mono-logger-internals.h>
48 #include <mono/utils/mono-memory-model.h>
49 #include <mono/utils/atomic.h>
50 #include <mono/utils/unlocked.h>
51 #include <mono/utils/bsearch.h>
52 #include <mono/utils/checked-build.h>
53
54 MonoStats mono_stats;
55
56 gboolean mono_print_vtable = FALSE;
57 gboolean mono_align_small_structs = FALSE;
58
59 /* Statistics */
60 gint32 inflated_classes_size, inflated_methods_size;
61 gint32 classes_size;
62 gint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
63
64 /* Low level lock which protects data structures in this module */
65 static mono_mutex_t classes_mutex;
66
67 /* Function supplied by the runtime to find classes by name using information from the AOT file */
68 static MonoGetClassFromName get_class_from_name = NULL;
69
70 static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error);
71 static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res);
72 static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
73 static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
74 static int generic_array_methods (MonoClass *klass);
75 static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache);
76
77 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
78 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
79 static void mono_field_resolve_type (MonoClassField *field, MonoError *error);
80 static guint32 mono_field_resolve_flags (MonoClassField *field);
81 static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
82 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
83
84 static gboolean mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error);
85
86 static gboolean class_kind_may_contain_generic_instances (MonoTypeKind kind);
87
88
89 /*
90 We use gclass recording to allow recursive system f types to be referenced by a parent.
91
92 Given the following type hierarchy:
93
94 class TextBox : TextBoxBase<TextBox> {}
95 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
96 class TextInput<T> : Input<T> where T: TextInput<T> {}
97 class Input<T> {}
98
99 The runtime tries to load TextBoxBase<>.
100 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
101 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
102 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
103
104 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
105 at this point, iow, both are registered in the type map and both and a NULL parent. This means
106 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
107
108 To fix that what we do is to record all generic instantes created while resolving the parent of
109 any generic type definition and, after resolved, correct the parent field if needed.
110
111 */
112 static int record_gclass_instantiation;
113 static GSList *gclass_recorded_list;
114 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
115
116 /* This TLS variable points to a GSList of classes which have setup_fields () executing */
117 static MonoNativeTlsKey setup_fields_tls_id;
118
119 static MonoNativeTlsKey init_pending_tls_id;
120
121 static inline void
classes_lock(void)122 classes_lock (void)
123 {
124 mono_locks_os_acquire (&classes_mutex, ClassesLock);
125 }
126
127 static inline void
classes_unlock(void)128 classes_unlock (void)
129 {
130 mono_locks_os_release (&classes_mutex, ClassesLock);
131 }
132
133 /*
134 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
135 */
136 static void
enable_gclass_recording(void)137 enable_gclass_recording (void)
138 {
139 ++record_gclass_instantiation;
140 }
141
142 /*
143 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
144 */
145 static void
disable_gclass_recording(gclass_record_func func,void * user_data)146 disable_gclass_recording (gclass_record_func func, void *user_data)
147 {
148 GSList **head = &gclass_recorded_list;
149
150 g_assert (record_gclass_instantiation > 0);
151 --record_gclass_instantiation;
152
153 while (*head) {
154 GSList *node = *head;
155 if (func ((MonoClass*)node->data, user_data)) {
156 *head = node->next;
157 g_slist_free_1 (node);
158 } else {
159 head = &node->next;
160 }
161 }
162
163 /* We automatically discard all recorded gclasses when disabled. */
164 if (!record_gclass_instantiation && gclass_recorded_list) {
165 g_slist_free (gclass_recorded_list);
166 gclass_recorded_list = NULL;
167 }
168 }
169
170 /**
171 * mono_class_from_typeref:
172 * \param image a MonoImage
173 * \param type_token a TypeRef token
174 *
175 * Creates the \c MonoClass* structure representing the type defined by
176 * the typeref token valid inside \p image.
177 * \returns The \c MonoClass* representing the typeref token, or NULL if it could
178 * not be loaded.
179 */
180 MonoClass *
mono_class_from_typeref(MonoImage * image,guint32 type_token)181 mono_class_from_typeref (MonoImage *image, guint32 type_token)
182 {
183 MonoError error;
184 MonoClass *klass = mono_class_from_typeref_checked (image, type_token, &error);
185 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
186 return klass;
187 }
188
189 /**
190 * mono_class_from_typeref_checked:
191 * \param image a MonoImage
192 * \param type_token a TypeRef token
193 * \param error error return code, if any.
194 *
195 * Creates the \c MonoClass* structure representing the type defined by
196 * the typeref token valid inside \p image.
197 *
198 * \returns The \c MonoClass* representing the typeref token, NULL if it could
199 * not be loaded with the \p error value filled with the information about the
200 * error.
201 */
202 MonoClass *
mono_class_from_typeref_checked(MonoImage * image,guint32 type_token,MonoError * error)203 mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
204 {
205 guint32 cols [MONO_TYPEREF_SIZE];
206 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
207 guint32 idx;
208 const char *name, *nspace;
209 MonoClass *res = NULL;
210 MonoImage *module;
211
212 error_init (error);
213
214 if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
215 return NULL;
216
217 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
218
219 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
220 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
221
222 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
223 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
224 case MONO_RESOLUTION_SCOPE_MODULE:
225 /*
226 LAMESPEC The spec says that a null module resolution scope should go through the exported type table.
227 This is not the observed behavior of existing implementations.
228 The defacto behavior is that it's just a typedef in disguise.
229 */
230 /* a typedef in disguise */
231 res = mono_class_from_name_checked (image, nspace, name, error);
232 goto done;
233
234 case MONO_RESOLUTION_SCOPE_MODULEREF:
235 module = mono_image_load_module_checked (image, idx, error);
236 if (module)
237 res = mono_class_from_name_checked (module, nspace, name, error);
238 goto done;
239
240 case MONO_RESOLUTION_SCOPE_TYPEREF: {
241 MonoClass *enclosing;
242 GList *tmp;
243
244 if (idx == mono_metadata_token_index (type_token)) {
245 mono_error_set_bad_image (error, image, "Image with self-referencing typeref token %08x.", type_token);
246 return NULL;
247 }
248
249 enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
250 return_val_if_nok (error, NULL);
251
252 GList *nested_classes = mono_class_get_nested_classes_property (enclosing);
253 if (enclosing->nested_classes_inited && nested_classes) {
254 /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
255 for (tmp = nested_classes; tmp; tmp = tmp->next) {
256 res = (MonoClass *)tmp->data;
257 if (strcmp (res->name, name) == 0)
258 return res;
259 }
260 } else {
261 /* Don't call mono_class_init as we might've been called by it recursively */
262 int i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, 1);
263 while (i) {
264 guint32 class_nested = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, MONO_NESTED_CLASS_NESTED);
265 guint32 string_offset = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
266 const char *nname = mono_metadata_string_heap (enclosing->image, string_offset);
267
268 if (strcmp (nname, name) == 0)
269 return mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, error);
270
271 i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1);
272 }
273 }
274 g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
275 goto done;
276 }
277 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
278 break;
279 }
280
281 if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
282 mono_error_set_bad_image (error, image, "Image with invalid assemblyref token %08x.", idx);
283 return NULL;
284 }
285
286 if (!image->references || !image->references [idx - 1])
287 mono_assembly_load_reference (image, idx - 1);
288 g_assert (image->references [idx - 1]);
289
290 /* If the assembly did not load, register this as a type load exception */
291 if (image->references [idx - 1] == REFERENCE_MISSING){
292 MonoAssemblyName aname;
293 char *human_name;
294
295 mono_assembly_get_assemblyref (image, idx - 1, &aname);
296 human_name = mono_stringify_assembly_name (&aname);
297 mono_error_set_assembly_load_simple (error, human_name, image->assembly ? image->assembly->ref_only : FALSE);
298 return NULL;
299 }
300
301 res = mono_class_from_name_checked (image->references [idx - 1]->image, nspace, name, error);
302
303 done:
304 /* Generic case, should be avoided for when a better error is possible. */
305 if (!res && mono_error_ok (error)) {
306 char *name = mono_class_name_from_token (image, type_token);
307 char *assembly = mono_assembly_name_from_token (image, type_token);
308 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x (from typeref, class/assembly %s, %s)", type_token, name, assembly);
309 }
310 return res;
311 }
312
313
314 static void *
mono_image_memdup(MonoImage * image,void * data,guint size)315 mono_image_memdup (MonoImage *image, void *data, guint size)
316 {
317 void *res = mono_image_alloc (image, size);
318 memcpy (res, data, size);
319 return res;
320 }
321
322 /* Copy everything mono_metadata_free_array free. */
323 MonoArrayType *
mono_dup_array_type(MonoImage * image,MonoArrayType * a)324 mono_dup_array_type (MonoImage *image, MonoArrayType *a)
325 {
326 if (image) {
327 a = (MonoArrayType *)mono_image_memdup (image, a, sizeof (MonoArrayType));
328 if (a->sizes)
329 a->sizes = (int *)mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
330 if (a->lobounds)
331 a->lobounds = (int *)mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
332 } else {
333 a = (MonoArrayType *)g_memdup (a, sizeof (MonoArrayType));
334 if (a->sizes)
335 a->sizes = (int *)g_memdup (a->sizes, a->numsizes * sizeof (int));
336 if (a->lobounds)
337 a->lobounds = (int *)g_memdup (a->lobounds, a->numlobounds * sizeof (int));
338 }
339 return a;
340 }
341
342 /* Copy everything mono_metadata_free_method_signature free. */
343 MonoMethodSignature*
mono_metadata_signature_deep_dup(MonoImage * image,MonoMethodSignature * sig)344 mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
345 {
346 int i;
347
348 sig = mono_metadata_signature_dup_full (image, sig);
349
350 sig->ret = mono_metadata_type_dup (image, sig->ret);
351 for (i = 0; i < sig->param_count; ++i)
352 sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
353
354 return sig;
355 }
356
357 static void
_mono_type_get_assembly_name(MonoClass * klass,GString * str)358 _mono_type_get_assembly_name (MonoClass *klass, GString *str)
359 {
360 MonoAssembly *ta = klass->image->assembly;
361 char *name;
362
363 name = mono_stringify_assembly_name (&ta->aname);
364 g_string_append_printf (str, ", %s", name);
365 g_free (name);
366 }
367
368 static inline void
mono_type_name_check_byref(MonoType * type,GString * str)369 mono_type_name_check_byref (MonoType *type, GString *str)
370 {
371 if (type->byref)
372 g_string_append_c (str, '&');
373 }
374
375 /**
376 * mono_identifier_escape_type_name_chars:
377 * \param str a destination string
378 * \param identifier an IDENTIFIER in internal form
379 *
380 * \returns \p str
381 *
382 * The displayed form of the identifier is appended to str.
383 *
384 * The displayed form of an identifier has the characters ,+&*[]\
385 * that have special meaning in type names escaped with a preceeding
386 * backslash (\) character.
387 */
388 static GString*
mono_identifier_escape_type_name_chars(GString * str,const char * identifier)389 mono_identifier_escape_type_name_chars (GString* str, const char* identifier)
390 {
391 if (!identifier)
392 return str;
393
394 size_t n = str->len;
395 // reserve space for common case: there will be no escaped characters.
396 g_string_set_size(str, n + strlen(identifier));
397 g_string_set_size(str, n);
398
399 for (const char* s = identifier; *s != 0 ; s++) {
400 switch (*s) {
401 case ',':
402 case '+':
403 case '&':
404 case '*':
405 case '[':
406 case ']':
407 case '\\':
408 g_string_append_c (str, '\\');
409 g_string_append_c (str, *s);
410 break;
411 default:
412 g_string_append_c (str, *s);
413 break;
414 }
415 }
416 return str;
417 }
418
419 static void
mono_type_get_name_recurse(MonoType * type,GString * str,gboolean is_recursed,MonoTypeNameFormat format)420 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
421 MonoTypeNameFormat format)
422 {
423 MonoClass *klass;
424
425 switch (type->type) {
426 case MONO_TYPE_ARRAY: {
427 int i, rank = type->data.array->rank;
428 MonoTypeNameFormat nested_format;
429
430 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
431 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
432
433 mono_type_get_name_recurse (
434 &type->data.array->eklass->byval_arg, str, FALSE, nested_format);
435 g_string_append_c (str, '[');
436 if (rank == 1)
437 g_string_append_c (str, '*');
438 for (i = 1; i < rank; i++)
439 g_string_append_c (str, ',');
440 g_string_append_c (str, ']');
441
442 mono_type_name_check_byref (type, str);
443
444 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
445 _mono_type_get_assembly_name (type->data.array->eklass, str);
446 break;
447 }
448 case MONO_TYPE_SZARRAY: {
449 MonoTypeNameFormat nested_format;
450
451 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
452 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
453
454 mono_type_get_name_recurse (
455 &type->data.klass->byval_arg, str, FALSE, nested_format);
456 g_string_append (str, "[]");
457
458 mono_type_name_check_byref (type, str);
459
460 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
461 _mono_type_get_assembly_name (type->data.klass, str);
462 break;
463 }
464 case MONO_TYPE_PTR: {
465 MonoTypeNameFormat nested_format;
466
467 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
468 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
469
470 mono_type_get_name_recurse (
471 type->data.type, str, FALSE, nested_format);
472 g_string_append_c (str, '*');
473
474 mono_type_name_check_byref (type, str);
475
476 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
477 _mono_type_get_assembly_name (mono_class_from_mono_type (type->data.type), str);
478 break;
479 }
480 case MONO_TYPE_VAR:
481 case MONO_TYPE_MVAR:
482 if (!mono_generic_param_info (type->data.generic_param))
483 g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
484 else
485 g_string_append (str, mono_generic_param_info (type->data.generic_param)->name);
486
487 mono_type_name_check_byref (type, str);
488
489 break;
490 default:
491 klass = mono_class_from_mono_type (type);
492 if (klass->nested_in) {
493 mono_type_get_name_recurse (
494 &klass->nested_in->byval_arg, str, TRUE, format);
495 if (format == MONO_TYPE_NAME_FORMAT_IL)
496 g_string_append_c (str, '.');
497 else
498 g_string_append_c (str, '+');
499 } else if (*klass->name_space) {
500 if (format == MONO_TYPE_NAME_FORMAT_IL)
501 g_string_append (str, klass->name_space);
502 else
503 mono_identifier_escape_type_name_chars (str, klass->name_space);
504 g_string_append_c (str, '.');
505 }
506 if (format == MONO_TYPE_NAME_FORMAT_IL) {
507 char *s = strchr (klass->name, '`');
508 int len = s ? s - klass->name : strlen (klass->name);
509 g_string_append_len (str, klass->name, len);
510 } else {
511 mono_identifier_escape_type_name_chars (str, klass->name);
512 }
513 if (is_recursed)
514 break;
515 if (mono_class_is_ginst (klass)) {
516 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
517 MonoGenericInst *inst = gclass->context.class_inst;
518 MonoTypeNameFormat nested_format;
519 int i;
520
521 nested_format = format == MONO_TYPE_NAME_FORMAT_FULL_NAME ?
522 MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format;
523
524 if (format == MONO_TYPE_NAME_FORMAT_IL)
525 g_string_append_c (str, '<');
526 else
527 g_string_append_c (str, '[');
528 for (i = 0; i < inst->type_argc; i++) {
529 MonoType *t = inst->type_argv [i];
530
531 if (i)
532 g_string_append_c (str, ',');
533 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
534 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
535 g_string_append_c (str, '[');
536 mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
537 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
538 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
539 g_string_append_c (str, ']');
540 }
541 if (format == MONO_TYPE_NAME_FORMAT_IL)
542 g_string_append_c (str, '>');
543 else
544 g_string_append_c (str, ']');
545 } else if (mono_class_is_gtd (klass) &&
546 (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
547 (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
548 int i;
549
550 if (format == MONO_TYPE_NAME_FORMAT_IL)
551 g_string_append_c (str, '<');
552 else
553 g_string_append_c (str, '[');
554 for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) {
555 if (i)
556 g_string_append_c (str, ',');
557 g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name);
558 }
559 if (format == MONO_TYPE_NAME_FORMAT_IL)
560 g_string_append_c (str, '>');
561 else
562 g_string_append_c (str, ']');
563 }
564
565 mono_type_name_check_byref (type, str);
566
567 if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
568 (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
569 _mono_type_get_assembly_name (klass, str);
570 break;
571 }
572 }
573
574 /**
575 * mono_type_get_name_full:
576 * \param type a type
577 * \param format the format for the return string.
578 *
579 *
580 * \returns The string representation in a number of formats:
581 *
582 * if \p format is \c MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
583 * returned in the format required by \c System.Reflection, this is the
584 * inverse of mono_reflection_parse_type().
585 *
586 * if \p format is \c MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
587 * be used by the IL assembler.
588 *
589 * if \p format is \c MONO_TYPE_NAME_FORMAT_FULL_NAME
590 *
591 * if \p format is \c MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
592 */
593 char*
mono_type_get_name_full(MonoType * type,MonoTypeNameFormat format)594 mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
595 {
596 GString* result;
597
598 result = g_string_new ("");
599
600 mono_type_get_name_recurse (type, result, FALSE, format);
601
602 return g_string_free (result, FALSE);
603 }
604
605 /**
606 * mono_type_get_full_name:
607 * \param class a class
608 *
609 * \returns The string representation for type as required by System.Reflection.
610 * The inverse of mono_reflection_parse_type().
611 */
612 char *
mono_type_get_full_name(MonoClass * klass)613 mono_type_get_full_name (MonoClass *klass)
614 {
615 return mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_REFLECTION);
616 }
617
618 /**
619 * mono_type_get_name:
620 * \param type a type
621 * \returns The string representation for type as it would be represented in IL code.
622 */
623 char*
mono_type_get_name(MonoType * type)624 mono_type_get_name (MonoType *type)
625 {
626 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
627 }
628
629 /**
630 * mono_type_get_underlying_type:
631 * \param type a type
632 * \returns The \c MonoType for the underlying integer type if \p type
633 * is an enum and byref is false, otherwise the type itself.
634 */
635 MonoType*
mono_type_get_underlying_type(MonoType * type)636 mono_type_get_underlying_type (MonoType *type)
637 {
638 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype && !type->byref)
639 return mono_class_enum_basetype (type->data.klass);
640 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype && !type->byref)
641 return mono_class_enum_basetype (type->data.generic_class->container_class);
642 return type;
643 }
644
645 /**
646 * mono_class_is_open_constructed_type:
647 * \param type a type
648 *
649 * \returns TRUE if type represents a generics open constructed type.
650 * IOW, not all type parameters required for the instantiation have
651 * been provided or it's a generic type definition.
652 *
653 * An open constructed type means it's a non realizable type. Not to
654 * be mixed up with an abstract type - we can't cast or dispatch to
655 * an open type, for example.
656 */
657 gboolean
mono_class_is_open_constructed_type(MonoType * t)658 mono_class_is_open_constructed_type (MonoType *t)
659 {
660 switch (t->type) {
661 case MONO_TYPE_VAR:
662 case MONO_TYPE_MVAR:
663 return TRUE;
664 case MONO_TYPE_SZARRAY:
665 return mono_class_is_open_constructed_type (&t->data.klass->byval_arg);
666 case MONO_TYPE_ARRAY:
667 return mono_class_is_open_constructed_type (&t->data.array->eklass->byval_arg);
668 case MONO_TYPE_PTR:
669 return mono_class_is_open_constructed_type (t->data.type);
670 case MONO_TYPE_GENERICINST:
671 return t->data.generic_class->context.class_inst->is_open;
672 case MONO_TYPE_CLASS:
673 case MONO_TYPE_VALUETYPE:
674 return mono_class_is_gtd (t->data.klass);
675 default:
676 return FALSE;
677 }
678 }
679
680 /*
681 This is a simple function to catch the most common bad instances of generic types.
682 Specially those that might lead to further failures in the runtime.
683 */
684 static gboolean
is_valid_generic_argument(MonoType * type)685 is_valid_generic_argument (MonoType *type)
686 {
687 switch (type->type) {
688 case MONO_TYPE_VOID:
689 //case MONO_TYPE_TYPEDBYREF:
690 return FALSE;
691 default:
692 return TRUE;
693 }
694 }
695
696 static MonoType*
inflate_generic_type(MonoImage * image,MonoType * type,MonoGenericContext * context,MonoError * error)697 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
698 {
699 error_init (error);
700
701 switch (type->type) {
702 case MONO_TYPE_MVAR: {
703 MonoType *nt;
704 int num = mono_type_get_generic_param_num (type);
705 MonoGenericInst *inst = context->method_inst;
706 if (!inst)
707 return NULL;
708 if (num >= inst->type_argc) {
709 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
710 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
711 num, info ? info->name : "", inst->type_argc);
712 return NULL;
713 }
714
715 if (!is_valid_generic_argument (inst->type_argv [num])) {
716 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
717 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
718 num, info ? info->name : "", inst->type_argv [num]->type);
719 return NULL;
720 }
721 /*
722 * Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
723 * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
724 * ->byref and ->attrs from @type are propagated to the returned type.
725 */
726 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
727 nt->byref = type->byref;
728 nt->attrs = type->attrs;
729 return nt;
730 }
731 case MONO_TYPE_VAR: {
732 MonoType *nt;
733 int num = mono_type_get_generic_param_num (type);
734 MonoGenericInst *inst = context->class_inst;
735 if (!inst)
736 return NULL;
737 if (num >= inst->type_argc) {
738 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
739 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
740 num, info ? info->name : "", inst->type_argc);
741 return NULL;
742 }
743 if (!is_valid_generic_argument (inst->type_argv [num])) {
744 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
745 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
746 num, info ? info->name : "", inst->type_argv [num]->type);
747 return NULL;
748 }
749 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
750 nt->byref = type->byref;
751 nt->attrs = type->attrs;
752 return nt;
753 }
754 case MONO_TYPE_SZARRAY: {
755 MonoClass *eclass = type->data.klass;
756 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
757 if (!inflated || !mono_error_ok (error))
758 return NULL;
759 nt = mono_metadata_type_dup (image, type);
760 nt->data.klass = mono_class_from_mono_type (inflated);
761 mono_metadata_free_type (inflated);
762 return nt;
763 }
764 case MONO_TYPE_ARRAY: {
765 MonoClass *eclass = type->data.array->eklass;
766 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
767 if (!inflated || !mono_error_ok (error))
768 return NULL;
769 nt = mono_metadata_type_dup (image, type);
770 nt->data.array->eklass = mono_class_from_mono_type (inflated);
771 mono_metadata_free_type (inflated);
772 return nt;
773 }
774 case MONO_TYPE_GENERICINST: {
775 MonoGenericClass *gclass = type->data.generic_class;
776 MonoGenericInst *inst;
777 MonoType *nt;
778 if (!gclass->context.class_inst->is_open)
779 return NULL;
780
781 inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
782 return_val_if_nok (error, NULL);
783
784 if (inst != gclass->context.class_inst)
785 gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
786
787 if (gclass == type->data.generic_class)
788 return NULL;
789
790 nt = mono_metadata_type_dup (image, type);
791 nt->data.generic_class = gclass;
792 return nt;
793 }
794 case MONO_TYPE_CLASS:
795 case MONO_TYPE_VALUETYPE: {
796 MonoClass *klass = type->data.klass;
797 MonoGenericContainer *container = mono_class_try_get_generic_container (klass);
798 MonoGenericInst *inst;
799 MonoGenericClass *gclass = NULL;
800 MonoType *nt;
801
802 if (!container)
803 return NULL;
804
805 /* We can't use context->class_inst directly, since it can have more elements */
806 inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
807 return_val_if_nok (error, NULL);
808
809 if (inst == container->context.class_inst)
810 return NULL;
811
812 gclass = mono_metadata_lookup_generic_class (klass, inst, image_is_dynamic (klass->image));
813
814 nt = mono_metadata_type_dup (image, type);
815 nt->type = MONO_TYPE_GENERICINST;
816 nt->data.generic_class = gclass;
817 return nt;
818 }
819 default:
820 return NULL;
821 }
822 return NULL;
823 }
824
825 MonoGenericContext *
mono_generic_class_get_context(MonoGenericClass * gclass)826 mono_generic_class_get_context (MonoGenericClass *gclass)
827 {
828 return &gclass->context;
829 }
830
831 MonoGenericContext *
mono_class_get_context(MonoClass * klass)832 mono_class_get_context (MonoClass *klass)
833 {
834 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
835 return gklass ? mono_generic_class_get_context (gklass) : NULL;
836 }
837
838 /*
839 * mono_class_inflate_generic_type_with_mempool:
840 * @mempool: a mempool
841 * @type: a type
842 * @context: a generics context
843 * @error: error context
844 *
845 * The same as mono_class_inflate_generic_type, but allocates the MonoType
846 * from mempool if it is non-NULL. If it is NULL, the MonoType is
847 * allocated on the heap and is owned by the caller.
848 * The returned type can potentially be the same as TYPE, so it should not be
849 * modified by the caller, and it should be freed using mono_metadata_free_type ().
850 */
851 MonoType*
mono_class_inflate_generic_type_with_mempool(MonoImage * image,MonoType * type,MonoGenericContext * context,MonoError * error)852 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
853 {
854 MonoType *inflated = NULL;
855 error_init (error);
856
857 if (context)
858 inflated = inflate_generic_type (image, type, context, error);
859 return_val_if_nok (error, NULL);
860
861 if (!inflated) {
862 MonoType *shared = mono_metadata_get_shared_type (type);
863
864 if (shared) {
865 return shared;
866 } else {
867 return mono_metadata_type_dup (image, type);
868 }
869 }
870
871 UnlockedIncrement (&mono_stats.inflated_type_count);
872 return inflated;
873 }
874
875 /**
876 * mono_class_inflate_generic_type:
877 * \param type a type
878 * \param context a generics context
879 * \deprecated Please use \c mono_class_inflate_generic_type_checked instead
880 *
881 * If \p type is a generic type and \p context is not NULL, instantiate it using the
882 * generics context \p context.
883 *
884 * \returns The instantiated type or a copy of \p type. The returned \c MonoType is allocated
885 * on the heap and is owned by the caller. Returns NULL on error.
886 */
887 MonoType*
mono_class_inflate_generic_type(MonoType * type,MonoGenericContext * context)888 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
889 {
890 MonoError error;
891 MonoType *result;
892 result = mono_class_inflate_generic_type_checked (type, context, &error);
893 mono_error_cleanup (&error);
894 return result;
895 }
896
897 /*
898 * mono_class_inflate_generic_type:
899 * @type: a type
900 * @context: a generics context
901 * @error: error context to use
902 *
903 * If @type is a generic type and @context is not NULL, instantiate it using the
904 * generics context @context.
905 *
906 * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
907 * on the heap and is owned by the caller.
908 */
909 MonoType*
mono_class_inflate_generic_type_checked(MonoType * type,MonoGenericContext * context,MonoError * error)910 mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
911 {
912 return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
913 }
914
915 /*
916 * mono_class_inflate_generic_type_no_copy:
917 *
918 * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
919 * was done.
920 */
921 static MonoType*
mono_class_inflate_generic_type_no_copy(MonoImage * image,MonoType * type,MonoGenericContext * context,MonoError * error)922 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
923 {
924 MonoType *inflated = NULL;
925
926 error_init (error);
927 if (context) {
928 inflated = inflate_generic_type (image, type, context, error);
929 return_val_if_nok (error, NULL);
930 }
931
932 if (!inflated)
933 return type;
934
935 UnlockedIncrement (&mono_stats.inflated_type_count);
936 return inflated;
937 }
938
939 /*
940 * mono_class_inflate_generic_class:
941 *
942 * Inflate the class @gklass with @context. Set @error on failure.
943 */
944 MonoClass*
mono_class_inflate_generic_class_checked(MonoClass * gklass,MonoGenericContext * context,MonoError * error)945 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
946 {
947 MonoClass *res;
948 MonoType *inflated;
949
950 inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, error);
951 return_val_if_nok (error, NULL);
952
953 res = mono_class_from_mono_type (inflated);
954 mono_metadata_free_type (inflated);
955
956 return res;
957 }
958
959 static MonoGenericContext
inflate_generic_context(MonoGenericContext * context,MonoGenericContext * inflate_with,MonoError * error)960 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
961 {
962 MonoGenericInst *class_inst = NULL;
963 MonoGenericInst *method_inst = NULL;
964 MonoGenericContext res = { NULL, NULL };
965
966 error_init (error);
967
968 if (context->class_inst) {
969 class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
970 if (!mono_error_ok (error))
971 goto fail;
972 }
973
974 if (context->method_inst) {
975 method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with, error);
976 if (!mono_error_ok (error))
977 goto fail;
978 }
979
980 res.class_inst = class_inst;
981 res.method_inst = method_inst;
982 fail:
983 return res;
984 }
985
986 /**
987 * mono_class_inflate_generic_method:
988 * \param method a generic method
989 * \param context a generics context
990 *
991 * Instantiate the generic method \p method using the generics context \p context.
992 *
993 * \returns The new instantiated method
994 */
995 MonoMethod *
mono_class_inflate_generic_method(MonoMethod * method,MonoGenericContext * context)996 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
997 {
998 return mono_class_inflate_generic_method_full (method, NULL, context);
999 }
1000
1001 MonoMethod *
mono_class_inflate_generic_method_checked(MonoMethod * method,MonoGenericContext * context,MonoError * error)1002 mono_class_inflate_generic_method_checked (MonoMethod *method, MonoGenericContext *context, MonoError *error)
1003 {
1004 return mono_class_inflate_generic_method_full_checked (method, NULL, context, error);
1005 }
1006
1007 /**
1008 * mono_class_inflate_generic_method_full:
1009 *
1010 * Instantiate method \p method with the generic context \p context.
1011 * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
1012 * Use mono_method_signature() and mono_method_get_header() to get the correct values.
1013 */
1014 MonoMethod*
mono_class_inflate_generic_method_full(MonoMethod * method,MonoClass * klass_hint,MonoGenericContext * context)1015 mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context)
1016 {
1017 MonoError error;
1018 MonoMethod *res = mono_class_inflate_generic_method_full_checked (method, klass_hint, context, &error);
1019 if (!mono_error_ok (&error))
1020 /*FIXME do proper error handling - on this case, kill this function. */
1021 g_error ("Could not inflate generic method due to %s", mono_error_get_message (&error));
1022
1023 return res;
1024 }
1025
1026 /**
1027 * mono_class_inflate_generic_method_full_checked:
1028 * Same as mono_class_inflate_generic_method_full but return failure using \p error.
1029 */
1030 MonoMethod*
mono_class_inflate_generic_method_full_checked(MonoMethod * method,MonoClass * klass_hint,MonoGenericContext * context,MonoError * error)1031 mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error)
1032 {
1033 MonoMethod *result;
1034 MonoMethodInflated *iresult, *cached;
1035 MonoMethodSignature *sig;
1036 MonoGenericContext tmp_context;
1037
1038 error_init (error);
1039
1040 /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
1041 while (method->is_inflated) {
1042 MonoGenericContext *method_context = mono_method_get_context (method);
1043 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1044
1045 tmp_context = inflate_generic_context (method_context, context, error);
1046 return_val_if_nok (error, NULL);
1047
1048 context = &tmp_context;
1049
1050 if (mono_metadata_generic_context_equal (method_context, context))
1051 return method;
1052
1053 method = imethod->declaring;
1054 }
1055
1056 /*
1057 * A method only needs to be inflated if the context has argument for which it is
1058 * parametric. Eg:
1059 *
1060 * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
1061 * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
1062 *
1063 */
1064 if (!((method->is_generic && context->method_inst) ||
1065 (mono_class_is_gtd (method->klass) && context->class_inst)))
1066 return method;
1067
1068 iresult = g_new0 (MonoMethodInflated, 1);
1069 iresult->context = *context;
1070 iresult->declaring = method;
1071
1072 if (!context->method_inst && method->is_generic)
1073 iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
1074
1075 if (!context->class_inst) {
1076 g_assert (!mono_class_is_ginst (iresult->declaring->klass));
1077 if (mono_class_is_gtd (iresult->declaring->klass))
1078 iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst;
1079 }
1080 /* This can happen with some callers like mono_object_get_virtual_method () */
1081 if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass))
1082 iresult->context.class_inst = NULL;
1083
1084 MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
1085
1086 // check cache
1087 mono_image_set_lock (set);
1088 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1089 mono_image_set_unlock (set);
1090
1091 if (cached) {
1092 g_free (iresult);
1093 return (MonoMethod*)cached;
1094 }
1095
1096 UnlockedIncrement (&mono_stats.inflated_method_count);
1097
1098 UnlockedAdd (&inflated_methods_size, sizeof (MonoMethodInflated));
1099
1100 sig = mono_method_signature (method);
1101 if (!sig) {
1102 char *name = mono_type_get_full_name (method->klass);
1103 mono_error_set_bad_image (error, method->klass->image, "Could not resolve signature of method %s:%s", name, method->name);
1104 g_free (name);
1105 goto fail;
1106 }
1107
1108 if (sig->pinvoke) {
1109 memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
1110 } else {
1111 memcpy (&iresult->method.method, method, sizeof (MonoMethod));
1112 }
1113
1114 result = (MonoMethod *) iresult;
1115 result->is_inflated = TRUE;
1116 result->is_generic = FALSE;
1117 result->sre_method = FALSE;
1118 result->signature = NULL;
1119
1120 if (method->wrapper_type) {
1121 MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
1122 MonoMethodWrapper *resw = (MonoMethodWrapper*)result;
1123 int len = GPOINTER_TO_INT (((void**)mw->method_data) [0]);
1124
1125 resw->method_data = (void **)g_malloc (sizeof (gpointer) * (len + 1));
1126 memcpy (resw->method_data, mw->method_data, sizeof (gpointer) * (len + 1));
1127 }
1128
1129 if (iresult->context.method_inst) {
1130 /* Set the generic_container of the result to the generic_container of method */
1131 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
1132
1133 if (generic_container && iresult->context.method_inst == generic_container->context.method_inst) {
1134 result->is_generic = 1;
1135 mono_method_set_generic_container (result, generic_container);
1136 }
1137 }
1138
1139 if (klass_hint) {
1140 MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint);
1141 if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst))
1142 klass_hint = NULL;
1143 }
1144
1145 if (mono_class_is_gtd (method->klass))
1146 result->klass = klass_hint;
1147
1148 if (!result->klass) {
1149 MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context, error);
1150 if (!mono_error_ok (error))
1151 goto fail;
1152
1153 result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
1154 if (inflated)
1155 mono_metadata_free_type (inflated);
1156 }
1157
1158 /*
1159 * FIXME: This should hold, but it doesn't:
1160 *
1161 * if (result->is_inflated && mono_method_get_context (result)->method_inst &&
1162 * mono_method_get_context (result)->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)result)->declaring)->context.method_inst) {
1163 * g_assert (result->is_generic);
1164 * }
1165 *
1166 * Fixing this here causes other things to break, hence a very
1167 * ugly hack in mini-trampolines.c - see
1168 * is_generic_method_definition().
1169 */
1170
1171 // check cache
1172 mono_image_set_lock (set);
1173 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1174 if (!cached) {
1175 g_hash_table_insert (set->gmethod_cache, iresult, iresult);
1176 iresult->owner = set;
1177 cached = iresult;
1178 }
1179 mono_image_set_unlock (set);
1180
1181 return (MonoMethod*)cached;
1182
1183 fail:
1184 g_free (iresult);
1185 return NULL;
1186 }
1187
1188 /**
1189 * mono_get_inflated_method:
1190 *
1191 * Obsolete. We keep it around since it's mentioned in the public API.
1192 */
1193 MonoMethod*
mono_get_inflated_method(MonoMethod * method)1194 mono_get_inflated_method (MonoMethod *method)
1195 {
1196 return method;
1197 }
1198
1199 /*
1200 * mono_method_get_context_general:
1201 * @method: a method
1202 * @uninflated: handle uninflated methods?
1203 *
1204 * Returns the generic context of a method or NULL if it doesn't have
1205 * one. For an inflated method that's the context stored in the
1206 * method. Otherwise it's in the method's generic container or in the
1207 * generic container of the method's class.
1208 */
1209 MonoGenericContext*
mono_method_get_context_general(MonoMethod * method,gboolean uninflated)1210 mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
1211 {
1212 if (method->is_inflated) {
1213 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1214 return &imethod->context;
1215 }
1216 if (!uninflated)
1217 return NULL;
1218 if (method->is_generic)
1219 return &(mono_method_get_generic_container (method)->context);
1220 if (mono_class_is_gtd (method->klass))
1221 return &mono_class_get_generic_container (method->klass)->context;
1222 return NULL;
1223 }
1224
1225 /*
1226 * mono_method_get_context:
1227 * @method: a method
1228 *
1229 * Returns the generic context for method if it's inflated, otherwise
1230 * NULL.
1231 */
1232 MonoGenericContext*
mono_method_get_context(MonoMethod * method)1233 mono_method_get_context (MonoMethod *method)
1234 {
1235 return mono_method_get_context_general (method, FALSE);
1236 }
1237
1238 /*
1239 * mono_method_get_generic_container:
1240 *
1241 * Returns the generic container of METHOD, which should be a generic method definition.
1242 * Returns NULL if METHOD is not a generic method definition.
1243 * LOCKING: Acquires the loader lock.
1244 */
1245 MonoGenericContainer*
mono_method_get_generic_container(MonoMethod * method)1246 mono_method_get_generic_container (MonoMethod *method)
1247 {
1248 MonoGenericContainer *container;
1249
1250 if (!method->is_generic)
1251 return NULL;
1252
1253 container = (MonoGenericContainer *)mono_image_property_lookup (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER);
1254 g_assert (container);
1255
1256 return container;
1257 }
1258
1259 /*
1260 * mono_method_set_generic_container:
1261 *
1262 * Sets the generic container of METHOD to CONTAINER.
1263 * LOCKING: Acquires the image lock.
1264 */
1265 void
mono_method_set_generic_container(MonoMethod * method,MonoGenericContainer * container)1266 mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
1267 {
1268 g_assert (method->is_generic);
1269
1270 mono_image_property_insert (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
1271 }
1272
1273 /**
1274 * mono_class_find_enum_basetype:
1275 * \param class The enum class
1276 *
1277 * Determine the basetype of an enum by iterating through its fields. We do this
1278 * in a separate function since it is cheaper than calling mono_class_setup_fields.
1279 */
1280 static MonoType*
mono_class_find_enum_basetype(MonoClass * klass,MonoError * error)1281 mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
1282 {
1283 MonoGenericContainer *container = NULL;
1284 MonoImage *m = klass->image;
1285 const int top = mono_class_get_field_count (klass);
1286 int i, first_field_idx;
1287
1288 g_assert (klass->enumtype);
1289
1290 error_init (error);
1291
1292 container = mono_class_try_get_generic_container (klass);
1293 if (mono_class_is_ginst (klass)) {
1294 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1295
1296 container = mono_class_get_generic_container (gklass);
1297 g_assert (container);
1298 }
1299
1300 /*
1301 * Fetch all the field information.
1302 */
1303 first_field_idx = mono_class_get_first_field_idx (klass);
1304 for (i = 0; i < top; i++){
1305 const char *sig;
1306 guint32 cols [MONO_FIELD_SIZE];
1307 int idx = first_field_idx + i;
1308 MonoType *ftype;
1309
1310 /* first_field_idx and idx points into the fieldptr table */
1311 mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
1312
1313 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
1314 continue;
1315
1316 if (!mono_verifier_verify_field_signature (klass->image, cols [MONO_FIELD_SIGNATURE], NULL)) {
1317 mono_error_set_bad_image (error, klass->image, "Invalid field signature %x", cols [MONO_FIELD_SIGNATURE]);
1318 goto fail;
1319 }
1320
1321 sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
1322 mono_metadata_decode_value (sig, &sig);
1323 /* FIELD signature == 0x06 */
1324 if (*sig != 0x06) {
1325 mono_error_set_bad_image (error, klass->image, "Invalid field signature %x, expected 0x6 but got %x", cols [MONO_FIELD_SIGNATURE], *sig);
1326 goto fail;
1327 }
1328
1329 ftype = mono_metadata_parse_type_checked (m, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
1330 if (!ftype)
1331 goto fail;
1332
1333 if (mono_class_is_ginst (klass)) {
1334 //FIXME do we leak here?
1335 ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error);
1336 if (!mono_error_ok (error))
1337 goto fail;
1338 ftype->attrs = cols [MONO_FIELD_FLAGS];
1339 }
1340
1341 return ftype;
1342 }
1343 mono_error_set_type_load_class (error, klass, "Could not find base type");
1344
1345 fail:
1346 return NULL;
1347 }
1348
1349 /*
1350 * Checks for MonoClass::has_failure without resolving all MonoType's into MonoClass'es
1351 */
1352 static gboolean
mono_type_has_exceptions(MonoType * type)1353 mono_type_has_exceptions (MonoType *type)
1354 {
1355 switch (type->type) {
1356 case MONO_TYPE_CLASS:
1357 case MONO_TYPE_VALUETYPE:
1358 case MONO_TYPE_SZARRAY:
1359 return mono_class_has_failure (type->data.klass);
1360 case MONO_TYPE_ARRAY:
1361 return mono_class_has_failure (type->data.array->eklass);
1362 case MONO_TYPE_GENERICINST:
1363 return mono_class_has_failure (mono_generic_class_get_class (type->data.generic_class));
1364 default:
1365 return FALSE;
1366 }
1367 }
1368
1369 void
mono_error_set_for_class_failure(MonoError * oerror,const MonoClass * klass)1370 mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
1371 {
1372 g_assert (mono_class_has_failure (klass));
1373 MonoErrorBoxed *box = mono_class_get_exception_data ((MonoClass*)klass);
1374 mono_error_set_from_boxed (oerror, box);
1375 }
1376
1377 /*
1378 * mono_class_alloc:
1379 *
1380 * Allocate memory for some data belonging to CLASS, either from its image's mempool,
1381 * or from the heap.
1382 */
1383 gpointer
mono_class_alloc(MonoClass * klass,int size)1384 mono_class_alloc (MonoClass *klass, int size)
1385 {
1386 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1387 if (gklass)
1388 return mono_image_set_alloc (gklass->owner, size);
1389 else
1390 return mono_image_alloc (klass->image, size);
1391 }
1392
1393 gpointer
mono_class_alloc0(MonoClass * klass,int size)1394 mono_class_alloc0 (MonoClass *klass, int size)
1395 {
1396 gpointer res;
1397
1398 res = mono_class_alloc (klass, size);
1399 memset (res, 0, size);
1400 return res;
1401 }
1402
1403 #define mono_class_new0(klass,struct_type, n_structs) \
1404 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
1405
1406 /**
1407 * mono_class_setup_basic_field_info:
1408 * \param class The class to initialize
1409 *
1410 * Initializes the following fields in MonoClass:
1411 * * klass->fields (only field->parent and field->name)
1412 * * klass->field.count
1413 * * klass->first_field_idx
1414 * LOCKING: Acquires the loader lock
1415 */
1416 static void
mono_class_setup_basic_field_info(MonoClass * klass)1417 mono_class_setup_basic_field_info (MonoClass *klass)
1418 {
1419 MonoGenericClass *gklass;
1420 MonoClassField *field;
1421 MonoClassField *fields;
1422 MonoClass *gtd;
1423 MonoImage *image;
1424 int i, top;
1425
1426 if (klass->fields)
1427 return;
1428
1429 gklass = mono_class_try_get_generic_class (klass);
1430 gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
1431 image = klass->image;
1432
1433
1434 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
1435 /*
1436 * This happens when a generic instance of an unfinished generic typebuilder
1437 * is used as an element type for creating an array type. We can't initialize
1438 * the fields of this class using the fields of gklass, since gklass is not
1439 * finished yet, fields could be added to it later.
1440 */
1441 return;
1442 }
1443
1444 if (gtd) {
1445 mono_class_setup_basic_field_info (gtd);
1446
1447 mono_loader_lock ();
1448 mono_class_set_field_count (klass, mono_class_get_field_count (gtd));
1449 mono_loader_unlock ();
1450 }
1451
1452 top = mono_class_get_field_count (klass);
1453
1454 fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
1455
1456 /*
1457 * Fetch all the field information.
1458 */
1459 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
1460 for (i = 0; i < top; i++) {
1461 field = &fields [i];
1462 field->parent = klass;
1463
1464 if (gtd) {
1465 field->name = mono_field_get_name (>d->fields [i]);
1466 } else {
1467 int idx = first_field_idx + i;
1468 /* first_field_idx and idx points into the fieldptr table */
1469 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
1470 /* The name is needed for fieldrefs */
1471 field->name = mono_metadata_string_heap (image, name_idx);
1472 }
1473 }
1474
1475 mono_memory_barrier ();
1476
1477 mono_loader_lock ();
1478 if (!klass->fields)
1479 klass->fields = fields;
1480 mono_loader_unlock ();
1481 }
1482
1483 /**
1484 * mono_class_set_failure_causedby_class:
1485 * \param klass the class that is failing
1486 * \param caused_by the class that caused the failure
1487 * \param msg Why \p klass is failing.
1488 *
1489 * If \p caused_by has a failure, sets a TypeLoadException failure on
1490 * \p klass with message "\p msg, due to: {\p caused_by message}".
1491 *
1492 * \returns TRUE if a failiure was set, or FALSE if \p caused_by doesn't have a failure.
1493 */
1494 static gboolean
mono_class_set_type_load_failure_causedby_class(MonoClass * klass,const MonoClass * caused_by,const gchar * msg)1495 mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg)
1496 {
1497 if (mono_class_has_failure (caused_by)) {
1498 MonoError cause_error;
1499 error_init (&cause_error);
1500 mono_error_set_for_class_failure (&cause_error, caused_by);
1501 mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (&cause_error));
1502 mono_error_cleanup (&cause_error);
1503 return TRUE;
1504 } else {
1505 return FALSE;
1506 }
1507 }
1508
1509
1510 /**
1511 * mono_class_setup_fields:
1512 * \p klass The class to initialize
1513 *
1514 * Initializes klass->fields, computes class layout and sizes.
1515 * typebuilder_setup_fields () is the corresponding function for dynamic classes.
1516 * Sets the following fields in \p klass:
1517 * - all the fields initialized by mono_class_init_sizes ()
1518 * - element_class/cast_class (for enums)
1519 * - sizes:element_size (for arrays)
1520 * - field->type/offset for all fields
1521 * - fields_inited
1522 *
1523 * LOCKING: Acquires the loader lock.
1524 */
1525 void
mono_class_setup_fields(MonoClass * klass)1526 mono_class_setup_fields (MonoClass *klass)
1527 {
1528 MonoError error;
1529 MonoImage *m = klass->image;
1530 int top;
1531 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
1532 int i;
1533 guint32 real_size = 0;
1534 guint32 packing_size = 0;
1535 int instance_size;
1536 gboolean explicit_size;
1537 MonoClassField *field;
1538 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1539 MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
1540
1541 if (klass->fields_inited)
1542 return;
1543
1544 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
1545 /*
1546 * This happens when a generic instance of an unfinished generic typebuilder
1547 * is used as an element type for creating an array type. We can't initialize
1548 * the fields of this class using the fields of gklass, since gklass is not
1549 * finished yet, fields could be added to it later.
1550 */
1551 return;
1552 }
1553
1554 mono_class_setup_basic_field_info (klass);
1555 top = mono_class_get_field_count (klass);
1556
1557 if (gtd) {
1558 mono_class_setup_fields (gtd);
1559 if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
1560 return;
1561 }
1562
1563 instance_size = 0;
1564 if (klass->parent) {
1565 /* For generic instances, klass->parent might not have been initialized */
1566 mono_class_init (klass->parent);
1567 mono_class_setup_fields (klass->parent);
1568 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
1569 return;
1570 instance_size = klass->parent->instance_size;
1571 } else {
1572 instance_size = sizeof (MonoObject);
1573 }
1574
1575 /* Get the real size */
1576 explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
1577 if (explicit_size)
1578 instance_size += real_size;
1579
1580 /*
1581 * This function can recursively call itself.
1582 * Prevent infinite recursion by using a list in TLS.
1583 */
1584 GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
1585 if (g_slist_find (init_list, klass))
1586 return;
1587 init_list = g_slist_prepend (init_list, klass);
1588 mono_native_tls_set_value (setup_fields_tls_id, init_list);
1589
1590 /*
1591 * Fetch all the field information.
1592 */
1593 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
1594 for (i = 0; i < top; i++) {
1595 int idx = first_field_idx + i;
1596 field = &klass->fields [i];
1597
1598 if (!field->type) {
1599 mono_field_resolve_type (field, &error);
1600 if (!mono_error_ok (&error)) {
1601 /*mono_field_resolve_type already failed class*/
1602 mono_error_cleanup (&error);
1603 break;
1604 }
1605 if (!field->type)
1606 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
1607 g_assert (field->type);
1608 }
1609
1610 if (!mono_type_get_underlying_type (field->type)) {
1611 mono_class_set_type_load_failure (klass, "Field '%s' is an enum type with a bad underlying type", field->name);
1612 break;
1613 }
1614
1615 if (mono_field_is_deleted (field))
1616 continue;
1617 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
1618 guint32 uoffset;
1619 mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
1620 int offset = uoffset;
1621
1622 if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1623 mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
1624 break;
1625 }
1626 if (offset < -1) { /*-1 is used to encode special static fields */
1627 mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
1628 break;
1629 }
1630 if (mono_class_is_gtd (klass)) {
1631 mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
1632 break;
1633 }
1634 }
1635 if (mono_type_has_exceptions (field->type)) {
1636 char *class_name = mono_type_get_full_name (klass);
1637 char *type_name = mono_type_full_name (field->type);
1638
1639 mono_class_set_type_load_failure (klass, "Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
1640 g_free (class_name);
1641 g_free (type_name);
1642 break;
1643 }
1644 /* The def_value of fields is compute lazily during vtable creation */
1645 }
1646
1647 if (!mono_class_has_failure (klass)) {
1648 mono_loader_lock ();
1649 mono_class_layout_fields (klass, instance_size, packing_size, real_size, FALSE);
1650 mono_loader_unlock ();
1651 }
1652
1653 init_list = g_slist_remove (init_list, klass);
1654 mono_native_tls_set_value (setup_fields_tls_id, init_list);
1655 }
1656
1657 static void
init_sizes_with_info(MonoClass * klass,MonoCachedClassInfo * cached_info)1658 init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
1659 {
1660 if (cached_info) {
1661 mono_loader_lock ();
1662 klass->instance_size = cached_info->instance_size;
1663 klass->sizes.class_size = cached_info->class_size;
1664 klass->packing_size = cached_info->packing_size;
1665 klass->min_align = cached_info->min_align;
1666 klass->blittable = cached_info->blittable;
1667 klass->has_references = cached_info->has_references;
1668 klass->has_static_refs = cached_info->has_static_refs;
1669 klass->no_special_static_fields = cached_info->no_special_static_fields;
1670 klass->has_weak_fields = cached_info->has_weak_fields;
1671 mono_loader_unlock ();
1672 }
1673 else {
1674 if (!klass->size_inited)
1675 mono_class_setup_fields (klass);
1676 }
1677 }
1678 /*
1679
1680 * mono_class_init_sizes:
1681 *
1682 * Initializes the size related fields of @klass without loading all field data if possible.
1683 * Sets the following fields in @klass:
1684 * - instance_size
1685 * - sizes.class_size
1686 * - packing_size
1687 * - min_align
1688 * - blittable
1689 * - has_references
1690 * - has_static_refs
1691 * - size_inited
1692 * Can fail the class.
1693 *
1694 * LOCKING: Acquires the loader lock.
1695 */
1696 static void
mono_class_init_sizes(MonoClass * klass)1697 mono_class_init_sizes (MonoClass *klass)
1698 {
1699 MonoCachedClassInfo cached_info;
1700 gboolean has_cached_info;
1701
1702 if (klass->size_inited)
1703 return;
1704
1705 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
1706
1707 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
1708 }
1709
1710 /*
1711 * mono_type_get_basic_type_from_generic:
1712 * @type: a type
1713 *
1714 * Returns a closed type corresponding to the possibly open type
1715 * passed to it.
1716 */
1717 MonoType*
mono_type_get_basic_type_from_generic(MonoType * type)1718 mono_type_get_basic_type_from_generic (MonoType *type)
1719 {
1720 /* When we do generic sharing we let type variables stand for reference/primitive types. */
1721 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) &&
1722 (!type->data.generic_param->gshared_constraint || type->data.generic_param->gshared_constraint->type == MONO_TYPE_OBJECT))
1723 return &mono_defaults.object_class->byval_arg;
1724 return type;
1725 }
1726
1727 static gboolean
class_has_references(MonoClass * klass)1728 class_has_references (MonoClass *klass)
1729 {
1730 mono_class_init_sizes (klass);
1731
1732 /*
1733 * has_references is not set if this is called recursively, but this is not a problem since this is only used
1734 * during field layout, and instance fields are initialized before static fields, and instance fields can't
1735 * embed themselves.
1736 */
1737 return klass->has_references;
1738 }
1739
1740 static gboolean
type_has_references(MonoClass * klass,MonoType * ftype)1741 type_has_references (MonoClass *klass, MonoType *ftype)
1742 {
1743 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && class_has_references (mono_class_from_mono_type (ftype)))))
1744 return TRUE;
1745 if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
1746 MonoGenericParam *gparam = ftype->data.generic_param;
1747
1748 if (gparam->gshared_constraint)
1749 return class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
1750 }
1751 return FALSE;
1752 }
1753
1754 /*
1755 * mono_class_layout_fields:
1756 * @class: a class
1757 * @base_instance_size: base instance size
1758 * @packing_size:
1759 *
1760 * This contains the common code for computing the layout of classes and sizes.
1761 * This should only be called from mono_class_setup_fields () and
1762 * typebuilder_setup_fields ().
1763 *
1764 * LOCKING: Acquires the loader lock
1765 */
1766 void
mono_class_layout_fields(MonoClass * klass,int base_instance_size,int packing_size,int explicit_size,gboolean sre)1767 mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, int explicit_size, gboolean sre)
1768 {
1769 int i;
1770 const int top = mono_class_get_field_count (klass);
1771 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
1772 guint32 pass, passes, real_size;
1773 gboolean gc_aware_layout = FALSE;
1774 gboolean has_static_fields = FALSE;
1775 gboolean has_references = FALSE;
1776 gboolean has_static_refs = FALSE;
1777 MonoClassField *field;
1778 gboolean blittable;
1779 int instance_size = base_instance_size;
1780 int element_size = -1;
1781 int class_size, min_align;
1782 int *field_offsets;
1783 gboolean *fields_has_references;
1784
1785 /*
1786 * We want to avoid doing complicated work inside locks, so we compute all the required
1787 * information and write it to @klass inside a lock.
1788 */
1789 if (klass->fields_inited)
1790 return;
1791
1792 if ((packing_size & 0xffffff00) != 0) {
1793 mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
1794 return;
1795 }
1796
1797 if (klass->parent) {
1798 min_align = klass->parent->min_align;
1799 /* we use | since it may have been set already */
1800 has_references = klass->has_references | klass->parent->has_references;
1801 } else {
1802 min_align = 1;
1803 }
1804 /* We can't really enable 16 bytes alignment until the GC supports it.
1805 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
1806 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
1807 Bug #506144 is an example of this issue.
1808
1809 if (klass->simd_type)
1810 min_align = 16;
1811 */
1812
1813 /*
1814 * When we do generic sharing we need to have layout
1815 * information for open generic classes (either with a generic
1816 * context containing type variables or with a generic
1817 * container), so we don't return in that case anymore.
1818 */
1819
1820 if (klass->enumtype) {
1821 for (i = 0; i < top; i++) {
1822 field = &klass->fields [i];
1823 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1824 klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
1825 break;
1826 }
1827 }
1828
1829 if (!mono_class_enum_basetype (klass)) {
1830 mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
1831 return;
1832 }
1833 }
1834
1835 /*
1836 * Enable GC aware auto layout: in this mode, reference
1837 * fields are grouped together inside objects, increasing collector
1838 * performance.
1839 * Requires that all classes whose layout is known to native code be annotated
1840 * with [StructLayout (LayoutKind.Sequential)]
1841 * Value types have gc_aware_layout disabled by default, as per
1842 * what the default is for other runtimes.
1843 */
1844 /* corlib is missing [StructLayout] directives in many places */
1845 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
1846 if (!klass->valuetype)
1847 gc_aware_layout = TRUE;
1848 }
1849
1850 /* Compute klass->blittable */
1851 blittable = TRUE;
1852 if (klass->parent)
1853 blittable = klass->parent->blittable;
1854 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
1855 blittable = FALSE;
1856 for (i = 0; i < top; i++) {
1857 field = &klass->fields [i];
1858
1859 if (mono_field_is_deleted (field))
1860 continue;
1861 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1862 continue;
1863 if (blittable) {
1864 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
1865 blittable = FALSE;
1866 } else {
1867 MonoClass *field_class = mono_class_from_mono_type (field->type);
1868 if (field_class) {
1869 mono_class_setup_fields (field_class);
1870 if (mono_class_has_failure (field_class)) {
1871 MonoError field_error;
1872 error_init (&field_error);
1873 mono_error_set_for_class_failure (&field_error, field_class);
1874 mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (&field_error));
1875 mono_error_cleanup (&field_error);
1876 break;
1877 }
1878 }
1879 if (!field_class || !field_class->blittable)
1880 blittable = FALSE;
1881 }
1882 }
1883 if (klass->enumtype)
1884 blittable = klass->element_class->blittable;
1885 }
1886 if (mono_class_has_failure (klass))
1887 return;
1888 if (klass == mono_defaults.string_class)
1889 blittable = FALSE;
1890
1891 /* Compute klass->has_references */
1892 /*
1893 * Process non-static fields first, since static fields might recursively
1894 * refer to the class itself.
1895 */
1896 for (i = 0; i < top; i++) {
1897 MonoType *ftype;
1898
1899 field = &klass->fields [i];
1900
1901 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1902 ftype = mono_type_get_underlying_type (field->type);
1903 ftype = mono_type_get_basic_type_from_generic (ftype);
1904 if (type_has_references (klass, ftype))
1905 has_references = TRUE;
1906 }
1907 }
1908
1909 /*
1910 * Compute field layout and total size (not considering static fields)
1911 */
1912 field_offsets = g_new0 (int, top);
1913 fields_has_references = g_new0 (gboolean, top);
1914 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
1915 switch (layout) {
1916 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
1917 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
1918 if (gc_aware_layout)
1919 passes = 2;
1920 else
1921 passes = 1;
1922
1923 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
1924 passes = 1;
1925
1926 if (klass->parent) {
1927 mono_class_setup_fields (klass->parent);
1928 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
1929 return;
1930 real_size = klass->parent->instance_size;
1931 } else {
1932 real_size = sizeof (MonoObject);
1933 }
1934
1935 for (pass = 0; pass < passes; ++pass) {
1936 for (i = 0; i < top; i++){
1937 gint32 align;
1938 guint32 size;
1939 MonoType *ftype;
1940
1941 field = &klass->fields [i];
1942
1943 if (mono_field_is_deleted (field))
1944 continue;
1945 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1946 continue;
1947
1948 ftype = mono_type_get_underlying_type (field->type);
1949 ftype = mono_type_get_basic_type_from_generic (ftype);
1950 if (gc_aware_layout) {
1951 fields_has_references [i] = type_has_references (klass, ftype);
1952 if (fields_has_references [i]) {
1953 if (pass == 1)
1954 continue;
1955 } else {
1956 if (pass == 0)
1957 continue;
1958 }
1959 }
1960
1961 if ((top == 1) && (instance_size == sizeof (MonoObject)) &&
1962 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
1963 /* This field is a hack inserted by MCS to empty structures */
1964 continue;
1965 }
1966
1967 size = mono_type_size (field->type, &align);
1968
1969 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
1970 align = packing_size ? MIN (packing_size, align): align;
1971 /* if the field has managed references, we need to force-align it
1972 * see bug #77788
1973 */
1974 if (type_has_references (klass, ftype))
1975 align = MAX (align, sizeof (gpointer));
1976
1977 min_align = MAX (align, min_align);
1978 field_offsets [i] = real_size;
1979 if (align) {
1980 field_offsets [i] += align - 1;
1981 field_offsets [i] &= ~(align - 1);
1982 }
1983 /*TypeBuilders produce all sort of weird things*/
1984 g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
1985 real_size = field_offsets [i] + size;
1986 }
1987
1988 /* Make SIMD types as big as a SIMD register since they can be stored into using simd stores */
1989 if (klass->simd_type)
1990 real_size = MAX (real_size, sizeof (MonoObject) + 16);
1991 instance_size = MAX (real_size, instance_size);
1992
1993 if (instance_size & (min_align - 1)) {
1994 instance_size += min_align - 1;
1995 instance_size &= ~(min_align - 1);
1996 }
1997 }
1998 break;
1999 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
2000 guint8 *ref_bitmap;
2001
2002 real_size = 0;
2003 for (i = 0; i < top; i++) {
2004 gint32 align;
2005 guint32 size;
2006 MonoType *ftype;
2007
2008 field = &klass->fields [i];
2009
2010 /*
2011 * There must be info about all the fields in a type if it
2012 * uses explicit layout.
2013 */
2014 if (mono_field_is_deleted (field))
2015 continue;
2016 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2017 continue;
2018
2019 size = mono_type_size (field->type, &align);
2020 align = packing_size ? MIN (packing_size, align): align;
2021 min_align = MAX (align, min_align);
2022
2023 if (sre) {
2024 /* Already set by typebuilder_setup_fields () */
2025 field_offsets [i] = field->offset + sizeof (MonoObject);
2026 } else {
2027 int idx = first_field_idx + i;
2028 guint32 offset;
2029 mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
2030 field_offsets [i] = offset + sizeof (MonoObject);
2031 }
2032 ftype = mono_type_get_underlying_type (field->type);
2033 ftype = mono_type_get_basic_type_from_generic (ftype);
2034 if (type_has_references (klass, ftype)) {
2035 if (field_offsets [i] % sizeof (gpointer)) {
2036 mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
2037 }
2038 }
2039
2040 /*
2041 * Calc max size.
2042 */
2043 real_size = MAX (real_size, size + field_offsets [i]);
2044 }
2045
2046 if (klass->has_references) {
2047 ref_bitmap = g_new0 (guint8, real_size / sizeof (gpointer));
2048
2049 /* Check for overlapping reference and non-reference fields */
2050 for (i = 0; i < top; i++) {
2051 MonoType *ftype;
2052
2053 field = &klass->fields [i];
2054
2055 if (mono_field_is_deleted (field))
2056 continue;
2057 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2058 continue;
2059 ftype = mono_type_get_underlying_type (field->type);
2060 if (MONO_TYPE_IS_REFERENCE (ftype))
2061 ref_bitmap [field_offsets [i] / sizeof (gpointer)] = 1;
2062 }
2063 for (i = 0; i < top; i++) {
2064 field = &klass->fields [i];
2065
2066 if (mono_field_is_deleted (field))
2067 continue;
2068 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2069 continue;
2070
2071 // FIXME: Too much code does this
2072 #if 0
2073 if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / sizeof (gpointer)]) {
2074 mono_class_set_type_load_failure (klass, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field_offsets [i]);
2075 }
2076 #endif
2077 }
2078 g_free (ref_bitmap);
2079 }
2080
2081 instance_size = MAX (real_size, instance_size);
2082 if (!((layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && explicit_size)) {
2083 if (instance_size & (min_align - 1)) {
2084 instance_size += min_align - 1;
2085 instance_size &= ~(min_align - 1);
2086 }
2087 }
2088 break;
2089 }
2090 }
2091
2092 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
2093 /*
2094 * This leads to all kinds of problems with nested structs, so only
2095 * enable it when a MONO_DEBUG property is set.
2096 *
2097 * For small structs, set min_align to at least the struct size to improve
2098 * performance, and since the JIT memset/memcpy code assumes this and generates
2099 * unaligned accesses otherwise. See #78990 for a testcase.
2100 */
2101 if (mono_align_small_structs && top) {
2102 if (instance_size <= sizeof (MonoObject) + sizeof (gpointer))
2103 min_align = MAX (min_align, instance_size - sizeof (MonoObject));
2104 }
2105 }
2106
2107 if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
2108 instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
2109 else if (klass->byval_arg.type == MONO_TYPE_PTR)
2110 instance_size = sizeof (MonoObject) + sizeof (gpointer);
2111
2112 if (klass->byval_arg.type == MONO_TYPE_SZARRAY || klass->byval_arg.type == MONO_TYPE_ARRAY)
2113 element_size = mono_class_array_element_size (klass->element_class);
2114
2115 /* Publish the data */
2116 mono_loader_lock ();
2117 if (klass->instance_size && !klass->image->dynamic) {
2118 /* Might be already set using cached info */
2119 if (klass->instance_size != instance_size) {
2120 /* Emit info to help debugging */
2121 g_print ("%s\n", mono_class_full_name (klass));
2122 g_print ("%d %d %d %d\n", klass->instance_size, instance_size, klass->blittable, blittable);
2123 g_print ("%d %d %d %d\n", klass->has_references, has_references, klass->packing_size, packing_size);
2124 g_print ("%d %d\n", klass->min_align, min_align);
2125 for (i = 0; i < top; ++i) {
2126 field = &klass->fields [i];
2127 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2128 printf (" %s %d %d %d\n", klass->fields [i].name, klass->fields [i].offset, field_offsets [i], fields_has_references [i]);
2129 }
2130 }
2131 g_assert (klass->instance_size == instance_size);
2132 } else {
2133 klass->instance_size = instance_size;
2134 }
2135 klass->blittable = blittable;
2136 klass->has_references = has_references;
2137 klass->packing_size = packing_size;
2138 klass->min_align = min_align;
2139 for (i = 0; i < top; ++i) {
2140 field = &klass->fields [i];
2141 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2142 klass->fields [i].offset = field_offsets [i];
2143 }
2144
2145 if (klass->byval_arg.type == MONO_TYPE_SZARRAY || klass->byval_arg.type == MONO_TYPE_ARRAY)
2146 klass->sizes.element_size = element_size;
2147
2148 mono_memory_barrier ();
2149 klass->size_inited = 1;
2150 mono_loader_unlock ();
2151
2152 /*
2153 * Compute static field layout and size
2154 * Static fields can reference the class itself, so this has to be
2155 * done after instance_size etc. are initialized.
2156 */
2157 class_size = 0;
2158 for (i = 0; i < top; i++) {
2159 gint32 align;
2160 guint32 size;
2161
2162 field = &klass->fields [i];
2163
2164 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
2165 continue;
2166 if (mono_field_is_deleted (field))
2167 continue;
2168
2169 if (mono_type_has_exceptions (field->type)) {
2170 mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
2171 break;
2172 }
2173
2174 has_static_fields = TRUE;
2175
2176 size = mono_type_size (field->type, &align);
2177 field_offsets [i] = class_size;
2178 /*align is always non-zero here*/
2179 field_offsets [i] += align - 1;
2180 field_offsets [i] &= ~(align - 1);
2181 class_size = field_offsets [i] + size;
2182 }
2183
2184 if (has_static_fields && class_size == 0)
2185 /* Simplify code which depends on class_size != 0 if the class has static fields */
2186 class_size = 8;
2187
2188 /* Compute klass->has_static_refs */
2189 has_static_refs = FALSE;
2190 for (i = 0; i < top; i++) {
2191 MonoType *ftype;
2192
2193 field = &klass->fields [i];
2194
2195 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2196 ftype = mono_type_get_underlying_type (field->type);
2197 ftype = mono_type_get_basic_type_from_generic (ftype);
2198 if (type_has_references (klass, ftype))
2199 has_static_refs = TRUE;
2200 }
2201 }
2202
2203 /*valuetypes can't be neither bigger than 1Mb or empty. */
2204 if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject)))) {
2205 /* Special case compiler generated types */
2206 /* Hard to check for [CompilerGenerated] here */
2207 if (!strstr (klass->name, "StaticArrayInitTypeSize") && !strstr (klass->name, "$ArrayType"))
2208 mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
2209 }
2210
2211 // Weak field support
2212 //
2213 // FIXME:
2214 // - generic instances
2215 // - Disallow on structs/static fields/nonref fields
2216 gboolean has_weak_fields = FALSE;
2217
2218 if (mono_class_has_static_metadata (klass)) {
2219 for (MonoClass *p = klass; p != NULL; p = p->parent) {
2220 gpointer iter = NULL;
2221 guint32 first_field_idx = mono_class_get_first_field_idx (p);
2222
2223 while ((field = mono_class_get_fields (p, &iter))) {
2224 guint32 field_idx = first_field_idx + (field - p->fields);
2225 if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) {
2226 has_weak_fields = TRUE;
2227 mono_trace_message (MONO_TRACE_TYPE, "Field %s:%s at offset %x is weak.", field->parent->name, field->name, field->offset);
2228 }
2229 }
2230 }
2231 }
2232
2233 /* Publish the data */
2234 mono_loader_lock ();
2235 if (!klass->rank)
2236 klass->sizes.class_size = class_size;
2237 klass->has_static_refs = has_static_refs;
2238 klass->has_weak_fields = has_weak_fields;
2239 for (i = 0; i < top; ++i) {
2240 field = &klass->fields [i];
2241
2242 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2243 field->offset = field_offsets [i];
2244 }
2245 mono_memory_barrier ();
2246 klass->fields_inited = 1;
2247 mono_loader_unlock ();
2248
2249 g_free (field_offsets);
2250 g_free (fields_has_references);
2251 }
2252
2253 static MonoMethod*
create_array_method(MonoClass * klass,const char * name,MonoMethodSignature * sig)2254 create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *sig)
2255 {
2256 MonoMethod *method;
2257
2258 method = (MonoMethod *) mono_image_alloc0 (klass->image, sizeof (MonoMethodPInvoke));
2259 method->klass = klass;
2260 method->flags = METHOD_ATTRIBUTE_PUBLIC;
2261 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
2262 method->signature = sig;
2263 method->name = name;
2264 method->slot = -1;
2265 /* .ctor */
2266 if (name [0] == '.') {
2267 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
2268 } else {
2269 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
2270 }
2271 return method;
2272 }
2273
2274 /*
2275 * mono_class_setup_methods:
2276 * @class: a class
2277 *
2278 * Initializes the 'methods' array in CLASS.
2279 * Calling this method should be avoided if possible since it allocates a lot
2280 * of long-living MonoMethod structures.
2281 * Methods belonging to an interface are assigned a sequential slot starting
2282 * from 0.
2283 *
2284 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
2285 */
2286 void
mono_class_setup_methods(MonoClass * klass)2287 mono_class_setup_methods (MonoClass *klass)
2288 {
2289 int i, count;
2290 MonoMethod **methods;
2291
2292 if (klass->methods)
2293 return;
2294
2295 if (mono_class_is_ginst (klass)) {
2296 MonoError error;
2297 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2298
2299 mono_class_init (gklass);
2300 if (!mono_class_has_failure (gklass))
2301 mono_class_setup_methods (gklass);
2302 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2303 return;
2304
2305 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
2306 count = mono_class_get_method_count (gklass);
2307 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1));
2308
2309 for (i = 0; i < count; i++) {
2310 methods [i] = mono_class_inflate_generic_method_full_checked (
2311 gklass->methods [i], klass, mono_class_get_context (klass), &error);
2312 if (!mono_error_ok (&error)) {
2313 char *method = mono_method_full_name (gklass->methods [i], TRUE);
2314 mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (&error));
2315
2316 g_free (method);
2317 mono_error_cleanup (&error);
2318 return;
2319 }
2320 }
2321 } else if (klass->rank) {
2322 MonoError error;
2323 MonoMethod *amethod;
2324 MonoMethodSignature *sig;
2325 int count_generic = 0, first_generic = 0;
2326 int method_num = 0;
2327 gboolean jagged_ctor = FALSE;
2328
2329 count = 3 + (klass->rank > 1? 2: 1);
2330
2331 mono_class_setup_interfaces (klass, &error);
2332 g_assert (mono_error_ok (&error)); /*FIXME can this fail for array types?*/
2333
2334 if (klass->rank == 1 && klass->element_class->rank) {
2335 jagged_ctor = TRUE;
2336 count ++;
2337 }
2338
2339 if (klass->interface_count) {
2340 count_generic = generic_array_methods (klass);
2341 first_generic = count;
2342 count += klass->interface_count * count_generic;
2343 }
2344
2345 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * count);
2346
2347 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2348 sig->ret = &mono_defaults.void_class->byval_arg;
2349 sig->pinvoke = TRUE;
2350 sig->hasthis = TRUE;
2351 for (i = 0; i < klass->rank; ++i)
2352 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2353
2354 amethod = create_array_method (klass, ".ctor", sig);
2355 methods [method_num++] = amethod;
2356 if (klass->rank > 1) {
2357 sig = mono_metadata_signature_alloc (klass->image, klass->rank * 2);
2358 sig->ret = &mono_defaults.void_class->byval_arg;
2359 sig->pinvoke = TRUE;
2360 sig->hasthis = TRUE;
2361 for (i = 0; i < klass->rank * 2; ++i)
2362 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2363
2364 amethod = create_array_method (klass, ".ctor", sig);
2365 methods [method_num++] = amethod;
2366 }
2367
2368 if (jagged_ctor) {
2369 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
2370 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
2371 sig->ret = &mono_defaults.void_class->byval_arg;
2372 sig->pinvoke = TRUE;
2373 sig->hasthis = TRUE;
2374 for (i = 0; i < klass->rank + 1; ++i)
2375 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2376 amethod = create_array_method (klass, ".ctor", sig);
2377 methods [method_num++] = amethod;
2378 }
2379
2380 /* element Get (idx11, [idx2, ...]) */
2381 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2382 sig->ret = &klass->element_class->byval_arg;
2383 sig->pinvoke = TRUE;
2384 sig->hasthis = TRUE;
2385 for (i = 0; i < klass->rank; ++i)
2386 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2387 amethod = create_array_method (klass, "Get", sig);
2388 methods [method_num++] = amethod;
2389 /* element& Address (idx11, [idx2, ...]) */
2390 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2391 sig->ret = &klass->element_class->this_arg;
2392 sig->pinvoke = TRUE;
2393 sig->hasthis = TRUE;
2394 for (i = 0; i < klass->rank; ++i)
2395 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2396 amethod = create_array_method (klass, "Address", sig);
2397 methods [method_num++] = amethod;
2398 /* void Set (idx11, [idx2, ...], element) */
2399 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
2400 sig->ret = &mono_defaults.void_class->byval_arg;
2401 sig->pinvoke = TRUE;
2402 sig->hasthis = TRUE;
2403 for (i = 0; i < klass->rank; ++i)
2404 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2405 sig->params [i] = &klass->element_class->byval_arg;
2406 amethod = create_array_method (klass, "Set", sig);
2407 methods [method_num++] = amethod;
2408
2409 GHashTable *cache = g_hash_table_new (NULL, NULL);
2410 for (i = 0; i < klass->interface_count; i++)
2411 setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic, cache);
2412 g_hash_table_destroy (cache);
2413 } else if (mono_class_has_static_metadata (klass)) {
2414 MonoError error;
2415 int first_idx = mono_class_get_first_method_idx (klass);
2416
2417 count = mono_class_get_method_count (klass);
2418 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
2419 for (i = 0; i < count; ++i) {
2420 int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
2421 methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, &error);
2422 if (!methods [i]) {
2423 mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (&error));
2424 mono_error_cleanup (&error);
2425 }
2426 }
2427 } else {
2428 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
2429 count = 0;
2430 }
2431
2432 if (MONO_CLASS_IS_INTERFACE (klass)) {
2433 int slot = 0;
2434 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
2435 for (i = 0; i < count; ++i) {
2436 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
2437 methods [i]->slot = slot++;
2438 }
2439 }
2440
2441 mono_image_lock (klass->image);
2442
2443 if (!klass->methods) {
2444 mono_class_set_method_count (klass, count);
2445
2446 /* Needed because of the double-checking locking pattern */
2447 mono_memory_barrier ();
2448
2449 klass->methods = methods;
2450 }
2451
2452 mono_image_unlock (klass->image);
2453 }
2454
2455 /*
2456 * mono_class_get_method_by_index:
2457 *
2458 * Returns klass->methods [index], initializing klass->methods if neccesary.
2459 *
2460 * LOCKING: Acquires the loader lock.
2461 */
2462 MonoMethod*
mono_class_get_method_by_index(MonoClass * klass,int index)2463 mono_class_get_method_by_index (MonoClass *klass, int index)
2464 {
2465 MonoError error;
2466
2467 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
2468 /* Avoid calling setup_methods () if possible */
2469 if (gklass && !klass->methods) {
2470 MonoMethod *m;
2471
2472 m = mono_class_inflate_generic_method_full_checked (
2473 gklass->container_class->methods [index], klass, mono_class_get_context (klass), &error);
2474 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2475 /*
2476 * If setup_methods () is called later for this class, no duplicates are created,
2477 * since inflate_generic_method guarantees that only one instance of a method
2478 * is created for each context.
2479 */
2480 /*
2481 mono_class_setup_methods (klass);
2482 g_assert (m == klass->methods [index]);
2483 */
2484 return m;
2485 } else {
2486 mono_class_setup_methods (klass);
2487 if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
2488 return NULL;
2489 g_assert (index >= 0 && index < mono_class_get_method_count (klass));
2490 return klass->methods [index];
2491 }
2492 }
2493
2494 /*
2495 * mono_class_get_inflated_method:
2496 *
2497 * Given an inflated class CLASS and a method METHOD which should be a method of
2498 * CLASS's generic definition, return the inflated method corresponding to METHOD.
2499 */
2500 MonoMethod*
mono_class_get_inflated_method(MonoClass * klass,MonoMethod * method)2501 mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method)
2502 {
2503 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2504 int i, mcount;
2505
2506 g_assert (method->klass == gklass);
2507
2508 mono_class_setup_methods (gklass);
2509 g_assert (!mono_class_has_failure (gklass)); /*FIXME do proper error handling*/
2510
2511 mcount = mono_class_get_method_count (gklass);
2512 for (i = 0; i < mcount; ++i) {
2513 if (gklass->methods [i] == method) {
2514 if (klass->methods) {
2515 return klass->methods [i];
2516 } else {
2517 MonoError error;
2518 MonoMethod *result = mono_class_inflate_generic_method_full_checked (gklass->methods [i], klass, mono_class_get_context (klass), &error);
2519 g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
2520 return result;
2521 }
2522 }
2523 }
2524
2525 return NULL;
2526 }
2527
2528 /*
2529 * mono_class_get_vtable_entry:
2530 *
2531 * Returns klass->vtable [offset], computing it if neccesary. Returns NULL on failure.
2532 * LOCKING: Acquires the loader lock.
2533 */
2534 MonoMethod*
mono_class_get_vtable_entry(MonoClass * klass,int offset)2535 mono_class_get_vtable_entry (MonoClass *klass, int offset)
2536 {
2537 MonoMethod *m;
2538
2539 if (klass->rank == 1) {
2540 /*
2541 * szarrays do not overwrite any methods of Array, so we can avoid
2542 * initializing their vtables in some cases.
2543 */
2544 mono_class_setup_vtable (klass->parent);
2545 if (offset < klass->parent->vtable_size)
2546 return klass->parent->vtable [offset];
2547 }
2548
2549 if (mono_class_is_ginst (klass)) {
2550 MonoError error;
2551 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2552 mono_class_setup_vtable (gklass);
2553 m = gklass->vtable [offset];
2554
2555 m = mono_class_inflate_generic_method_full_checked (m, klass, mono_class_get_context (klass), &error);
2556 g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
2557 } else {
2558 mono_class_setup_vtable (klass);
2559 if (mono_class_has_failure (klass))
2560 return NULL;
2561 m = klass->vtable [offset];
2562 }
2563
2564 return m;
2565 }
2566
2567 /*
2568 * mono_class_get_vtable_size:
2569 *
2570 * Return the vtable size for KLASS.
2571 */
2572 int
mono_class_get_vtable_size(MonoClass * klass)2573 mono_class_get_vtable_size (MonoClass *klass)
2574 {
2575 mono_class_setup_vtable (klass);
2576
2577 return klass->vtable_size;
2578 }
2579
2580 /*
2581 * mono_class_setup_properties:
2582 *
2583 * Initialize klass->ext.property and klass->ext.properties.
2584 *
2585 * This method can fail the class.
2586 */
2587 static void
mono_class_setup_properties(MonoClass * klass)2588 mono_class_setup_properties (MonoClass *klass)
2589 {
2590 guint startm, endm, i, j;
2591 guint32 cols [MONO_PROPERTY_SIZE];
2592 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
2593 MonoProperty *properties;
2594 guint32 last;
2595 int first, count;
2596 MonoClassPropertyInfo *info;
2597
2598 info = mono_class_get_property_info (klass);
2599 if (info)
2600 return;
2601
2602 if (mono_class_is_ginst (klass)) {
2603 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2604
2605 mono_class_init (gklass);
2606 mono_class_setup_properties (gklass);
2607 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2608 return;
2609
2610 MonoClassPropertyInfo *ginfo = mono_class_get_property_info (gklass);
2611 properties = mono_class_new0 (klass, MonoProperty, ginfo->count + 1);
2612
2613 for (i = 0; i < ginfo->count; i++) {
2614 MonoError error;
2615 MonoProperty *prop = &properties [i];
2616
2617 *prop = ginfo->properties [i];
2618
2619 if (prop->get)
2620 prop->get = mono_class_inflate_generic_method_full_checked (
2621 prop->get, klass, mono_class_get_context (klass), &error);
2622 if (prop->set)
2623 prop->set = mono_class_inflate_generic_method_full_checked (
2624 prop->set, klass, mono_class_get_context (klass), &error);
2625
2626 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2627 prop->parent = klass;
2628 }
2629
2630 first = ginfo->first;
2631 count = ginfo->count;
2632 } else {
2633 first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
2634 count = last - first;
2635
2636 if (count) {
2637 mono_class_setup_methods (klass);
2638 if (mono_class_has_failure (klass))
2639 return;
2640 }
2641
2642 properties = (MonoProperty *)mono_class_alloc0 (klass, sizeof (MonoProperty) * count);
2643 for (i = first; i < last; ++i) {
2644 mono_metadata_decode_table_row (klass->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
2645 properties [i - first].parent = klass;
2646 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
2647 properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
2648
2649 startm = mono_metadata_methods_from_property (klass->image, i, &endm);
2650 int first_idx = mono_class_get_first_method_idx (klass);
2651 for (j = startm; j < endm; ++j) {
2652 MonoMethod *method;
2653
2654 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2655
2656 if (klass->image->uncompressed_metadata) {
2657 MonoError error;
2658 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2659 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
2660 mono_error_cleanup (&error); /* FIXME don't swallow this error */
2661 } else {
2662 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
2663 }
2664
2665 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2666 case METHOD_SEMANTIC_SETTER:
2667 properties [i - first].set = method;
2668 break;
2669 case METHOD_SEMANTIC_GETTER:
2670 properties [i - first].get = method;
2671 break;
2672 default:
2673 break;
2674 }
2675 }
2676 }
2677 }
2678
2679 info = mono_class_alloc0 (klass, sizeof (MonoClassPropertyInfo));
2680 info->first = first;
2681 info->count = count;
2682 info->properties = properties;
2683 mono_memory_barrier ();
2684
2685 /* This might leak 'info' which was allocated from the image mempool */
2686 mono_class_set_property_info (klass, info);
2687 }
2688
2689 static MonoMethod**
inflate_method_listz(MonoMethod ** methods,MonoClass * klass,MonoGenericContext * context)2690 inflate_method_listz (MonoMethod **methods, MonoClass *klass, MonoGenericContext *context)
2691 {
2692 MonoMethod **om, **retval;
2693 int count;
2694
2695 for (om = methods, count = 0; *om; ++om, ++count)
2696 ;
2697
2698 retval = g_new0 (MonoMethod*, count + 1);
2699 count = 0;
2700 for (om = methods, count = 0; *om; ++om, ++count) {
2701 MonoError error;
2702 retval [count] = mono_class_inflate_generic_method_full_checked (*om, klass, context, &error);
2703 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2704 }
2705
2706 return retval;
2707 }
2708
2709 /*This method can fail the class.*/
2710 static void
mono_class_setup_events(MonoClass * klass)2711 mono_class_setup_events (MonoClass *klass)
2712 {
2713 int first, count;
2714 guint startm, endm, i, j;
2715 guint32 cols [MONO_EVENT_SIZE];
2716 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
2717 guint32 last;
2718 MonoEvent *events;
2719
2720 MonoClassEventInfo *info = mono_class_get_event_info (klass);
2721 if (info)
2722 return;
2723
2724 if (mono_class_is_ginst (klass)) {
2725 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2726 MonoGenericContext *context = NULL;
2727
2728 mono_class_setup_events (gklass);
2729 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2730 return;
2731
2732 MonoClassEventInfo *ginfo = mono_class_get_event_info (gklass);
2733 first = ginfo->first;
2734 count = ginfo->count;
2735
2736 events = mono_class_new0 (klass, MonoEvent, count);
2737
2738 if (count)
2739 context = mono_class_get_context (klass);
2740
2741 for (i = 0; i < count; i++) {
2742 MonoError error;
2743 MonoEvent *event = &events [i];
2744 MonoEvent *gevent = &ginfo->events [i];
2745
2746 error_init (&error); //since we do conditional calls, we must ensure the default value is ok
2747
2748 event->parent = klass;
2749 event->name = gevent->name;
2750 event->add = gevent->add ? mono_class_inflate_generic_method_full_checked (gevent->add, klass, context, &error) : NULL;
2751 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2752 event->remove = gevent->remove ? mono_class_inflate_generic_method_full_checked (gevent->remove, klass, context, &error) : NULL;
2753 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2754 event->raise = gevent->raise ? mono_class_inflate_generic_method_full_checked (gevent->raise, klass, context, &error) : NULL;
2755 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2756
2757 #ifndef MONO_SMALL_CONFIG
2758 event->other = gevent->other ? inflate_method_listz (gevent->other, klass, context) : NULL;
2759 #endif
2760 event->attrs = gevent->attrs;
2761 }
2762 } else {
2763 first = mono_metadata_events_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
2764 count = last - first;
2765
2766 if (count) {
2767 mono_class_setup_methods (klass);
2768 if (mono_class_has_failure (klass)) {
2769 return;
2770 }
2771 }
2772
2773 events = (MonoEvent *)mono_class_alloc0 (klass, sizeof (MonoEvent) * count);
2774 for (i = first; i < last; ++i) {
2775 MonoEvent *event = &events [i - first];
2776
2777 mono_metadata_decode_table_row (klass->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
2778 event->parent = klass;
2779 event->attrs = cols [MONO_EVENT_FLAGS];
2780 event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
2781
2782 startm = mono_metadata_methods_from_event (klass->image, i, &endm);
2783 int first_idx = mono_class_get_first_method_idx (klass);
2784 for (j = startm; j < endm; ++j) {
2785 MonoMethod *method;
2786
2787 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2788
2789 if (klass->image->uncompressed_metadata) {
2790 MonoError error;
2791 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2792 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
2793 mono_error_cleanup (&error); /* FIXME don't swallow this error */
2794 } else {
2795 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
2796 }
2797
2798 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2799 case METHOD_SEMANTIC_ADD_ON:
2800 event->add = method;
2801 break;
2802 case METHOD_SEMANTIC_REMOVE_ON:
2803 event->remove = method;
2804 break;
2805 case METHOD_SEMANTIC_FIRE:
2806 event->raise = method;
2807 break;
2808 case METHOD_SEMANTIC_OTHER: {
2809 #ifndef MONO_SMALL_CONFIG
2810 int n = 0;
2811
2812 if (event->other == NULL) {
2813 event->other = g_new0 (MonoMethod*, 2);
2814 } else {
2815 while (event->other [n])
2816 n++;
2817 event->other = (MonoMethod **)g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
2818 }
2819 event->other [n] = method;
2820 /* NULL terminated */
2821 event->other [n + 1] = NULL;
2822 #endif
2823 break;
2824 }
2825 default:
2826 break;
2827 }
2828 }
2829 }
2830 }
2831
2832 info = mono_class_alloc0 (klass, sizeof (MonoClassEventInfo));
2833 info->events = events;
2834 info->first = first;
2835 info->count = count;
2836
2837 mono_memory_barrier ();
2838
2839 mono_class_set_event_info (klass, info);
2840 }
2841
2842 /*
2843 * Global pool of interface IDs, represented as a bitset.
2844 * LOCKING: Protected by the classes lock.
2845 */
2846 static MonoBitSet *global_interface_bitset = NULL;
2847
2848 /*
2849 * mono_unload_interface_ids:
2850 * @bitset: bit set of interface IDs
2851 *
2852 * When an image is unloaded, the interface IDs associated with
2853 * the image are put back in the global pool of IDs so the numbers
2854 * can be reused.
2855 */
2856 void
mono_unload_interface_ids(MonoBitSet * bitset)2857 mono_unload_interface_ids (MonoBitSet *bitset)
2858 {
2859 classes_lock ();
2860 mono_bitset_sub (global_interface_bitset, bitset);
2861 classes_unlock ();
2862 }
2863
2864 void
mono_unload_interface_id(MonoClass * klass)2865 mono_unload_interface_id (MonoClass *klass)
2866 {
2867 if (global_interface_bitset && klass->interface_id) {
2868 classes_lock ();
2869 mono_bitset_clear (global_interface_bitset, klass->interface_id);
2870 classes_unlock ();
2871 }
2872 }
2873
2874 /**
2875 * mono_get_unique_iid:
2876 * \param klass interface
2877 *
2878 * Assign a unique integer ID to the interface represented by \p klass.
2879 * The ID will positive and as small as possible.
2880 * LOCKING: Acquires the classes lock.
2881 * \returns The new ID.
2882 */
2883 static guint32
mono_get_unique_iid(MonoClass * klass)2884 mono_get_unique_iid (MonoClass *klass)
2885 {
2886 int iid;
2887
2888 g_assert (MONO_CLASS_IS_INTERFACE (klass));
2889
2890 classes_lock ();
2891
2892 if (!global_interface_bitset) {
2893 global_interface_bitset = mono_bitset_new (128, 0);
2894 }
2895
2896 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
2897 if (iid < 0) {
2898 int old_size = mono_bitset_size (global_interface_bitset);
2899 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
2900 mono_bitset_free (global_interface_bitset);
2901 global_interface_bitset = new_set;
2902 iid = old_size;
2903 }
2904 mono_bitset_set (global_interface_bitset, iid);
2905 /* set the bit also in the per-image set */
2906 if (!mono_class_is_ginst (klass)) {
2907 if (klass->image->interface_bitset) {
2908 if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
2909 MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
2910 mono_bitset_free (klass->image->interface_bitset);
2911 klass->image->interface_bitset = new_set;
2912 }
2913 } else {
2914 klass->image->interface_bitset = mono_bitset_new (iid + 1, 0);
2915 }
2916 mono_bitset_set (klass->image->interface_bitset, iid);
2917 }
2918
2919 classes_unlock ();
2920
2921 #ifndef MONO_SMALL_CONFIG
2922 if (mono_print_vtable) {
2923 int generic_id;
2924 char *type_name = mono_type_full_name (&klass->byval_arg);
2925 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
2926 if (gklass && !gklass->context.class_inst->is_open) {
2927 generic_id = gklass->context.class_inst->id;
2928 g_assert (generic_id != 0);
2929 } else {
2930 generic_id = 0;
2931 }
2932 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->name, type_name, generic_id);
2933 g_free (type_name);
2934 }
2935 #endif
2936
2937 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
2938 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
2939 g_assert (iid < INT_MAX);
2940 return iid;
2941 }
2942
2943 static void
collect_implemented_interfaces_aux(MonoClass * klass,GPtrArray ** res,GHashTable ** ifaces,MonoError * error)2944 collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, GHashTable **ifaces, MonoError *error)
2945 {
2946 int i;
2947 MonoClass *ic;
2948
2949 mono_class_setup_interfaces (klass, error);
2950 return_if_nok (error);
2951
2952 for (i = 0; i < klass->interface_count; i++) {
2953 ic = klass->interfaces [i];
2954
2955 if (*res == NULL)
2956 *res = g_ptr_array_new ();
2957 if (*ifaces == NULL)
2958 *ifaces = g_hash_table_new (NULL, NULL);
2959 if (g_hash_table_lookup (*ifaces, ic))
2960 continue;
2961 /* A gparam is not an implemented interface for the purposes of
2962 * mono_class_get_implemented_interfaces */
2963 if (mono_class_is_gparam (ic))
2964 continue;
2965 g_ptr_array_add (*res, ic);
2966 g_hash_table_insert (*ifaces, ic, ic);
2967 mono_class_init (ic);
2968 if (mono_class_has_failure (ic)) {
2969 mono_error_set_type_load_class (error, ic, "Error Loading class");
2970 return;
2971 }
2972
2973 collect_implemented_interfaces_aux (ic, res, ifaces, error);
2974 return_if_nok (error);
2975 }
2976 }
2977
2978 GPtrArray*
mono_class_get_implemented_interfaces(MonoClass * klass,MonoError * error)2979 mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error)
2980 {
2981 GPtrArray *res = NULL;
2982 GHashTable *ifaces = NULL;
2983
2984 collect_implemented_interfaces_aux (klass, &res, &ifaces, error);
2985 if (ifaces)
2986 g_hash_table_destroy (ifaces);
2987 if (!mono_error_ok (error)) {
2988 if (res)
2989 g_ptr_array_free (res, TRUE);
2990 return NULL;
2991 }
2992 return res;
2993 }
2994
2995 static int
compare_interface_ids(const void * p_key,const void * p_element)2996 compare_interface_ids (const void *p_key, const void *p_element)
2997 {
2998 const MonoClass *key = (const MonoClass *)p_key;
2999 const MonoClass *element = *(const MonoClass **)p_element;
3000
3001 return (key->interface_id - element->interface_id);
3002 }
3003
3004 /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/
3005 int
mono_class_interface_offset(MonoClass * klass,MonoClass * itf)3006 mono_class_interface_offset (MonoClass *klass, MonoClass *itf)
3007 {
3008 MonoClass **result = (MonoClass **)mono_binary_search (
3009 itf,
3010 klass->interfaces_packed,
3011 klass->interface_offsets_count,
3012 sizeof (MonoClass *),
3013 compare_interface_ids);
3014 if (result) {
3015 return klass->interface_offsets_packed [result - (klass->interfaces_packed)];
3016 } else {
3017 return -1;
3018 }
3019 }
3020
3021 /**
3022 * mono_class_interface_offset_with_variance:
3023 *
3024 * Return the interface offset of \p itf in \p klass. Sets \p non_exact_match to TRUE if the match required variance check
3025 * If \p itf is an interface with generic variant arguments, try to find the compatible one.
3026 *
3027 * Note that this function is responsible for resolving ambiguities. Right now we use whatever ordering interfaces_packed gives us.
3028 *
3029 * FIXME figure out MS disambiguation rules and fix this function.
3030 */
3031 int
mono_class_interface_offset_with_variance(MonoClass * klass,MonoClass * itf,gboolean * non_exact_match)3032 mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match)
3033 {
3034 int i = mono_class_interface_offset (klass, itf);
3035 *non_exact_match = FALSE;
3036 if (i >= 0)
3037 return i;
3038
3039 if (itf->is_array_special_interface && klass->rank < 2) {
3040 MonoClass *gtd = mono_class_get_generic_type_definition (itf);
3041
3042 for (i = 0; i < klass->interface_offsets_count; i++) {
3043 // printf ("\t%s\n", mono_type_get_full_name (klass->interfaces_packed [i]));
3044 if (mono_class_get_generic_type_definition (klass->interfaces_packed [i]) == gtd) {
3045 *non_exact_match = TRUE;
3046 return klass->interface_offsets_packed [i];
3047 }
3048 }
3049 }
3050
3051 if (!mono_class_has_variant_generic_params (itf))
3052 return -1;
3053
3054 for (i = 0; i < klass->interface_offsets_count; i++) {
3055 if (mono_class_is_variant_compatible (itf, klass->interfaces_packed [i], FALSE)) {
3056 *non_exact_match = TRUE;
3057 return klass->interface_offsets_packed [i];
3058 }
3059 }
3060
3061 return -1;
3062 }
3063
3064 static void
print_implemented_interfaces(MonoClass * klass)3065 print_implemented_interfaces (MonoClass *klass)
3066 {
3067 char *name;
3068 MonoError error;
3069 GPtrArray *ifaces = NULL;
3070 int i;
3071 int ancestor_level = 0;
3072
3073 name = mono_type_get_full_name (klass);
3074 printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
3075 g_free (name);
3076
3077 for (i = 0; i < klass->interface_offsets_count; i++)
3078 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
3079 klass->interfaces_packed [i]->interface_id,
3080 klass->interface_offsets_packed [i],
3081 mono_class_get_method_count (klass->interfaces_packed [i]),
3082 klass->interfaces_packed [i]->name_space,
3083 klass->interfaces_packed [i]->name );
3084 printf ("Interface flags: ");
3085 for (i = 0; i <= klass->max_interface_id; i++)
3086 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
3087 printf ("(%d,T)", i);
3088 else
3089 printf ("(%d,F)", i);
3090 printf ("\n");
3091 printf ("Dump interface flags:");
3092 #ifdef COMPRESSED_INTERFACE_BITMAP
3093 {
3094 const uint8_t* p = klass->interface_bitmap;
3095 i = klass->max_interface_id;
3096 while (i > 0) {
3097 printf (" %d x 00 %02X", p [0], p [1]);
3098 i -= p [0] * 8;
3099 i -= 8;
3100 }
3101 }
3102 #else
3103 for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
3104 printf (" %02X", klass->interface_bitmap [i]);
3105 #endif
3106 printf ("\n");
3107 while (klass != NULL) {
3108 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
3109 ifaces = mono_class_get_implemented_interfaces (klass, &error);
3110 if (!mono_error_ok (&error)) {
3111 printf (" Type failed due to %s\n", mono_error_get_message (&error));
3112 mono_error_cleanup (&error);
3113 } else if (ifaces) {
3114 for (i = 0; i < ifaces->len; i++) {
3115 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3116 printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
3117 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
3118 ic->interface_id,
3119 mono_class_interface_offset (klass, ic),
3120 mono_class_get_method_count (ic),
3121 ic->name_space,
3122 ic->name );
3123 }
3124 g_ptr_array_free (ifaces, TRUE);
3125 }
3126 ancestor_level ++;
3127 klass = klass->parent;
3128 }
3129 }
3130
3131 /*
3132 * Return the number of virtual methods.
3133 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
3134 * Return -1 on failure.
3135 * FIXME It would be nice if this information could be cached somewhere.
3136 */
3137 static int
count_virtual_methods(MonoClass * klass)3138 count_virtual_methods (MonoClass *klass)
3139 {
3140 int i, mcount, vcount = 0;
3141 guint32 flags;
3142 klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/
3143
3144 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
3145 mono_class_setup_methods (klass);
3146 if (mono_class_has_failure (klass))
3147 return -1;
3148
3149 mcount = mono_class_get_method_count (klass);
3150 for (i = 0; i < mcount; ++i) {
3151 flags = klass->methods [i]->flags;
3152 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3153 ++vcount;
3154 }
3155 } else {
3156 int first_idx = mono_class_get_first_method_idx (klass);
3157 mcount = mono_class_get_method_count (klass);
3158 for (i = 0; i < mcount; ++i) {
3159 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
3160
3161 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3162 ++vcount;
3163 }
3164 }
3165 return vcount;
3166 }
3167
3168 static int
find_interface(int num_ifaces,MonoClass ** interfaces_full,MonoClass * ic)3169 find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic)
3170 {
3171 int m, l = 0;
3172 if (!num_ifaces)
3173 return -1;
3174 while (1) {
3175 if (l > num_ifaces)
3176 return -1;
3177 m = (l + num_ifaces) / 2;
3178 if (interfaces_full [m] == ic)
3179 return m;
3180 if (l == num_ifaces)
3181 return -1;
3182 if (!interfaces_full [m] || interfaces_full [m]->interface_id > ic->interface_id) {
3183 num_ifaces = m - 1;
3184 } else {
3185 l = m + 1;
3186 }
3187 }
3188 }
3189
3190 static mono_bool
set_interface_and_offset(int num_ifaces,MonoClass ** interfaces_full,int * interface_offsets_full,MonoClass * ic,int offset,mono_bool force_set)3191 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
3192 {
3193 int i = find_interface (num_ifaces, interfaces_full, ic);
3194 if (i >= 0) {
3195 if (!force_set)
3196 return TRUE;
3197 interface_offsets_full [i] = offset;
3198 return FALSE;
3199 }
3200 for (i = 0; i < num_ifaces; ++i) {
3201 if (interfaces_full [i]) {
3202 int end;
3203 if (interfaces_full [i]->interface_id < ic->interface_id)
3204 continue;
3205 end = i + 1;
3206 while (end < num_ifaces && interfaces_full [end]) end++;
3207 memmove (interfaces_full + i + 1, interfaces_full + i, sizeof (MonoClass*) * (end - i));
3208 memmove (interface_offsets_full + i + 1, interface_offsets_full + i, sizeof (int) * (end - i));
3209 }
3210 interfaces_full [i] = ic;
3211 interface_offsets_full [i] = offset;
3212 break;
3213 }
3214 return FALSE;
3215 }
3216
3217 #ifdef COMPRESSED_INTERFACE_BITMAP
3218
3219 /*
3220 * Compressed interface bitmap design.
3221 *
3222 * Interface bitmaps take a large amount of memory, because their size is
3223 * linear with the maximum interface id assigned in the process (each interface
3224 * is assigned a unique id as it is loaded). The number of interface classes
3225 * is high because of the many implicit interfaces implemented by arrays (we'll
3226 * need to lazy-load them in the future).
3227 * Most classes implement a very small number of interfaces, so the bitmap is
3228 * sparse. This bitmap needs to be checked by interface casts, so access to the
3229 * needed bit must be fast and doable with few jit instructions.
3230 *
3231 * The current compression format is as follows:
3232 * *) it is a sequence of one or more two-byte elements
3233 * *) the first byte in the element is the count of empty bitmap bytes
3234 * at the current bitmap position
3235 * *) the second byte in the element is an actual bitmap byte at the current
3236 * bitmap position
3237 *
3238 * As an example, the following compressed bitmap bytes:
3239 * 0x07 0x01 0x00 0x7
3240 * correspond to the following bitmap:
3241 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
3242 *
3243 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
3244 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
3245 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
3246 */
3247
3248 /**
3249 * mono_compress_bitmap:
3250 * \param dest destination buffer
3251 * \param bitmap bitmap buffer
3252 * \param size size of \p bitmap in bytes
3253 *
3254 * This is a mono internal function.
3255 * The \p bitmap data is compressed into a format that is small but
3256 * still searchable in few instructions by the JIT and runtime.
3257 * The compressed data is stored in the buffer pointed to by the
3258 * \p dest array. Passing a NULL value for \p dest allows to just compute
3259 * the size of the buffer.
3260 * This compression algorithm assumes the bits set in the bitmap are
3261 * few and far between, like in interface bitmaps.
3262 * \returns The size of the compressed bitmap in bytes.
3263 */
3264 int
mono_compress_bitmap(uint8_t * dest,const uint8_t * bitmap,int size)3265 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
3266 {
3267 int numz = 0;
3268 int res = 0;
3269 const uint8_t *end = bitmap + size;
3270 while (bitmap < end) {
3271 if (*bitmap || numz == 255) {
3272 if (dest) {
3273 *dest++ = numz;
3274 *dest++ = *bitmap;
3275 }
3276 res += 2;
3277 numz = 0;
3278 bitmap++;
3279 continue;
3280 }
3281 bitmap++;
3282 numz++;
3283 }
3284 if (numz) {
3285 res += 2;
3286 if (dest) {
3287 *dest++ = numz;
3288 *dest++ = 0;
3289 }
3290 }
3291 return res;
3292 }
3293
3294 /**
3295 * mono_class_interface_match:
3296 * \param bitmap a compressed bitmap buffer
3297 * \param id the index to check in the bitmap
3298 *
3299 * This is a mono internal function.
3300 * Checks if a bit is set in a compressed interface bitmap. \p id must
3301 * be already checked for being smaller than the maximum id encoded in the
3302 * bitmap.
3303 *
3304 * \returns A non-zero value if bit \p id is set in the bitmap \p bitmap,
3305 * FALSE otherwise.
3306 */
3307 int
mono_class_interface_match(const uint8_t * bitmap,int id)3308 mono_class_interface_match (const uint8_t *bitmap, int id)
3309 {
3310 while (TRUE) {
3311 id -= bitmap [0] * 8;
3312 if (id < 8) {
3313 if (id < 0)
3314 return 0;
3315 return bitmap [1] & (1 << id);
3316 }
3317 bitmap += 2;
3318 id -= 8;
3319 }
3320 }
3321 #endif
3322
3323 /*
3324 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
3325 * LOCKING: Acquires the loader lock.
3326 */
3327 static int
setup_interface_offsets(MonoClass * klass,int cur_slot,gboolean overwrite)3328 setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
3329 {
3330 MonoError error;
3331 MonoClass *k, *ic;
3332 int i, j, num_ifaces;
3333 guint32 max_iid;
3334 MonoClass **interfaces_full = NULL;
3335 int *interface_offsets_full = NULL;
3336 GPtrArray *ifaces;
3337 GPtrArray **ifaces_array = NULL;
3338 int interface_offsets_count;
3339
3340 mono_loader_lock ();
3341
3342 mono_class_setup_supertypes (klass);
3343
3344 /* compute maximum number of slots and maximum interface id */
3345 max_iid = 0;
3346 num_ifaces = 0; /* this can include duplicated ones */
3347 ifaces_array = g_new0 (GPtrArray *, klass->idepth);
3348 for (j = 0; j < klass->idepth; j++) {
3349 k = klass->supertypes [j];
3350 g_assert (k);
3351 num_ifaces += k->interface_count;
3352 for (i = 0; i < k->interface_count; i++) {
3353 ic = k->interfaces [i];
3354
3355 /* A gparam does not have any interface_id set. */
3356 if (! mono_class_is_gparam (ic))
3357 mono_class_init (ic);
3358
3359 if (max_iid < ic->interface_id)
3360 max_iid = ic->interface_id;
3361 }
3362 ifaces = mono_class_get_implemented_interfaces (k, &error);
3363 if (!mono_error_ok (&error)) {
3364 char *name = mono_type_get_full_name (k);
3365 mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error));
3366 g_free (name);
3367 mono_error_cleanup (&error);
3368 cur_slot = -1;
3369 goto end;
3370 }
3371 if (ifaces) {
3372 num_ifaces += ifaces->len;
3373 for (i = 0; i < ifaces->len; ++i) {
3374 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3375 if (max_iid < ic->interface_id)
3376 max_iid = ic->interface_id;
3377 }
3378 ifaces_array [j] = ifaces;
3379 }
3380 }
3381
3382 if (MONO_CLASS_IS_INTERFACE (klass)) {
3383 num_ifaces++;
3384 if (max_iid < klass->interface_id)
3385 max_iid = klass->interface_id;
3386 }
3387
3388 /* compute vtable offset for interfaces */
3389 interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
3390 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
3391
3392 for (i = 0; i < num_ifaces; i++)
3393 interface_offsets_full [i] = -1;
3394
3395 /* skip the current class */
3396 for (j = 0; j < klass->idepth - 1; j++) {
3397 k = klass->supertypes [j];
3398 ifaces = ifaces_array [j];
3399
3400 if (ifaces) {
3401 for (i = 0; i < ifaces->len; ++i) {
3402 int io;
3403 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3404
3405 /*Force the sharing of interface offsets between parent and subtypes.*/
3406 io = mono_class_interface_offset (k, ic);
3407 g_assert (io >= 0);
3408 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
3409 }
3410 }
3411 }
3412
3413 g_assert (klass == klass->supertypes [klass->idepth - 1]);
3414 ifaces = ifaces_array [klass->idepth - 1];
3415 if (ifaces) {
3416 for (i = 0; i < ifaces->len; ++i) {
3417 int count;
3418 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3419 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
3420 continue;
3421 count = count_virtual_methods (ic);
3422 if (count == -1) {
3423 char *name = mono_type_get_full_name (ic);
3424 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
3425 g_free (name);
3426 cur_slot = -1;
3427 goto end;
3428 }
3429 cur_slot += count;
3430 }
3431 }
3432
3433 if (MONO_CLASS_IS_INTERFACE (klass))
3434 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE);
3435
3436 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
3437 if (interface_offsets_full [i] != -1)
3438 interface_offsets_count ++;
3439 }
3440
3441 /* Publish the data */
3442 klass->max_interface_id = max_iid;
3443 /*
3444 * We might get called multiple times:
3445 * - mono_class_init ()
3446 * - mono_class_setup_vtable ().
3447 * - mono_class_setup_interface_offsets ().
3448 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
3449 * means we have to overwrite those when called from other places (#4440).
3450 */
3451 if (klass->interfaces_packed) {
3452 if (!overwrite)
3453 g_assert (klass->interface_offsets_count == interface_offsets_count);
3454 } else {
3455 uint8_t *bitmap;
3456 int bsize;
3457 klass->interface_offsets_count = interface_offsets_count;
3458 klass->interfaces_packed = (MonoClass **)mono_class_alloc (klass, sizeof (MonoClass*) * interface_offsets_count);
3459 klass->interface_offsets_packed = (guint16 *)mono_class_alloc (klass, sizeof (guint16) * interface_offsets_count);
3460 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
3461 #ifdef COMPRESSED_INTERFACE_BITMAP
3462 bitmap = g_malloc0 (bsize);
3463 #else
3464 bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
3465 #endif
3466 for (i = 0; i < interface_offsets_count; i++) {
3467 guint32 id = interfaces_full [i]->interface_id;
3468 bitmap [id >> 3] |= (1 << (id & 7));
3469 klass->interfaces_packed [i] = interfaces_full [i];
3470 klass->interface_offsets_packed [i] = interface_offsets_full [i];
3471 }
3472 #ifdef COMPRESSED_INTERFACE_BITMAP
3473 i = mono_compress_bitmap (NULL, bitmap, bsize);
3474 klass->interface_bitmap = mono_class_alloc0 (klass, i);
3475 mono_compress_bitmap (klass->interface_bitmap, bitmap, bsize);
3476 g_free (bitmap);
3477 #else
3478 klass->interface_bitmap = bitmap;
3479 #endif
3480 }
3481 end:
3482 mono_loader_unlock ();
3483
3484 g_free (interfaces_full);
3485 g_free (interface_offsets_full);
3486 for (i = 0; i < klass->idepth; i++) {
3487 ifaces = ifaces_array [i];
3488 if (ifaces)
3489 g_ptr_array_free (ifaces, TRUE);
3490 }
3491 g_free (ifaces_array);
3492
3493 //printf ("JUST DONE: ");
3494 //print_implemented_interfaces (klass);
3495
3496 return cur_slot;
3497 }
3498
3499 /*
3500 * Setup interface offsets for interfaces.
3501 * Initializes:
3502 * - klass->max_interface_id
3503 * - klass->interface_offsets_count
3504 * - klass->interfaces_packed
3505 * - klass->interface_offsets_packed
3506 * - klass->interface_bitmap
3507 *
3508 * This function can fail @class.
3509 *
3510 */
3511 void
mono_class_setup_interface_offsets(MonoClass * klass)3512 mono_class_setup_interface_offsets (MonoClass *klass)
3513 {
3514 /* NOTE: This function is only correct for interfaces.
3515 *
3516 * It assumes that klass's interfaces can be assigned offsets starting
3517 * from 0. That assumption is incorrect for classes and valuetypes.
3518 */
3519 g_assert (MONO_CLASS_IS_INTERFACE (klass) && !mono_class_is_ginst (klass));
3520 setup_interface_offsets (klass, 0, FALSE);
3521 }
3522
3523 /*Checks if @klass has @parent as one of it's parents type gtd
3524 *
3525 * For example:
3526 * Foo<T>
3527 * Bar<T> : Foo<Bar<Bar<T>>>
3528 *
3529 */
3530 static gboolean
mono_class_has_gtd_parent(MonoClass * klass,MonoClass * parent)3531 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
3532 {
3533 klass = mono_class_get_generic_type_definition (klass);
3534 parent = mono_class_get_generic_type_definition (parent);
3535 mono_class_setup_supertypes (klass);
3536 mono_class_setup_supertypes (parent);
3537
3538 return klass->idepth >= parent->idepth &&
3539 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
3540 }
3541
3542 gboolean
mono_class_check_vtable_constraints(MonoClass * klass,GList * in_setup)3543 mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
3544 {
3545 MonoGenericInst *ginst;
3546 int i;
3547
3548 if (!mono_class_is_ginst (klass)) {
3549 mono_class_setup_vtable_full (klass, in_setup);
3550 return !mono_class_has_failure (klass);
3551 }
3552
3553 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
3554 if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
3555 return FALSE;
3556
3557 ginst = mono_class_get_generic_class (klass)->context.class_inst;
3558 for (i = 0; i < ginst->type_argc; ++i) {
3559 MonoClass *arg;
3560 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
3561 continue;
3562 arg = mono_class_from_mono_type (ginst->type_argv [i]);
3563 /*Those 2 will be checked by mono_class_setup_vtable itself*/
3564 if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
3565 continue;
3566 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
3567 mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
3568 return FALSE;
3569 }
3570 }
3571 return TRUE;
3572 }
3573
3574 /*
3575 * mono_class_setup_vtable:
3576 *
3577 * Creates the generic vtable of CLASS.
3578 * Initializes the following fields in MonoClass:
3579 * - vtable
3580 * - vtable_size
3581 * Plus all the fields initialized by setup_interface_offsets ().
3582 * If there is an error during vtable construction, klass->has_failure
3583 * is set and details are stored in a MonoErrorBoxed.
3584 *
3585 * LOCKING: Acquires the loader lock.
3586 */
3587 void
mono_class_setup_vtable(MonoClass * klass)3588 mono_class_setup_vtable (MonoClass *klass)
3589 {
3590 mono_class_setup_vtable_full (klass, NULL);
3591 }
3592
3593 static void
mono_class_setup_vtable_full(MonoClass * klass,GList * in_setup)3594 mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
3595 {
3596 MonoError error;
3597 MonoMethod **overrides;
3598 MonoGenericContext *context;
3599 guint32 type_token;
3600 int onum = 0;
3601 gboolean ok = TRUE;
3602
3603 if (klass->vtable)
3604 return;
3605
3606 if (MONO_CLASS_IS_INTERFACE (klass)) {
3607 /* This sets method->slot for all methods if this is an interface */
3608 mono_class_setup_methods (klass);
3609 return;
3610 }
3611
3612 if (mono_class_has_failure (klass))
3613 return;
3614
3615 if (g_list_find (in_setup, klass))
3616 return;
3617
3618 mono_loader_lock ();
3619
3620 if (klass->vtable) {
3621 mono_loader_unlock ();
3622 return;
3623 }
3624
3625 UnlockedIncrement (&mono_stats.generic_vtable_count);
3626 in_setup = g_list_prepend (in_setup, klass);
3627
3628 if (mono_class_is_ginst (klass)) {
3629 if (!mono_class_check_vtable_constraints (klass, in_setup)) {
3630 mono_loader_unlock ();
3631 g_list_remove (in_setup, klass);
3632 return;
3633 }
3634
3635 context = mono_class_get_context (klass);
3636 type_token = mono_class_get_generic_class (klass)->container_class->type_token;
3637 } else {
3638 context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
3639 type_token = klass->type_token;
3640 }
3641
3642 if (image_is_dynamic (klass->image)) {
3643 /* Generic instances can have zero method overrides without causing any harm.
3644 * This is true since we don't do layout all over again for them, we simply inflate
3645 * the layout of the parent.
3646 */
3647 mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, &error);
3648 if (!is_ok (&error)) {
3649 mono_loader_unlock ();
3650 g_list_remove (in_setup, klass);
3651 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (&error));
3652 mono_error_cleanup (&error);
3653 return;
3654 }
3655 } else {
3656 /* The following call fails if there are missing methods in the type */
3657 /* FIXME it's probably a good idea to avoid this for generic instances. */
3658 ok = mono_class_get_overrides_full (klass->image, type_token, &overrides, &onum, context);
3659 }
3660
3661 if (ok)
3662 mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
3663 else
3664 mono_class_set_type_load_failure (klass, "Could not load list of method overrides");
3665
3666 g_free (overrides);
3667
3668 mono_loader_unlock ();
3669 g_list_remove (in_setup, klass);
3670
3671 return;
3672 }
3673
3674 #define DEBUG_INTERFACE_VTABLE_CODE 0
3675 #define TRACE_INTERFACE_VTABLE_CODE 0
3676 #define VERIFY_INTERFACE_VTABLE_CODE 0
3677 #define VTABLE_SELECTOR (1)
3678
3679 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3680 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
3681 if (!(VTABLE_SELECTOR)) break; \
3682 stmt;\
3683 } while (0)
3684 #else
3685 #define DEBUG_INTERFACE_VTABLE(stmt)
3686 #endif
3687
3688 #if TRACE_INTERFACE_VTABLE_CODE
3689 #define TRACE_INTERFACE_VTABLE(stmt) do {\
3690 if (!(VTABLE_SELECTOR)) break; \
3691 stmt;\
3692 } while (0)
3693 #else
3694 #define TRACE_INTERFACE_VTABLE(stmt)
3695 #endif
3696
3697 #if VERIFY_INTERFACE_VTABLE_CODE
3698 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
3699 if (!(VTABLE_SELECTOR)) break; \
3700 stmt;\
3701 } while (0)
3702 #else
3703 #define VERIFY_INTERFACE_VTABLE(stmt)
3704 #endif
3705
3706
3707 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3708 static char*
mono_signature_get_full_desc(MonoMethodSignature * sig,gboolean include_namespace)3709 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
3710 {
3711 int i;
3712 char *result;
3713 GString *res = g_string_new ("");
3714
3715 g_string_append_c (res, '(');
3716 for (i = 0; i < sig->param_count; ++i) {
3717 if (i > 0)
3718 g_string_append_c (res, ',');
3719 mono_type_get_desc (res, sig->params [i], include_namespace);
3720 }
3721 g_string_append (res, ")=>");
3722 if (sig->ret != NULL) {
3723 mono_type_get_desc (res, sig->ret, include_namespace);
3724 } else {
3725 g_string_append (res, "NULL");
3726 }
3727 result = res->str;
3728 g_string_free (res, FALSE);
3729 return result;
3730 }
3731 static void
print_method_signatures(MonoMethod * im,MonoMethod * cm)3732 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
3733 char *im_sig = mono_signature_get_full_desc (mono_method_signature (im), TRUE);
3734 char *cm_sig = mono_signature_get_full_desc (mono_method_signature (cm), TRUE);
3735 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
3736 g_free (im_sig);
3737 g_free (cm_sig);
3738
3739 }
3740
3741 #endif
3742 static gboolean
is_wcf_hack_disabled(void)3743 is_wcf_hack_disabled (void)
3744 {
3745 static gboolean disabled;
3746 static gboolean inited = FALSE;
3747 if (!inited) {
3748 disabled = g_hasenv ("MONO_DISABLE_WCF_HACK");
3749 inited = TRUE;
3750 }
3751 return disabled;
3752 }
3753
3754 static gboolean
check_interface_method_override(MonoClass * klass,MonoMethod * im,MonoMethod * cm,gboolean require_newslot,gboolean interface_is_explicitly_implemented_by_class,gboolean slot_is_empty)3755 check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty)
3756 {
3757 MonoMethodSignature *cmsig, *imsig;
3758 if (strcmp (im->name, cm->name) == 0) {
3759 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
3760 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
3761 return FALSE;
3762 }
3763 if (! slot_is_empty) {
3764 if (require_newslot) {
3765 if (! interface_is_explicitly_implemented_by_class) {
3766 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
3767 return FALSE;
3768 }
3769 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
3770 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
3771 return FALSE;
3772 }
3773 } else {
3774 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
3775 }
3776 }
3777 cmsig = mono_method_signature (cm);
3778 imsig = mono_method_signature (im);
3779 if (!cmsig || !imsig) {
3780 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
3781 return FALSE;
3782 }
3783
3784 if (! mono_metadata_signature_equal (cmsig, imsig)) {
3785 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
3786 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
3787 TRACE_INTERFACE_VTABLE (printf ("]"));
3788 return FALSE;
3789 }
3790 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
3791 if (mono_security_core_clr_enabled ())
3792 mono_security_core_clr_check_override (klass, cm, im);
3793
3794 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
3795 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
3796 char *body_name = mono_method_full_name (cm, TRUE);
3797 char *decl_name = mono_method_full_name (im, TRUE);
3798 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
3799 g_free (body_name);
3800 g_free (decl_name);
3801 return FALSE;
3802 }
3803
3804 return TRUE;
3805 } else {
3806 MonoClass *ic = im->klass;
3807 const char *ic_name_space = ic->name_space;
3808 const char *ic_name = ic->name;
3809 char *subname;
3810
3811 if (! require_newslot) {
3812 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
3813 return FALSE;
3814 }
3815 if (cm->klass->rank == 0) {
3816 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
3817 return FALSE;
3818 }
3819 cmsig = mono_method_signature (cm);
3820 imsig = mono_method_signature (im);
3821 if (!cmsig || !imsig) {
3822 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
3823 return FALSE;
3824 }
3825
3826 if (! mono_metadata_signature_equal (cmsig, imsig)) {
3827 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
3828 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
3829 TRACE_INTERFACE_VTABLE (printf ("]"));
3830 return FALSE;
3831 }
3832 if (mono_class_get_image (ic) != mono_defaults.corlib) {
3833 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
3834 return FALSE;
3835 }
3836 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
3837 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
3838 return FALSE;
3839 }
3840 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))) {
3841 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
3842 return FALSE;
3843 }
3844
3845 subname = strstr (cm->name, ic_name_space);
3846 if (subname != cm->name) {
3847 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
3848 return FALSE;
3849 }
3850 subname += strlen (ic_name_space);
3851 if (subname [0] != '.') {
3852 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
3853 return FALSE;
3854 }
3855 subname ++;
3856 if (strstr (subname, ic_name) != subname) {
3857 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
3858 return FALSE;
3859 }
3860 subname += strlen (ic_name);
3861 if (subname [0] != '.') {
3862 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
3863 return FALSE;
3864 }
3865 subname ++;
3866 if (strcmp (subname, im->name) != 0) {
3867 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
3868 return FALSE;
3869 }
3870
3871 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
3872 if (mono_security_core_clr_enabled ())
3873 mono_security_core_clr_check_override (klass, cm, im);
3874
3875 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
3876 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
3877 char *body_name = mono_method_full_name (cm, TRUE);
3878 char *decl_name = mono_method_full_name (im, TRUE);
3879 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
3880 g_free (body_name);
3881 g_free (decl_name);
3882 return FALSE;
3883 }
3884
3885 return TRUE;
3886 }
3887 }
3888
3889 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3890 static void
foreach_override(gpointer key,gpointer value,gpointer user_data)3891 foreach_override (gpointer key, gpointer value, gpointer user_data) {
3892 MonoMethod *method = key;
3893 MonoMethod *override = value;
3894 MonoClass *method_class = mono_method_get_class (method);
3895 MonoClass *override_class = mono_method_get_class (override);
3896
3897 printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
3898 mono_class_get_namespace (method_class), mono_class_get_name (method_class), mono_method_get_name (method),
3899 mono_class_get_namespace (override_class), mono_class_get_name (override_class), mono_method_get_name (override));
3900 }
3901 static void
print_overrides(GHashTable * override_map,const char * message)3902 print_overrides (GHashTable *override_map, const char *message) {
3903 if (override_map) {
3904 printf ("Override map \"%s\" START:\n", message);
3905 g_hash_table_foreach (override_map, foreach_override, NULL);
3906 printf ("Override map \"%s\" END.\n", message);
3907 } else {
3908 printf ("Override map \"%s\" EMPTY.\n", message);
3909 }
3910 }
3911 static void
print_vtable_full(MonoClass * klass,MonoMethod ** vtable,int size,int first_non_interface_slot,const char * message,gboolean print_interfaces)3912 print_vtable_full (MonoClass *klass, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
3913 char *full_name = mono_type_full_name (&klass->byval_arg);
3914 int i;
3915 int parent_size;
3916
3917 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
3918
3919 if (print_interfaces) {
3920 print_implemented_interfaces (klass);
3921 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
3922 }
3923
3924 if (klass->parent) {
3925 parent_size = klass->parent->vtable_size;
3926 } else {
3927 parent_size = 0;
3928 }
3929 for (i = 0; i < size; ++i) {
3930 MonoMethod *cm = vtable [i];
3931 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
3932 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
3933
3934 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
3935 g_free (cm_name);
3936 }
3937
3938 g_free (full_name);
3939 }
3940 #endif
3941
3942 #if VERIFY_INTERFACE_VTABLE_CODE
3943 static int
mono_method_try_get_vtable_index(MonoMethod * method)3944 mono_method_try_get_vtable_index (MonoMethod *method)
3945 {
3946 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
3947 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
3948 if (imethod->declaring->is_generic)
3949 return imethod->declaring->slot;
3950 }
3951 return method->slot;
3952 }
3953
3954 static void
mono_class_verify_vtable(MonoClass * klass)3955 mono_class_verify_vtable (MonoClass *klass)
3956 {
3957 int i, count;
3958 char *full_name = mono_type_full_name (&klass->byval_arg);
3959
3960 printf ("*** Verifying VTable of class '%s' \n", full_name);
3961 g_free (full_name);
3962 full_name = NULL;
3963
3964 if (!klass->methods)
3965 return;
3966
3967 count = mono_class_get_method_count (klass);
3968 for (i = 0; i < count; ++i) {
3969 MonoMethod *cm = klass->methods [i];
3970 int slot;
3971
3972 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
3973 continue;
3974
3975 g_free (full_name);
3976 full_name = mono_method_full_name (cm, TRUE);
3977
3978 slot = mono_method_try_get_vtable_index (cm);
3979 if (slot >= 0) {
3980 if (slot >= klass->vtable_size) {
3981 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, klass->vtable_size);
3982 continue;
3983 }
3984
3985 if (slot >= 0 && klass->vtable [slot] != cm && (klass->vtable [slot])) {
3986 char *other_name = klass->vtable [slot] ? mono_method_full_name (klass->vtable [slot], TRUE) : g_strdup ("[null value]");
3987 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
3988 g_free (other_name);
3989 }
3990 } else
3991 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
3992 }
3993 g_free (full_name);
3994 }
3995 #endif
3996
3997 static void
print_unimplemented_interface_method_info(MonoClass * klass,MonoClass * ic,MonoMethod * im,int im_slot,MonoMethod ** overrides,int onum)3998 print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum)
3999 {
4000 int index, mcount;
4001 char *method_signature;
4002 char *type_name;
4003
4004 for (index = 0; index < onum; ++index) {
4005 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)", im_slot, overrides [index*2+1]->name,
4006 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
4007 }
4008 method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
4009 type_name = mono_type_full_name (&klass->byval_arg);
4010 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s",
4011 mono_type_get_name (&ic->byval_arg), im->name, method_signature, type_name);
4012 g_free (method_signature);
4013 g_free (type_name);
4014 mono_class_setup_methods (klass);
4015 if (mono_class_has_failure (klass)) {
4016 char *name = mono_type_get_full_name (klass);
4017 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods", name);
4018 g_free (name);
4019 return;
4020 }
4021 mcount = mono_class_get_method_count (klass);
4022 for (index = 0; index < mcount; ++index) {
4023 MonoMethod *cm = klass->methods [index];
4024 method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
4025
4026 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)", cm->name, method_signature);
4027 g_free (method_signature);
4028 }
4029 }
4030
4031 static MonoMethod*
mono_method_get_method_definition(MonoMethod * method)4032 mono_method_get_method_definition (MonoMethod *method)
4033 {
4034 while (method->is_inflated)
4035 method = ((MonoMethodInflated*)method)->declaring;
4036 return method;
4037 }
4038
4039 static gboolean
verify_class_overrides(MonoClass * klass,MonoMethod ** overrides,int onum)4040 verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
4041 {
4042 int i;
4043
4044 for (i = 0; i < onum; ++i) {
4045 MonoMethod *decl = overrides [i * 2];
4046 MonoMethod *body = overrides [i * 2 + 1];
4047
4048 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
4049 mono_class_set_type_load_failure (klass, "Method belongs to a different class than the declared one");
4050 return FALSE;
4051 }
4052
4053 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
4054 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4055 mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
4056 else
4057 mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
4058 return FALSE;
4059 }
4060
4061 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
4062 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4063 mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
4064 else
4065 mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
4066 return FALSE;
4067 }
4068
4069 if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
4070 mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
4071 return FALSE;
4072 }
4073
4074 body = mono_method_get_method_definition (body);
4075 decl = mono_method_get_method_definition (decl);
4076
4077 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
4078 char *body_name = mono_method_full_name (body, TRUE);
4079 char *decl_name = mono_method_full_name (decl, TRUE);
4080 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4081 g_free (body_name);
4082 g_free (decl_name);
4083 return FALSE;
4084 }
4085 }
4086 return TRUE;
4087 }
4088
4089 static gboolean
mono_class_need_stelemref_method(MonoClass * klass)4090 mono_class_need_stelemref_method (MonoClass *klass)
4091 {
4092 return klass->rank == 1 && MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg);
4093 }
4094
4095 static int
apply_override(MonoClass * klass,MonoMethod ** vtable,MonoMethod * decl,MonoMethod * override)4096 apply_override (MonoClass *klass, MonoMethod **vtable, MonoMethod *decl, MonoMethod *override)
4097 {
4098 int dslot;
4099 dslot = mono_method_get_vtable_slot (decl);
4100 if (dslot == -1) {
4101 mono_class_set_type_load_failure (klass, "");
4102 return FALSE;
4103 }
4104
4105 dslot += mono_class_interface_offset (klass, decl->klass);
4106 vtable [dslot] = override;
4107 if (!MONO_CLASS_IS_INTERFACE (override->klass)) {
4108 /*
4109 * If override from an interface, then it is an override of a default interface method,
4110 * don't override its slot.
4111 */
4112 vtable [dslot]->slot = dslot;
4113 }
4114
4115 if (mono_security_core_clr_enabled ())
4116 mono_security_core_clr_check_override (klass, vtable [dslot], decl);
4117
4118 return TRUE;
4119 }
4120
4121 /*
4122 * LOCKING: this is supposed to be called with the loader lock held.
4123 */
4124 void
mono_class_setup_vtable_general(MonoClass * klass,MonoMethod ** overrides,int onum,GList * in_setup)4125 mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup)
4126 {
4127 MonoError error;
4128 MonoClass *k, *ic;
4129 MonoMethod **vtable = NULL;
4130 int i, max_vtsize = 0, cur_slot = 0;
4131 guint32 max_iid;
4132 GPtrArray *ifaces = NULL;
4133 GHashTable *override_map = NULL;
4134 MonoMethod *cm;
4135 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
4136 int first_non_interface_slot;
4137 #endif
4138 GSList *virt_methods = NULL, *l;
4139 int stelemref_slot = 0;
4140
4141 if (klass->vtable)
4142 return;
4143
4144 if (overrides && !verify_class_overrides (klass, overrides, onum))
4145 return;
4146
4147 ifaces = mono_class_get_implemented_interfaces (klass, &error);
4148 if (!mono_error_ok (&error)) {
4149 char *name = mono_type_get_full_name (klass);
4150 mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error));
4151 g_free (name);
4152 mono_error_cleanup (&error);
4153 return;
4154 } else if (ifaces) {
4155 for (i = 0; i < ifaces->len; i++) {
4156 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
4157 max_vtsize += mono_class_get_method_count (ic);
4158 }
4159 g_ptr_array_free (ifaces, TRUE);
4160 ifaces = NULL;
4161 }
4162
4163 if (klass->parent) {
4164 mono_class_init (klass->parent);
4165 mono_class_setup_vtable_full (klass->parent, in_setup);
4166
4167 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
4168 return;
4169
4170 max_vtsize += klass->parent->vtable_size;
4171 cur_slot = klass->parent->vtable_size;
4172 }
4173
4174 max_vtsize += mono_class_get_method_count (klass);
4175
4176 /*Array have a slot for stelemref*/
4177 if (mono_class_need_stelemref_method (klass)) {
4178 stelemref_slot = cur_slot;
4179 ++max_vtsize;
4180 ++cur_slot;
4181 }
4182
4183 /* printf ("METAINIT %s.%s\n", klass->name_space, klass->name); */
4184
4185 cur_slot = setup_interface_offsets (klass, cur_slot, TRUE);
4186 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
4187 return;
4188
4189 max_iid = klass->max_interface_id;
4190 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
4191
4192 /* Optimized version for generic instances */
4193 if (mono_class_is_ginst (klass)) {
4194 MonoError error;
4195 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4196 MonoMethod **tmp;
4197
4198 mono_class_setup_vtable_full (gklass, in_setup);
4199 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
4200 return;
4201
4202 tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
4203 klass->vtable_size = gklass->vtable_size;
4204 for (i = 0; i < gklass->vtable_size; ++i)
4205 if (gklass->vtable [i]) {
4206 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), &error);
4207 if (!mono_error_ok (&error)) {
4208 mono_class_set_type_load_failure (klass, "Could not inflate method due to %s", mono_error_get_message (&error));
4209 mono_error_cleanup (&error);
4210 return;
4211 }
4212 tmp [i] = inflated;
4213 tmp [i]->slot = gklass->vtable [i]->slot;
4214 }
4215 mono_memory_barrier ();
4216 klass->vtable = tmp;
4217
4218 /* Have to set method->slot for abstract virtual methods */
4219 if (klass->methods && gklass->methods) {
4220 int mcount = mono_class_get_method_count (klass);
4221 for (i = 0; i < mcount; ++i)
4222 if (klass->methods [i]->slot == -1)
4223 klass->methods [i]->slot = gklass->methods [i]->slot;
4224 }
4225
4226 return;
4227 }
4228
4229 vtable = (MonoMethod **)g_malloc0 (sizeof (gpointer) * max_vtsize);
4230
4231 if (klass->parent && klass->parent->vtable_size) {
4232 MonoClass *parent = klass->parent;
4233 int i;
4234
4235 memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
4236
4237 // Also inherit parent interface vtables, just as a starting point.
4238 // This is needed otherwise bug-77127.exe fails when the property methods
4239 // have different names in the iterface and the class, because for child
4240 // classes the ".override" information is not used anymore.
4241 for (i = 0; i < parent->interface_offsets_count; i++) {
4242 MonoClass *parent_interface = parent->interfaces_packed [i];
4243 int interface_offset = mono_class_interface_offset (klass, parent_interface);
4244 /*FIXME this is now dead code as this condition will never hold true.
4245 Since interface offsets are inherited then the offset of an interface implemented
4246 by a parent will never be the out of it's vtable boundary.
4247 */
4248 if (interface_offset >= parent->vtable_size) {
4249 int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
4250 int j;
4251
4252 mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
4253 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
4254 int mcount = mono_class_get_method_count (parent_interface);
4255 for (j = 0; j < mcount && !mono_class_has_failure (klass); j++) {
4256 vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
4257 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
4258 parent_interface_offset + j, parent_interface_offset, j,
4259 interface_offset + j, interface_offset, j));
4260 }
4261 }
4262
4263 }
4264 }
4265
4266 /*Array have a slot for stelemref*/
4267 if (mono_class_need_stelemref_method (klass)) {
4268 MonoMethod *method = mono_marshal_get_virtual_stelemref (klass);
4269 if (!method->slot)
4270 method->slot = stelemref_slot;
4271 else
4272 g_assert (method->slot == stelemref_slot);
4273
4274 vtable [stelemref_slot] = method;
4275 }
4276
4277 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
4278
4279 /* Process overrides from interface default methods */
4280 // FIXME: Ordering between interfaces
4281 for (int ifindex = 0; ifindex < klass->interface_offsets_count; ifindex++) {
4282 ic = klass->interfaces_packed [ifindex];
4283
4284 mono_class_setup_methods (ic);
4285 if (mono_class_has_failure (ic))
4286 goto fail;
4287
4288 MonoMethod **iface_overrides;
4289 int iface_onum;
4290 gboolean ok = mono_class_get_overrides_full (ic->image, ic->type_token, &iface_overrides, &iface_onum, mono_class_get_context (ic));
4291 if (ok) {
4292 for (int i = 0; i < iface_onum; i++) {
4293 MonoMethod *decl = iface_overrides [i*2];
4294 MonoMethod *override = iface_overrides [i*2 + 1];
4295 if (!apply_override (klass, vtable, decl, override))
4296 goto fail;
4297
4298 if (!override_map)
4299 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4300 g_hash_table_insert (override_map, decl, override);
4301 }
4302 g_free (iface_overrides);
4303 }
4304 }
4305
4306 /* override interface methods */
4307 for (i = 0; i < onum; i++) {
4308 MonoMethod *decl = overrides [i*2];
4309 MonoMethod *override = overrides [i*2 + 1];
4310 if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
4311 if (!apply_override (klass, vtable, decl, override))
4312 goto fail;
4313
4314 if (!override_map)
4315 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4316 g_hash_table_insert (override_map, decl, override);
4317 }
4318 }
4319
4320 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
4321 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
4322
4323 /*
4324 * Create a list of virtual methods to avoid calling
4325 * mono_class_get_virtual_methods () which is slow because of the metadata
4326 * optimization.
4327 */
4328 {
4329 gpointer iter = NULL;
4330 MonoMethod *cm;
4331
4332 virt_methods = NULL;
4333 while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
4334 virt_methods = g_slist_prepend (virt_methods, cm);
4335 }
4336 if (mono_class_has_failure (klass))
4337 goto fail;
4338 }
4339
4340 // Loop on all implemented interfaces...
4341 for (i = 0; i < klass->interface_offsets_count; i++) {
4342 MonoClass *parent = klass->parent;
4343 int ic_offset;
4344 gboolean interface_is_explicitly_implemented_by_class;
4345 int im_index;
4346
4347 ic = klass->interfaces_packed [i];
4348 ic_offset = mono_class_interface_offset (klass, ic);
4349
4350 mono_class_setup_methods (ic);
4351 if (mono_class_has_failure (ic))
4352 goto fail;
4353
4354 // Check if this interface is explicitly implemented (instead of just inherited)
4355 if (parent != NULL) {
4356 int implemented_interfaces_index;
4357 interface_is_explicitly_implemented_by_class = FALSE;
4358 for (implemented_interfaces_index = 0; implemented_interfaces_index < klass->interface_count; implemented_interfaces_index++) {
4359 if (ic == klass->interfaces [implemented_interfaces_index]) {
4360 interface_is_explicitly_implemented_by_class = TRUE;
4361 break;
4362 }
4363 }
4364 } else {
4365 interface_is_explicitly_implemented_by_class = TRUE;
4366 }
4367
4368 // Loop on all interface methods...
4369 int mcount = mono_class_get_method_count (ic);
4370 for (im_index = 0; im_index < mcount; im_index++) {
4371 MonoMethod *im = ic->methods [im_index];
4372 int im_slot = ic_offset + im->slot;
4373 MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL;
4374
4375 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4376 continue;
4377
4378 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
4379
4380 // If there is an explicit implementation, just use it right away,
4381 // otherwise look for a matching method
4382 if (override_im == NULL) {
4383 int cm_index;
4384 MonoMethod *cm;
4385
4386 // First look for a suitable method among the class methods
4387 for (l = virt_methods; l; l = l->next) {
4388 cm = (MonoMethod *)l->data;
4389 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)));
4390 if (check_interface_method_override (klass, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
4391 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
4392 vtable [im_slot] = cm;
4393 /* Why do we need this? */
4394 if (cm->slot < 0) {
4395 cm->slot = im_slot;
4396 }
4397 }
4398 TRACE_INTERFACE_VTABLE (printf ("\n"));
4399 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
4400 goto fail;
4401 }
4402
4403 // If the slot is still empty, look in all the inherited virtual methods...
4404 if ((vtable [im_slot] == NULL) && klass->parent != NULL) {
4405 MonoClass *parent = klass->parent;
4406 // Reverse order, so that last added methods are preferred
4407 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
4408 MonoMethod *cm = parent->vtable [cm_index];
4409
4410 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));
4411 if ((cm != NULL) && check_interface_method_override (klass, im, cm, FALSE, FALSE, TRUE)) {
4412 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
4413 vtable [im_slot] = cm;
4414 /* Why do we need this? */
4415 if (cm->slot < 0) {
4416 cm->slot = im_slot;
4417 }
4418 break;
4419 }
4420 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
4421 goto fail;
4422 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
4423 }
4424 }
4425
4426 if (vtable [im_slot] == NULL) {
4427 if (!(im->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
4428 TRACE_INTERFACE_VTABLE (printf (" Using default iface method %s.\n", mono_method_full_name (im, 1)));
4429 vtable [im_slot] = im;
4430 }
4431 }
4432 } else {
4433 g_assert (vtable [im_slot] == override_im);
4434 }
4435 }
4436 }
4437
4438 // If the class is not abstract, check that all its interface slots are full.
4439 // The check is done here and not directly at the end of the loop above because
4440 // it can happen (for injected generic array interfaces) that the same slot is
4441 // processed multiple times (those interfaces have overlapping slots), and it
4442 // will not always be the first pass the one that fills the slot.
4443 if (!mono_class_is_abstract (klass)) {
4444 for (i = 0; i < klass->interface_offsets_count; i++) {
4445 int ic_offset;
4446 int im_index;
4447
4448 ic = klass->interfaces_packed [i];
4449 ic_offset = mono_class_interface_offset (klass, ic);
4450
4451 int mcount = mono_class_get_method_count (ic);
4452 for (im_index = 0; im_index < mcount; im_index++) {
4453 MonoMethod *im = ic->methods [im_index];
4454 int im_slot = ic_offset + im->slot;
4455
4456 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4457 continue;
4458
4459 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
4460 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
4461 if (vtable [im_slot] == NULL) {
4462 print_unimplemented_interface_method_info (klass, ic, im, im_slot, overrides, onum);
4463 goto fail;
4464 }
4465 }
4466 }
4467 }
4468
4469 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
4470 for (l = virt_methods; l; l = l->next) {
4471 cm = (MonoMethod *)l->data;
4472 /*
4473 * If the method is REUSE_SLOT, we must check in the
4474 * base class for a method to override.
4475 */
4476 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
4477 int slot = -1;
4478 for (k = klass->parent; k ; k = k->parent) {
4479 gpointer k_iter;
4480 MonoMethod *m1;
4481
4482 k_iter = NULL;
4483 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
4484 MonoMethodSignature *cmsig, *m1sig;
4485
4486 cmsig = mono_method_signature (cm);
4487 m1sig = mono_method_signature (m1);
4488
4489 if (!cmsig || !m1sig) {
4490 /* FIXME proper error message */
4491 mono_class_set_type_load_failure (klass, "");
4492 return;
4493 }
4494
4495 if (!strcmp(cm->name, m1->name) &&
4496 mono_metadata_signature_equal (cmsig, m1sig)) {
4497
4498 if (mono_security_core_clr_enabled ())
4499 mono_security_core_clr_check_override (klass, cm, m1);
4500
4501 slot = mono_method_get_vtable_slot (m1);
4502 if (slot == -1)
4503 goto fail;
4504
4505 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
4506 char *body_name = mono_method_full_name (cm, TRUE);
4507 char *decl_name = mono_method_full_name (m1, TRUE);
4508 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4509 g_free (body_name);
4510 g_free (decl_name);
4511 goto fail;
4512 }
4513
4514 g_assert (cm->slot < max_vtsize);
4515 if (!override_map)
4516 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4517 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
4518 mono_method_full_name (m1, 1), m1,
4519 mono_method_full_name (cm, 1), cm));
4520 g_hash_table_insert (override_map, m1, cm);
4521 break;
4522 }
4523 }
4524 if (mono_class_has_failure (k))
4525 goto fail;
4526
4527 if (slot >= 0)
4528 break;
4529 }
4530 if (slot >= 0)
4531 cm->slot = slot;
4532 }
4533
4534 /*Non final newslot methods must be given a non-interface vtable slot*/
4535 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
4536 cm->slot = -1;
4537
4538 if (cm->slot < 0)
4539 cm->slot = cur_slot++;
4540
4541 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
4542 vtable [cm->slot] = cm;
4543 }
4544
4545 /* override non interface methods */
4546 for (i = 0; i < onum; i++) {
4547 MonoMethod *decl = overrides [i*2];
4548 if (!MONO_CLASS_IS_INTERFACE (decl->klass)) {
4549 g_assert (decl->slot != -1);
4550 vtable [decl->slot] = overrides [i*2 + 1];
4551 overrides [i * 2 + 1]->slot = decl->slot;
4552 if (!override_map)
4553 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4554 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
4555 mono_method_full_name (decl, 1), decl,
4556 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
4557 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
4558
4559 if (mono_security_core_clr_enabled ())
4560 mono_security_core_clr_check_override (klass, vtable [decl->slot], decl);
4561 }
4562 }
4563
4564 /*
4565 * If a method occupies more than one place in the vtable, and it is
4566 * overriden, then change the other occurances too.
4567 */
4568 if (override_map) {
4569 MonoMethod *cm;
4570
4571 for (i = 0; i < max_vtsize; ++i)
4572 if (vtable [i]) {
4573 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
4574
4575 cm = (MonoMethod *)g_hash_table_lookup (override_map, vtable [i]);
4576 if (cm)
4577 vtable [i] = cm;
4578 }
4579
4580 g_hash_table_destroy (override_map);
4581 override_map = NULL;
4582 }
4583
4584 g_slist_free (virt_methods);
4585 virt_methods = NULL;
4586
4587 g_assert (cur_slot <= max_vtsize);
4588
4589 /* Ensure that all vtable slots are filled with concrete instance methods */
4590 if (!mono_class_is_abstract (klass)) {
4591 for (i = 0; i < cur_slot; ++i) {
4592 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
4593 char *type_name = mono_type_get_full_name (klass);
4594 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
4595 mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
4596 g_free (type_name);
4597 g_free (method_name);
4598 g_free (vtable);
4599 return;
4600 }
4601 }
4602 }
4603
4604 if (mono_class_is_ginst (klass)) {
4605 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4606
4607 mono_class_init (gklass);
4608
4609 klass->vtable_size = MAX (gklass->vtable_size, cur_slot);
4610 } else {
4611 /* Check that the vtable_size value computed in mono_class_init () is correct */
4612 if (klass->vtable_size)
4613 g_assert (cur_slot == klass->vtable_size);
4614 klass->vtable_size = cur_slot;
4615 }
4616
4617 /* Try to share the vtable with our parent. */
4618 if (klass->parent && (klass->parent->vtable_size == klass->vtable_size) && (memcmp (klass->parent->vtable, vtable, sizeof (gpointer) * klass->vtable_size) == 0)) {
4619 mono_memory_barrier ();
4620 klass->vtable = klass->parent->vtable;
4621 } else {
4622 MonoMethod **tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * klass->vtable_size);
4623 memcpy (tmp, vtable, sizeof (gpointer) * klass->vtable_size);
4624 mono_memory_barrier ();
4625 klass->vtable = tmp;
4626 }
4627
4628 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass, klass->vtable, klass->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
4629 if (mono_print_vtable) {
4630 int icount = 0;
4631
4632 print_implemented_interfaces (klass);
4633
4634 for (i = 0; i <= max_iid; i++)
4635 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
4636 icount++;
4637
4638 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&klass->byval_arg),
4639 klass->vtable_size, icount);
4640
4641 for (i = 0; i < cur_slot; ++i) {
4642 MonoMethod *cm;
4643
4644 cm = vtable [i];
4645 if (cm) {
4646 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
4647 mono_method_full_name (cm, TRUE));
4648 }
4649 }
4650
4651
4652 if (icount) {
4653 printf ("Interfaces %s.%s (max_iid = %d)\n", klass->name_space,
4654 klass->name, max_iid);
4655
4656 for (i = 0; i < klass->interface_count; i++) {
4657 ic = klass->interfaces [i];
4658 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
4659 mono_class_interface_offset (klass, ic),
4660 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4661 }
4662
4663 for (k = klass->parent; k ; k = k->parent) {
4664 for (i = 0; i < k->interface_count; i++) {
4665 ic = k->interfaces [i];
4666 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
4667 mono_class_interface_offset (klass, ic),
4668 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4669 }
4670 }
4671 }
4672 }
4673
4674 g_free (vtable);
4675
4676 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass));
4677 return;
4678
4679 fail:
4680 {
4681 char *name = mono_type_get_full_name (klass);
4682 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
4683 g_free (name);
4684 g_free (vtable);
4685 if (override_map)
4686 g_hash_table_destroy (override_map);
4687 if (virt_methods)
4688 g_slist_free (virt_methods);
4689 }
4690 }
4691
4692 /*
4693 * mono_method_get_vtable_slot:
4694 *
4695 * Returns method->slot, computing it if neccesary. Return -1 on failure.
4696 * LOCKING: Acquires the loader lock.
4697 *
4698 * FIXME Use proper MonoError machinery here.
4699 */
4700 int
mono_method_get_vtable_slot(MonoMethod * method)4701 mono_method_get_vtable_slot (MonoMethod *method)
4702 {
4703 if (method->slot == -1) {
4704 mono_class_setup_vtable (method->klass);
4705 if (mono_class_has_failure (method->klass))
4706 return -1;
4707 if (method->slot == -1) {
4708 MonoClass *gklass;
4709 int i, mcount;
4710
4711 if (!mono_class_is_ginst (method->klass)) {
4712 g_assert (method->is_inflated);
4713 return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
4714 }
4715
4716 /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
4717 g_assert (mono_class_is_ginst (method->klass));
4718 gklass = mono_class_get_generic_class (method->klass)->container_class;
4719 mono_class_setup_methods (method->klass);
4720 g_assert (method->klass->methods);
4721 mcount = mono_class_get_method_count (method->klass);
4722 for (i = 0; i < mcount; ++i) {
4723 if (method->klass->methods [i] == method)
4724 break;
4725 }
4726 g_assert (i < mcount);
4727 g_assert (gklass->methods);
4728 method->slot = gklass->methods [i]->slot;
4729 }
4730 g_assert (method->slot != -1);
4731 }
4732 return method->slot;
4733 }
4734
4735 /**
4736 * mono_method_get_vtable_index:
4737 * \param method a method
4738 *
4739 * Returns the index into the runtime vtable to access the method or,
4740 * in the case of a virtual generic method, the virtual generic method
4741 * thunk. Returns -1 on failure.
4742 *
4743 * FIXME Use proper MonoError machinery here.
4744 */
4745 int
mono_method_get_vtable_index(MonoMethod * method)4746 mono_method_get_vtable_index (MonoMethod *method)
4747 {
4748 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
4749 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
4750 if (imethod->declaring->is_generic)
4751 return mono_method_get_vtable_slot (imethod->declaring);
4752 }
4753 return mono_method_get_vtable_slot (method);
4754 }
4755
4756 static MonoMethod *default_ghc = NULL;
4757 static MonoMethod *default_finalize = NULL;
4758 static int finalize_slot = -1;
4759 static int ghc_slot = -1;
4760
4761 static void
initialize_object_slots(MonoClass * klass)4762 initialize_object_slots (MonoClass *klass)
4763 {
4764 int i;
4765 if (default_ghc)
4766 return;
4767 if (klass == mono_defaults.object_class) {
4768 mono_class_setup_vtable (klass);
4769 for (i = 0; i < klass->vtable_size; ++i) {
4770 MonoMethod *cm = klass->vtable [i];
4771
4772 if (!strcmp (cm->name, "GetHashCode"))
4773 ghc_slot = i;
4774 else if (!strcmp (cm->name, "Finalize"))
4775 finalize_slot = i;
4776 }
4777
4778 g_assert (ghc_slot > 0);
4779 default_ghc = klass->vtable [ghc_slot];
4780
4781 g_assert (finalize_slot > 0);
4782 default_finalize = klass->vtable [finalize_slot];
4783 }
4784 }
4785
4786 typedef struct {
4787 MonoMethod *array_method;
4788 char *name;
4789 } GenericArrayMethodInfo;
4790
4791 static int generic_array_method_num = 0;
4792 static GenericArrayMethodInfo *generic_array_method_info = NULL;
4793
4794 static int
generic_array_methods(MonoClass * klass)4795 generic_array_methods (MonoClass *klass)
4796 {
4797 int i, count_generic = 0, mcount;
4798 GList *list = NULL, *tmp;
4799 if (generic_array_method_num)
4800 return generic_array_method_num;
4801 mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
4802 g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
4803 mcount = mono_class_get_method_count (klass->parent);
4804 for (i = 0; i < mcount; i++) {
4805 MonoMethod *m = klass->parent->methods [i];
4806 if (!strncmp (m->name, "InternalArray__", 15)) {
4807 count_generic++;
4808 list = g_list_prepend (list, m);
4809 }
4810 }
4811 list = g_list_reverse (list);
4812 generic_array_method_info = (GenericArrayMethodInfo *)mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
4813 i = 0;
4814 for (tmp = list; tmp; tmp = tmp->next) {
4815 const char *mname, *iname;
4816 gchar *name;
4817 MonoMethod *m = (MonoMethod *)tmp->data;
4818 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
4819 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
4820
4821 generic_array_method_info [i].array_method = m;
4822 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
4823 iname = "System.Collections.Generic.ICollection`1.";
4824 mname = m->name + 27;
4825 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
4826 iname = "System.Collections.Generic.IEnumerable`1.";
4827 mname = m->name + 27;
4828 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
4829 iname = "System.Collections.Generic.IReadOnlyList`1.";
4830 mname = m->name + strlen (ireadonlylist_prefix);
4831 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
4832 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
4833 mname = m->name + strlen (ireadonlycollection_prefix);
4834 } else if (!strncmp (m->name, "InternalArray__", 15)) {
4835 iname = "System.Collections.Generic.IList`1.";
4836 mname = m->name + 15;
4837 } else {
4838 g_assert_not_reached ();
4839 }
4840
4841 name = (gchar *)mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
4842 strcpy (name, iname);
4843 strcpy (name + strlen (iname), mname);
4844 generic_array_method_info [i].name = name;
4845 i++;
4846 }
4847 /*g_print ("array generic methods: %d\n", count_generic);*/
4848
4849 generic_array_method_num = count_generic;
4850 g_list_free (list);
4851 return generic_array_method_num;
4852 }
4853
4854 static void
setup_generic_array_ifaces(MonoClass * klass,MonoClass * iface,MonoMethod ** methods,int pos,GHashTable * cache)4855 setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache)
4856 {
4857 MonoGenericContext tmp_context;
4858 int i;
4859
4860 tmp_context.class_inst = NULL;
4861 tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst;
4862 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
4863
4864 for (i = 0; i < generic_array_method_num; i++) {
4865 MonoError error;
4866 MonoMethod *m = generic_array_method_info [i].array_method;
4867 MonoMethod *inflated, *helper;
4868
4869 inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, &error);
4870 mono_error_assert_ok (&error);
4871 helper = g_hash_table_lookup (cache, inflated);
4872 if (!helper) {
4873 helper = mono_marshal_get_generic_array_helper (klass, generic_array_method_info [i].name, inflated);
4874 g_hash_table_insert (cache, inflated, helper);
4875 }
4876 methods [pos ++] = helper;
4877 }
4878 }
4879
4880 static char*
concat_two_strings_with_zero(MonoImage * image,const char * s1,const char * s2)4881 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
4882 {
4883 int null_length = strlen ("(null)");
4884 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
4885 char *s = (char *)mono_image_alloc (image, len);
4886 int result;
4887
4888 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
4889 g_assert (result == len - 1);
4890
4891 return s;
4892 }
4893
4894 /**
4895 * mono_class_init:
4896 * \param klass the class to initialize
4897 *
4898 * Compute the \c instance_size, \c class_size and other infos that cannot be
4899 * computed at \c mono_class_get time. Also compute vtable_size if possible.
4900 * Initializes the following fields in \p klass:
4901 * - all the fields initialized by \c mono_class_init_sizes
4902 * - has_cctor
4903 * - ghcimpl
4904 * - inited
4905 *
4906 * LOCKING: Acquires the loader lock.
4907 *
4908 * \returns TRUE on success or FALSE if there was a problem in loading
4909 * the type (incorrect assemblies, missing assemblies, methods, etc).
4910 */
4911 gboolean
mono_class_init(MonoClass * klass)4912 mono_class_init (MonoClass *klass)
4913 {
4914 int i, vtable_size = 0, array_method_count = 0;
4915 MonoCachedClassInfo cached_info;
4916 gboolean has_cached_info;
4917 gboolean locked = FALSE;
4918 gboolean ghcimpl = FALSE;
4919 gboolean has_cctor = FALSE;
4920 int first_iface_slot = 0;
4921
4922 g_assert (klass);
4923
4924 /* Double-checking locking pattern */
4925 if (klass->inited || mono_class_has_failure (klass))
4926 return !mono_class_has_failure (klass);
4927
4928 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
4929
4930 /*
4931 * This function can recursively call itself.
4932 */
4933 GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
4934 if (g_slist_find (init_list, klass)) {
4935 mono_class_set_type_load_failure (klass, "Recursive type definition detected");
4936 goto leave_no_init_pending;
4937 }
4938 init_list = g_slist_prepend (init_list, klass);
4939 mono_native_tls_set_value (init_pending_tls_id, init_list);
4940
4941 /*
4942 * We want to avoid doing complicated work inside locks, so we compute all the required
4943 * information and write it to @klass inside a lock.
4944 */
4945
4946 if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
4947 mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
4948 goto leave;
4949 }
4950
4951 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
4952 MonoClass *element_class = klass->element_class;
4953 if (!element_class->inited)
4954 mono_class_init (element_class);
4955 if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
4956 goto leave;
4957 }
4958
4959 UnlockedIncrement (&mono_stats.initialized_class_count);
4960
4961 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
4962 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4963
4964 mono_class_init (gklass);
4965 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
4966 goto leave;
4967
4968 if (MONO_CLASS_IS_INTERFACE (klass))
4969 mono_class_setup_interface_id (klass);
4970 }
4971
4972 if (klass->parent && !klass->parent->inited)
4973 mono_class_init (klass->parent);
4974
4975 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
4976
4977 /* Compute instance size etc. */
4978 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
4979 if (mono_class_has_failure (klass))
4980 goto leave;
4981
4982 mono_class_setup_supertypes (klass);
4983
4984 if (!default_ghc)
4985 initialize_object_slots (klass);
4986
4987 /*
4988 * Initialize the rest of the data without creating a generic vtable if possible.
4989 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
4990 * also avoid computing a generic vtable.
4991 */
4992 if (has_cached_info) {
4993 /* AOT case */
4994 vtable_size = cached_info.vtable_size;
4995 ghcimpl = cached_info.ghcimpl;
4996 has_cctor = cached_info.has_cctor;
4997 } else if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
4998 /* SZARRAY can have 3 vtable layouts, with and without the stelemref method and enum element type
4999 * The first slot if for array with.
5000 */
5001 static int szarray_vtable_size[3] = { 0 };
5002
5003 int slot;
5004
5005 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg))
5006 slot = 0;
5007 else if (klass->element_class->enumtype)
5008 slot = 1;
5009 else
5010 slot = 2;
5011
5012 /* SZARRAY case */
5013 if (!szarray_vtable_size [slot]) {
5014 mono_class_setup_vtable (klass);
5015 szarray_vtable_size [slot] = klass->vtable_size;
5016 vtable_size = klass->vtable_size;
5017 } else {
5018 vtable_size = szarray_vtable_size[slot];
5019 }
5020 } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE (klass)) {
5021 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5022
5023 /* Generic instance case */
5024 ghcimpl = gklass->ghcimpl;
5025 has_cctor = gklass->has_cctor;
5026
5027 mono_class_setup_vtable (gklass);
5028 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
5029 goto leave;
5030
5031 vtable_size = gklass->vtable_size;
5032 } else {
5033 /* General case */
5034
5035 /* ghcimpl is not currently used
5036 klass->ghcimpl = 1;
5037 if (klass->parent) {
5038 MonoMethod *cmethod = klass->vtable [ghc_slot];
5039 if (cmethod->is_inflated)
5040 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5041 if (cmethod == default_ghc) {
5042 klass->ghcimpl = 0;
5043 }
5044 }
5045 */
5046
5047 /* C# doesn't allow interfaces to have cctors */
5048 if (!MONO_CLASS_IS_INTERFACE (klass) || klass->image != mono_defaults.corlib) {
5049 MonoMethod *cmethod = NULL;
5050
5051 if (mono_class_is_ginst (klass)) {
5052 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5053
5054 /* Generic instance case */
5055 ghcimpl = gklass->ghcimpl;
5056 has_cctor = gklass->has_cctor;
5057 } else if (klass->type_token && !image_is_dynamic(klass->image)) {
5058 cmethod = find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
5059 /* The find_method function ignores the 'flags' argument */
5060 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
5061 has_cctor = 1;
5062 } else {
5063 mono_class_setup_methods (klass);
5064 if (mono_class_has_failure (klass))
5065 goto leave;
5066
5067 int mcount = mono_class_get_method_count (klass);
5068 for (i = 0; i < mcount; ++i) {
5069 MonoMethod *method = klass->methods [i];
5070 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
5071 (strcmp (".cctor", method->name) == 0)) {
5072 has_cctor = 1;
5073 break;
5074 }
5075 }
5076 }
5077 }
5078 }
5079
5080 if (klass->rank) {
5081 array_method_count = 3 + (klass->rank > 1? 2: 1);
5082
5083 if (klass->interface_count) {
5084 int count_generic = generic_array_methods (klass);
5085 array_method_count += klass->interface_count * count_generic;
5086 }
5087 }
5088
5089 if (klass->parent) {
5090 if (!klass->parent->vtable_size)
5091 mono_class_setup_vtable (klass->parent);
5092 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
5093 goto leave;
5094 g_assert (klass->parent->vtable_size);
5095 first_iface_slot = klass->parent->vtable_size;
5096 if (mono_class_need_stelemref_method (klass))
5097 ++first_iface_slot;
5098 }
5099
5100 /*
5101 * Do the actual changes to @klass inside the loader lock
5102 */
5103 mono_loader_lock ();
5104 locked = TRUE;
5105
5106 if (klass->inited || mono_class_has_failure (klass)) {
5107 mono_loader_unlock ();
5108 /* Somebody might have gotten in before us */
5109 return !mono_class_has_failure (klass);
5110 }
5111
5112 UnlockedIncrement (&mono_stats.initialized_class_count);
5113
5114 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic)
5115 UnlockedIncrement (&mono_stats.generic_class_count);
5116
5117 if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
5118 klass->nested_classes_inited = TRUE;
5119 klass->ghcimpl = ghcimpl;
5120 klass->has_cctor = has_cctor;
5121 if (vtable_size)
5122 klass->vtable_size = vtable_size;
5123 if (has_cached_info) {
5124 klass->has_finalize = cached_info.has_finalize;
5125 klass->has_finalize_inited = TRUE;
5126 }
5127 if (klass->rank)
5128 mono_class_set_method_count (klass, array_method_count);
5129
5130 mono_loader_unlock ();
5131 locked = FALSE;
5132
5133 setup_interface_offsets (klass, first_iface_slot, TRUE);
5134
5135 if (mono_security_core_clr_enabled ())
5136 mono_security_core_clr_check_inheritance (klass);
5137
5138 if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
5139 mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
5140
5141 goto leave;
5142
5143 leave:
5144 init_list = mono_native_tls_get_value (init_pending_tls_id);
5145 init_list = g_slist_remove (init_list, klass);
5146 mono_native_tls_set_value (init_pending_tls_id, init_list);
5147
5148 leave_no_init_pending:
5149 if (locked)
5150 mono_loader_unlock ();
5151
5152 /* Leave this for last */
5153 mono_loader_lock ();
5154 klass->inited = 1;
5155 mono_loader_unlock ();
5156
5157 return !mono_class_has_failure (klass);
5158 }
5159
5160 /*
5161 * mono_class_has_finalizer:
5162 *
5163 * Return whenever KLASS has a finalizer, initializing klass->has_finalizer in the
5164 * process.
5165 */
5166 gboolean
mono_class_has_finalizer(MonoClass * klass)5167 mono_class_has_finalizer (MonoClass *klass)
5168 {
5169 gboolean has_finalize = FALSE;
5170
5171 if (klass->has_finalize_inited)
5172 return klass->has_finalize;
5173
5174 /* Interfaces and valuetypes are not supposed to have finalizers */
5175 if (!(MONO_CLASS_IS_INTERFACE (klass) || klass->valuetype)) {
5176 MonoMethod *cmethod = NULL;
5177
5178 if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
5179 } else if (mono_class_is_ginst (klass)) {
5180 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5181
5182 has_finalize = mono_class_has_finalizer (gklass);
5183 } else if (klass->parent && klass->parent->has_finalize) {
5184 has_finalize = TRUE;
5185 } else {
5186 if (klass->parent) {
5187 /*
5188 * Can't search in metadata for a method named Finalize, because that
5189 * ignores overrides.
5190 */
5191 mono_class_setup_vtable (klass);
5192 if (mono_class_has_failure (klass))
5193 cmethod = NULL;
5194 else
5195 cmethod = klass->vtable [finalize_slot];
5196 }
5197
5198 if (cmethod) {
5199 g_assert (klass->vtable_size > finalize_slot);
5200
5201 if (klass->parent) {
5202 if (cmethod->is_inflated)
5203 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5204 if (cmethod != default_finalize)
5205 has_finalize = TRUE;
5206 }
5207 }
5208 }
5209 }
5210
5211 mono_loader_lock ();
5212 if (!klass->has_finalize_inited) {
5213 klass->has_finalize = has_finalize ? 1 : 0;
5214
5215 mono_memory_barrier ();
5216 klass->has_finalize_inited = TRUE;
5217 }
5218 mono_loader_unlock ();
5219
5220 return klass->has_finalize;
5221 }
5222
5223 gboolean
mono_is_corlib_image(MonoImage * image)5224 mono_is_corlib_image (MonoImage *image)
5225 {
5226 return image == mono_defaults.corlib;
5227 }
5228
5229 /*
5230 * LOCKING: this assumes the loader lock is held
5231 */
5232 void
mono_class_setup_mono_type(MonoClass * klass)5233 mono_class_setup_mono_type (MonoClass *klass)
5234 {
5235 const char *name = klass->name;
5236 const char *nspace = klass->name_space;
5237 gboolean is_corlib = mono_is_corlib_image (klass->image);
5238
5239 klass->this_arg.byref = 1;
5240 klass->this_arg.data.klass = klass;
5241 klass->this_arg.type = MONO_TYPE_CLASS;
5242 klass->byval_arg.data.klass = klass;
5243 klass->byval_arg.type = MONO_TYPE_CLASS;
5244
5245 if (is_corlib && !strcmp (nspace, "System")) {
5246 if (!strcmp (name, "ValueType")) {
5247 /*
5248 * do not set the valuetype bit for System.ValueType.
5249 * klass->valuetype = 1;
5250 */
5251 klass->blittable = TRUE;
5252 } else if (!strcmp (name, "Enum")) {
5253 /*
5254 * do not set the valuetype bit for System.Enum.
5255 * klass->valuetype = 1;
5256 */
5257 klass->valuetype = 0;
5258 klass->enumtype = 0;
5259 } else if (!strcmp (name, "Object")) {
5260 klass->byval_arg.type = MONO_TYPE_OBJECT;
5261 klass->this_arg.type = MONO_TYPE_OBJECT;
5262 } else if (!strcmp (name, "String")) {
5263 klass->byval_arg.type = MONO_TYPE_STRING;
5264 klass->this_arg.type = MONO_TYPE_STRING;
5265 } else if (!strcmp (name, "TypedReference")) {
5266 klass->byval_arg.type = MONO_TYPE_TYPEDBYREF;
5267 klass->this_arg.type = MONO_TYPE_TYPEDBYREF;
5268 }
5269 }
5270
5271 if (klass->valuetype) {
5272 int t = MONO_TYPE_VALUETYPE;
5273
5274 if (is_corlib && !strcmp (nspace, "System")) {
5275 switch (*name) {
5276 case 'B':
5277 if (!strcmp (name, "Boolean")) {
5278 t = MONO_TYPE_BOOLEAN;
5279 } else if (!strcmp(name, "Byte")) {
5280 t = MONO_TYPE_U1;
5281 klass->blittable = TRUE;
5282 }
5283 break;
5284 case 'C':
5285 if (!strcmp (name, "Char")) {
5286 t = MONO_TYPE_CHAR;
5287 }
5288 break;
5289 case 'D':
5290 if (!strcmp (name, "Double")) {
5291 t = MONO_TYPE_R8;
5292 klass->blittable = TRUE;
5293 }
5294 break;
5295 case 'I':
5296 if (!strcmp (name, "Int32")) {
5297 t = MONO_TYPE_I4;
5298 klass->blittable = TRUE;
5299 } else if (!strcmp(name, "Int16")) {
5300 t = MONO_TYPE_I2;
5301 klass->blittable = TRUE;
5302 } else if (!strcmp(name, "Int64")) {
5303 t = MONO_TYPE_I8;
5304 klass->blittable = TRUE;
5305 } else if (!strcmp(name, "IntPtr")) {
5306 t = MONO_TYPE_I;
5307 klass->blittable = TRUE;
5308 }
5309 break;
5310 case 'S':
5311 if (!strcmp (name, "Single")) {
5312 t = MONO_TYPE_R4;
5313 klass->blittable = TRUE;
5314 } else if (!strcmp(name, "SByte")) {
5315 t = MONO_TYPE_I1;
5316 klass->blittable = TRUE;
5317 }
5318 break;
5319 case 'U':
5320 if (!strcmp (name, "UInt32")) {
5321 t = MONO_TYPE_U4;
5322 klass->blittable = TRUE;
5323 } else if (!strcmp(name, "UInt16")) {
5324 t = MONO_TYPE_U2;
5325 klass->blittable = TRUE;
5326 } else if (!strcmp(name, "UInt64")) {
5327 t = MONO_TYPE_U8;
5328 klass->blittable = TRUE;
5329 } else if (!strcmp(name, "UIntPtr")) {
5330 t = MONO_TYPE_U;
5331 klass->blittable = TRUE;
5332 }
5333 break;
5334 case 'T':
5335 if (!strcmp (name, "TypedReference")) {
5336 t = MONO_TYPE_TYPEDBYREF;
5337 klass->blittable = TRUE;
5338 }
5339 break;
5340 case 'V':
5341 if (!strcmp (name, "Void")) {
5342 t = MONO_TYPE_VOID;
5343 }
5344 break;
5345 default:
5346 break;
5347 }
5348 }
5349 klass->byval_arg.type = (MonoTypeEnum)t;
5350 klass->this_arg.type = (MonoTypeEnum)t;
5351 }
5352
5353 if (MONO_CLASS_IS_INTERFACE (klass)) {
5354 klass->interface_id = mono_get_unique_iid (klass);
5355
5356 if (is_corlib && !strcmp (nspace, "System.Collections.Generic")) {
5357 //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
5358 /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
5359 * MS returns diferrent types based on which instance is called. For example:
5360 * object obj = new byte[10][];
5361 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
5362 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
5363 * a != b ==> true
5364 */
5365 if (!strcmp (name, "IList`1") || !strcmp (name, "ICollection`1") || !strcmp (name, "IEnumerable`1") || !strcmp (name, "IEnumerator`1"))
5366 klass->is_array_special_interface = 1;
5367 }
5368 }
5369 }
5370
5371 #ifndef DISABLE_COM
5372 /*
5373 * COM initialization is delayed until needed.
5374 * However when a [ComImport] attribute is present on a type it will trigger
5375 * the initialization. This is not a problem unless the BCL being executed
5376 * lacks the types that COM depends on (e.g. Variant on Silverlight).
5377 */
5378 static void
init_com_from_comimport(MonoClass * klass)5379 init_com_from_comimport (MonoClass *klass)
5380 {
5381 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
5382 if (mono_security_core_clr_enabled ()) {
5383 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
5384 if (!mono_security_core_clr_determine_platform_image (klass->image)) {
5385 /* but it can not be made available for application (i.e. user code) since all COM calls
5386 * are considered native calls. In this case we fail with a TypeLoadException (just like
5387 * Silverlight 2 does */
5388 mono_class_set_type_load_failure (klass, "");
5389 return;
5390 }
5391 }
5392
5393 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
5394 }
5395 #endif /*DISABLE_COM*/
5396
5397 /*
5398 * LOCKING: this assumes the loader lock is held
5399 */
5400 void
mono_class_setup_parent(MonoClass * klass,MonoClass * parent)5401 mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
5402 {
5403 gboolean system_namespace;
5404 gboolean is_corlib = mono_is_corlib_image (klass->image);
5405
5406 system_namespace = !strcmp (klass->name_space, "System") && is_corlib;
5407
5408 /* if root of the hierarchy */
5409 if (system_namespace && !strcmp (klass->name, "Object")) {
5410 klass->parent = NULL;
5411 klass->instance_size = sizeof (MonoObject);
5412 return;
5413 }
5414 if (!strcmp (klass->name, "<Module>")) {
5415 klass->parent = NULL;
5416 klass->instance_size = 0;
5417 return;
5418 }
5419
5420 if (!MONO_CLASS_IS_INTERFACE (klass)) {
5421 /* Imported COM Objects always derive from __ComObject. */
5422 #ifndef DISABLE_COM
5423 if (MONO_CLASS_IS_IMPORT (klass)) {
5424 init_com_from_comimport (klass);
5425 if (parent == mono_defaults.object_class)
5426 parent = mono_class_get_com_object_class ();
5427 }
5428 #endif
5429 if (!parent) {
5430 /* set the parent to something useful and safe, but mark the type as broken */
5431 parent = mono_defaults.object_class;
5432 mono_class_set_type_load_failure (klass, "");
5433 g_assert (parent);
5434 }
5435
5436 klass->parent = parent;
5437
5438 if (mono_class_is_ginst (parent) && !parent->name) {
5439 /*
5440 * If the parent is a generic instance, we may get
5441 * called before it is fully initialized, especially
5442 * before it has its name.
5443 */
5444 return;
5445 }
5446
5447 #ifndef DISABLE_REMOTING
5448 klass->marshalbyref = parent->marshalbyref;
5449 klass->contextbound = parent->contextbound;
5450 #endif
5451
5452 klass->delegate = parent->delegate;
5453
5454 if (MONO_CLASS_IS_IMPORT (klass) || mono_class_is_com_object (parent))
5455 mono_class_set_is_com_object (klass);
5456
5457 if (system_namespace) {
5458 #ifndef DISABLE_REMOTING
5459 if (klass->name [0] == 'M' && !strcmp (klass->name, "MarshalByRefObject"))
5460 klass->marshalbyref = 1;
5461
5462 if (klass->name [0] == 'C' && !strcmp (klass->name, "ContextBoundObject"))
5463 klass->contextbound = 1;
5464 #endif
5465 if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate"))
5466 klass->delegate = 1;
5467 }
5468
5469 if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) &&
5470 (strcmp (klass->parent->name_space, "System") == 0)))
5471 klass->valuetype = 1;
5472 if (mono_is_corlib_image (klass->parent->image) && ((strcmp (klass->parent->name, "Enum") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) {
5473 klass->valuetype = klass->enumtype = 1;
5474 }
5475 /*klass->enumtype = klass->parent->enumtype; */
5476 } else {
5477 /* initialize com types if COM interfaces are present */
5478 #ifndef DISABLE_COM
5479 if (MONO_CLASS_IS_IMPORT (klass))
5480 init_com_from_comimport (klass);
5481 #endif
5482 klass->parent = NULL;
5483 }
5484
5485 }
5486
5487 /*
5488 * mono_class_setup_supertypes:
5489 * @class: a class
5490 *
5491 * Build the data structure needed to make fast type checks work.
5492 * This currently sets two fields in @class:
5493 * - idepth: distance between @class and System.Object in the type
5494 * hierarchy + 1
5495 * - supertypes: array of classes: each element has a class in the hierarchy
5496 * starting from @class up to System.Object
5497 *
5498 * LOCKING: Acquires the loader lock.
5499 */
5500 void
mono_class_setup_supertypes(MonoClass * klass)5501 mono_class_setup_supertypes (MonoClass *klass)
5502 {
5503 int ms, idepth;
5504 MonoClass **supertypes;
5505
5506 mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes);
5507 if (supertypes)
5508 return;
5509
5510 if (klass->parent && !klass->parent->supertypes)
5511 mono_class_setup_supertypes (klass->parent);
5512 if (klass->parent)
5513 idepth = klass->parent->idepth + 1;
5514 else
5515 idepth = 1;
5516
5517 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, idepth);
5518 supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
5519
5520 if (klass->parent) {
5521 CHECKED_METADATA_WRITE_PTR ( supertypes [idepth - 1] , klass );
5522
5523 int supertype_idx;
5524 for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
5525 CHECKED_METADATA_WRITE_PTR ( supertypes [supertype_idx] , klass->parent->supertypes [supertype_idx] );
5526 } else {
5527 CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
5528 }
5529
5530 mono_memory_barrier ();
5531
5532 mono_loader_lock ();
5533 klass->idepth = idepth;
5534 /* Needed so idepth is visible before supertypes is set */
5535 mono_memory_barrier ();
5536 klass->supertypes = supertypes;
5537 mono_loader_unlock ();
5538 }
5539
5540 static gboolean
discard_gclass_due_to_failure(MonoClass * gclass,void * user_data)5541 discard_gclass_due_to_failure (MonoClass *gclass, void *user_data)
5542 {
5543 return mono_class_get_generic_class (gclass)->container_class == user_data;
5544 }
5545
5546 static gboolean
fix_gclass_incomplete_instantiation(MonoClass * gclass,void * user_data)5547 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
5548 {
5549 MonoClass *gtd = (MonoClass*)user_data;
5550 /* Only try to fix generic instances of @gtd */
5551 if (mono_class_get_generic_class (gclass)->container_class != gtd)
5552 return FALSE;
5553
5554 /* Check if the generic instance has no parent. */
5555 if (gtd->parent && !gclass->parent)
5556 mono_generic_class_setup_parent (gclass, gtd);
5557
5558 return TRUE;
5559 }
5560
5561 static void
mono_class_set_failure_and_error(MonoClass * klass,MonoError * error,const char * msg)5562 mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
5563 {
5564 mono_class_set_type_load_failure (klass, "%s", msg);
5565 mono_error_set_type_load_class (error, klass, "%s", msg);
5566 }
5567
5568 /**
5569 * mono_class_create_from_typedef:
5570 * \param image: image where the token is valid
5571 * \param type_token: typedef token
5572 * \param error: used to return any error found while creating the type
5573 *
5574 * Create the MonoClass* representing the specified type token.
5575 * \p type_token must be a TypeDef token.
5576 *
5577 * FIXME: don't return NULL on failure, just let the caller figure it out.
5578 */
5579 static MonoClass *
mono_class_create_from_typedef(MonoImage * image,guint32 type_token,MonoError * error)5580 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
5581 {
5582 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
5583 MonoClass *klass, *parent = NULL;
5584 guint32 cols [MONO_TYPEDEF_SIZE];
5585 guint32 cols_next [MONO_TYPEDEF_SIZE];
5586 guint tidx = mono_metadata_token_index (type_token);
5587 MonoGenericContext *context = NULL;
5588 const char *name, *nspace;
5589 guint icount = 0;
5590 MonoClass **interfaces;
5591 guint32 field_last, method_last;
5592 guint32 nesting_tokeen;
5593
5594 error_init (error);
5595
5596 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
5597 mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
5598 return NULL;
5599 }
5600
5601 mono_loader_lock ();
5602
5603 if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
5604 mono_loader_unlock ();
5605 return klass;
5606 }
5607
5608 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
5609
5610 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
5611 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
5612
5613 if (mono_metadata_has_generic_params (image, type_token)) {
5614 klass = mono_image_alloc0 (image, sizeof (MonoClassGtd));
5615 klass->class_kind = MONO_CLASS_GTD;
5616 UnlockedAdd (&classes_size, sizeof (MonoClassGtd));
5617 ++class_gtd_count;
5618 } else {
5619 klass = mono_image_alloc0 (image, sizeof (MonoClassDef));
5620 klass->class_kind = MONO_CLASS_DEF;
5621 UnlockedAdd (&classes_size, sizeof (MonoClassDef));
5622 ++class_def_count;
5623 }
5624
5625 klass->name = name;
5626 klass->name_space = nspace;
5627
5628 MONO_PROFILER_RAISE (class_loading, (klass));
5629
5630 klass->image = image;
5631 klass->type_token = type_token;
5632 mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
5633
5634 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
5635
5636 /*
5637 * Check whether we're a generic type definition.
5638 */
5639 if (mono_class_is_gtd (klass)) {
5640 MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
5641 generic_container->owner.klass = klass;
5642 generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
5643 context = &generic_container->context;
5644 mono_class_set_generic_container (klass, generic_container);
5645 MonoType *canonical_inst = &((MonoClassGtd*)klass)->canonical_inst;
5646 canonical_inst->type = MONO_TYPE_GENERICINST;
5647 canonical_inst->data.generic_class = mono_metadata_lookup_generic_class (klass, context->class_inst, FALSE);
5648 enable_gclass_recording ();
5649 }
5650
5651 if (cols [MONO_TYPEDEF_EXTENDS]) {
5652 MonoClass *tmp;
5653 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
5654
5655 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
5656 /*WARNING: this must satisfy mono_metadata_type_hash*/
5657 klass->this_arg.byref = 1;
5658 klass->this_arg.data.klass = klass;
5659 klass->this_arg.type = MONO_TYPE_CLASS;
5660 klass->byval_arg.data.klass = klass;
5661 klass->byval_arg.type = MONO_TYPE_CLASS;
5662 }
5663 parent = mono_class_get_checked (image, parent_token, error);
5664 if (parent && context) /* Always inflate */
5665 parent = mono_class_inflate_generic_class_checked (parent, context, error);
5666
5667 if (parent == NULL) {
5668 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5669 goto parent_failure;
5670 }
5671
5672 for (tmp = parent; tmp; tmp = tmp->parent) {
5673 if (tmp == klass) {
5674 mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
5675 goto parent_failure;
5676 }
5677 if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
5678 mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
5679 goto parent_failure;
5680 }
5681 }
5682 }
5683
5684 mono_class_setup_parent (klass, parent);
5685
5686 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
5687 mono_class_setup_mono_type (klass);
5688
5689 if (mono_class_is_gtd (klass))
5690 disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
5691
5692 /*
5693 * This might access klass->byval_arg for recursion generated by generic constraints,
5694 * so it has to come after setup_mono_type ().
5695 */
5696 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
5697 klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
5698 if (!mono_error_ok (error)) {
5699 /*FIXME implement a mono_class_set_failure_from_mono_error */
5700 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5701 mono_loader_unlock ();
5702 MONO_PROFILER_RAISE (class_failed, (klass));
5703 return NULL;
5704 }
5705 }
5706
5707 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
5708 klass->unicode = 1;
5709
5710 #ifdef HOST_WIN32
5711 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
5712 klass->unicode = 1;
5713 #endif
5714
5715 klass->cast_class = klass->element_class = klass;
5716 if (mono_is_corlib_image (klass->image)) {
5717 switch (klass->byval_arg.type) {
5718 case MONO_TYPE_I1:
5719 if (mono_defaults.byte_class)
5720 klass->cast_class = mono_defaults.byte_class;
5721 break;
5722 case MONO_TYPE_U1:
5723 if (mono_defaults.sbyte_class)
5724 mono_defaults.sbyte_class = klass;
5725 break;
5726 case MONO_TYPE_I2:
5727 if (mono_defaults.uint16_class)
5728 mono_defaults.uint16_class = klass;
5729 break;
5730 case MONO_TYPE_U2:
5731 if (mono_defaults.int16_class)
5732 klass->cast_class = mono_defaults.int16_class;
5733 break;
5734 case MONO_TYPE_I4:
5735 if (mono_defaults.uint32_class)
5736 mono_defaults.uint32_class = klass;
5737 break;
5738 case MONO_TYPE_U4:
5739 if (mono_defaults.int32_class)
5740 klass->cast_class = mono_defaults.int32_class;
5741 break;
5742 case MONO_TYPE_I8:
5743 if (mono_defaults.uint64_class)
5744 mono_defaults.uint64_class = klass;
5745 break;
5746 case MONO_TYPE_U8:
5747 if (mono_defaults.int64_class)
5748 klass->cast_class = mono_defaults.int64_class;
5749 break;
5750 }
5751 }
5752
5753 if (!klass->enumtype) {
5754 if (!mono_metadata_interfaces_from_typedef_full (
5755 image, type_token, &interfaces, &icount, FALSE, context, error)){
5756
5757 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5758 mono_loader_unlock ();
5759 MONO_PROFILER_RAISE (class_failed, (klass));
5760 return NULL;
5761 }
5762
5763 /* This is required now that it is possible for more than 2^16 interfaces to exist. */
5764 g_assert(icount <= 65535);
5765
5766 klass->interfaces = interfaces;
5767 klass->interface_count = icount;
5768 klass->interfaces_inited = 1;
5769 }
5770
5771 /*g_print ("Load class %s\n", name);*/
5772
5773 /*
5774 * Compute the field and method lists
5775 */
5776 int first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
5777 mono_class_set_first_field_idx (klass, first_field_idx);
5778 int first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
5779 mono_class_set_first_method_idx (klass, first_method_idx);
5780
5781 if (tt->rows > tidx){
5782 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
5783 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
5784 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
5785 } else {
5786 field_last = image->tables [MONO_TABLE_FIELD].rows;
5787 method_last = image->tables [MONO_TABLE_METHOD].rows;
5788 }
5789
5790 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
5791 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
5792 mono_class_set_field_count (klass, field_last - first_field_idx);
5793 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
5794 mono_class_set_method_count (klass, method_last - first_method_idx);
5795
5796 /* reserve space to store vector pointer in arrays */
5797 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
5798 klass->instance_size += 2 * sizeof (gpointer);
5799 g_assert (mono_class_get_field_count (klass) == 0);
5800 }
5801
5802 if (klass->enumtype) {
5803 MonoType *enum_basetype = mono_class_find_enum_basetype (klass, error);
5804 if (!enum_basetype) {
5805 /*set it to a default value as the whole runtime can't handle this to be null*/
5806 klass->cast_class = klass->element_class = mono_defaults.int32_class;
5807 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5808 mono_loader_unlock ();
5809 MONO_PROFILER_RAISE (class_failed, (klass));
5810 return NULL;
5811 }
5812 klass->cast_class = klass->element_class = mono_class_from_mono_type (enum_basetype);
5813 }
5814
5815 /*
5816 * If we're a generic type definition, load the constraints.
5817 * We must do this after the class has been constructed to make certain recursive scenarios
5818 * work.
5819 */
5820 if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
5821 mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
5822 mono_loader_unlock ();
5823 MONO_PROFILER_RAISE (class_failed, (klass));
5824 return NULL;
5825 }
5826
5827 if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
5828 if (!strncmp (name, "Vector", 6))
5829 klass->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");
5830 } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics") && !strcmp (nspace, "System.Numerics")) {
5831 if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
5832 klass->simd_type = 1;
5833 }
5834
5835 mono_loader_unlock ();
5836
5837 MONO_PROFILER_RAISE (class_loaded, (klass));
5838
5839 return klass;
5840
5841 parent_failure:
5842 if (mono_class_is_gtd (klass))
5843 disable_gclass_recording (discard_gclass_due_to_failure, klass);
5844
5845 mono_class_setup_mono_type (klass);
5846 mono_loader_unlock ();
5847 MONO_PROFILER_RAISE (class_failed, (klass));
5848 return NULL;
5849 }
5850
5851 /** Is klass a Nullable<T> ginst? */
5852 gboolean
mono_class_is_nullable(MonoClass * klass)5853 mono_class_is_nullable (MonoClass *klass)
5854 {
5855 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
5856 return gklass && gklass->container_class == mono_defaults.generic_nullable_class;
5857 }
5858
5859
5860 /** if klass is T? return T */
5861 MonoClass*
mono_class_get_nullable_param(MonoClass * klass)5862 mono_class_get_nullable_param (MonoClass *klass)
5863 {
5864 g_assert (mono_class_is_nullable (klass));
5865 return mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
5866 }
5867
5868 static void
mono_generic_class_setup_parent(MonoClass * klass,MonoClass * gtd)5869 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
5870 {
5871 if (gtd->parent) {
5872 MonoError error;
5873 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
5874
5875 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
5876 if (!mono_error_ok (&error)) {
5877 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
5878 klass->parent = mono_defaults.object_class;
5879 mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (&error));
5880 mono_error_cleanup (&error);
5881 }
5882 }
5883 mono_loader_lock ();
5884 if (klass->parent)
5885 mono_class_setup_parent (klass, klass->parent);
5886
5887 if (klass->enumtype) {
5888 klass->cast_class = gtd->cast_class;
5889 klass->element_class = gtd->element_class;
5890 }
5891 mono_loader_unlock ();
5892 }
5893
5894 gboolean
mono_type_is_primitive(MonoType * type)5895 mono_type_is_primitive (MonoType *type)
5896 {
5897 return (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_R8) ||
5898 type-> type == MONO_TYPE_I || type->type == MONO_TYPE_U;
5899 }
5900
5901 /*
5902 * Create the `MonoClass' for an instantiation of a generic type.
5903 * We only do this if we actually need it.
5904 */
5905 MonoClass*
mono_generic_class_get_class(MonoGenericClass * gclass)5906 mono_generic_class_get_class (MonoGenericClass *gclass)
5907 {
5908 MonoClass *klass, *gklass;
5909
5910 if (gclass->cached_class)
5911 return gclass->cached_class;
5912
5913 klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
5914
5915 gklass = gclass->container_class;
5916
5917 if (gklass->nested_in) {
5918 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
5919 klass->nested_in = gklass->nested_in;
5920 }
5921
5922 klass->name = gklass->name;
5923 klass->name_space = gklass->name_space;
5924
5925 klass->image = gklass->image;
5926 klass->type_token = gklass->type_token;
5927
5928 klass->class_kind = MONO_CLASS_GINST;
5929 //FIXME add setter
5930 ((MonoClassGenericInst*)klass)->generic_class = gclass;
5931
5932 klass->byval_arg.type = MONO_TYPE_GENERICINST;
5933 klass->this_arg.type = klass->byval_arg.type;
5934 klass->this_arg.data.generic_class = klass->byval_arg.data.generic_class = gclass;
5935 klass->this_arg.byref = TRUE;
5936 klass->enumtype = gklass->enumtype;
5937 klass->valuetype = gklass->valuetype;
5938
5939
5940 if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) {
5941 g_assert (gclass->context.class_inst);
5942 g_assert (gclass->context.class_inst->type_argc > 0);
5943 if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0]))
5944 klass->simd_type = 1;
5945 }
5946 klass->is_array_special_interface = gklass->is_array_special_interface;
5947
5948 klass->cast_class = klass->element_class = klass;
5949
5950 if (gclass->is_dynamic) {
5951 /*
5952 * We don't need to do any init workf with unbaked typebuilders. Generic instances created at this point will be later unregistered and/or fixed.
5953 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
5954 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
5955 */
5956 if (!gklass->wastypebuilder)
5957 klass->inited = 1;
5958
5959 if (klass->enumtype) {
5960 /*
5961 * For enums, gklass->fields might not been set, but instance_size etc. is
5962 * already set in mono_reflection_create_internal_class (). For non-enums,
5963 * these will be computed normally in mono_class_layout_fields ().
5964 */
5965 klass->instance_size = gklass->instance_size;
5966 klass->sizes.class_size = gklass->sizes.class_size;
5967 klass->size_inited = 1;
5968 }
5969 }
5970
5971 mono_loader_lock ();
5972
5973 if (gclass->cached_class) {
5974 mono_loader_unlock ();
5975 return gclass->cached_class;
5976 }
5977
5978 if (record_gclass_instantiation > 0)
5979 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
5980
5981 if (mono_class_is_nullable (klass))
5982 klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
5983
5984 MONO_PROFILER_RAISE (class_loading, (klass));
5985
5986 mono_generic_class_setup_parent (klass, gklass);
5987
5988 if (gclass->is_dynamic)
5989 mono_class_setup_supertypes (klass);
5990
5991 mono_memory_barrier ();
5992 gclass->cached_class = klass;
5993
5994 MONO_PROFILER_RAISE (class_loaded, (klass));
5995
5996 ++class_ginst_count;
5997 inflated_classes_size += sizeof (MonoClassGenericInst);
5998
5999 mono_loader_unlock ();
6000
6001 return klass;
6002 }
6003
6004 static MonoImage *
get_image_for_container(MonoGenericContainer * container)6005 get_image_for_container (MonoGenericContainer *container)
6006 {
6007 MonoImage *result;
6008 if (container->is_anonymous) {
6009 result = container->owner.image;
6010 } else {
6011 MonoClass *klass;
6012 if (container->is_method) {
6013 MonoMethod *method = container->owner.method;
6014 g_assert_checked (method);
6015 klass = method->klass;
6016 } else {
6017 klass = container->owner.klass;
6018 }
6019 g_assert_checked (klass);
6020 result = klass->image;
6021 }
6022 g_assert (result);
6023 return result;
6024 }
6025
6026 MonoImage *
get_image_for_generic_param(MonoGenericParam * param)6027 get_image_for_generic_param (MonoGenericParam *param)
6028 {
6029 MonoGenericContainer *container = mono_generic_param_owner (param);
6030 g_assert_checked (container);
6031 return get_image_for_container (container);
6032 }
6033
6034 // Make a string in the designated image consisting of a single integer.
6035 #define INT_STRING_SIZE 16
6036 char *
make_generic_name_string(MonoImage * image,int num)6037 make_generic_name_string (MonoImage *image, int num)
6038 {
6039 char *name = (char *)mono_image_alloc0 (image, INT_STRING_SIZE);
6040 g_snprintf (name, INT_STRING_SIZE, "%d", num);
6041 return name;
6042 }
6043
6044 // This is called by mono_class_from_generic_parameter_internal when a new class must be created.
6045 // pinfo is derived from param by the caller for us.
6046 static MonoClass*
make_generic_param_class(MonoGenericParam * param,MonoGenericParamInfo * pinfo)6047 make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
6048 {
6049 MonoClass *klass, **ptr;
6050 int count, pos, i;
6051 MonoGenericContainer *container = mono_generic_param_owner (param);
6052 g_assert_checked (container);
6053
6054 MonoImage *image = get_image_for_container (container);
6055 gboolean is_mvar = container->is_method;
6056 gboolean is_anonymous = container->is_anonymous;
6057
6058 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
6059 klass->class_kind = MONO_CLASS_GPARAM;
6060 UnlockedAdd (&classes_size, sizeof (MonoClassGenericParam));
6061 UnlockedIncrement (&class_gparam_count);
6062
6063 if (pinfo) {
6064 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
6065 } else {
6066 int n = mono_generic_param_num (param);
6067 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->name , make_generic_name_string (image, n) );
6068 }
6069
6070 if (is_anonymous) {
6071 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , "" );
6072 } else if (is_mvar) {
6073 MonoMethod *omethod = container->owner.method;
6074 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , (omethod && omethod->klass) ? omethod->klass->name_space : "" );
6075 } else {
6076 MonoClass *oklass = container->owner.klass;
6077 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
6078 }
6079
6080 MONO_PROFILER_RAISE (class_loading, (klass));
6081
6082 // Count non-NULL items in pinfo->constraints
6083 count = 0;
6084 if (pinfo)
6085 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
6086 ;
6087
6088 pos = 0;
6089 if ((count > 0) && !MONO_CLASS_IS_INTERFACE (pinfo->constraints [0])) {
6090 CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
6091 pos++;
6092 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
6093 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
6094 } else {
6095 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
6096 }
6097
6098 if (count - pos > 0) {
6099 klass->interface_count = count - pos;
6100 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->interfaces , (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos)) );
6101 klass->interfaces_inited = TRUE;
6102 for (i = pos; i < count; i++)
6103 CHECKED_METADATA_WRITE_PTR ( klass->interfaces [i - pos] , pinfo->constraints [i] );
6104 }
6105
6106 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->image , image );
6107
6108 klass->inited = TRUE;
6109 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
6110 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
6111
6112 klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
6113 klass->this_arg.type = klass->byval_arg.type;
6114 CHECKED_METADATA_WRITE_PTR ( klass->this_arg.data.generic_param , param );
6115 CHECKED_METADATA_WRITE_PTR ( klass->byval_arg.data.generic_param , param );
6116 klass->this_arg.byref = TRUE;
6117
6118 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
6119 klass->sizes.generic_param_token = pinfo ? pinfo->token : 0;
6120
6121 /*Init these fields to sane values*/
6122 klass->min_align = 1;
6123 /*
6124 * This makes sure the the value size of this class is equal to the size of the types the gparam is
6125 * constrained to, the JIT depends on this.
6126 */
6127 klass->instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
6128 mono_memory_barrier ();
6129 klass->size_inited = 1;
6130
6131 mono_class_setup_supertypes (klass);
6132
6133 if (count - pos > 0) {
6134 mono_class_setup_vtable (klass->parent);
6135 if (mono_class_has_failure (klass->parent))
6136 mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
6137 else
6138 setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
6139 }
6140
6141 return klass;
6142 }
6143
6144 #define FAST_CACHE_SIZE 16
6145
6146 /*
6147 * get_anon_gparam_class and set_anon_gparam_class are helpers for mono_class_from_generic_parameter_internal.
6148 * The latter will sometimes create MonoClasses for anonymous generic params. To prevent this being wasteful,
6149 * we cache the MonoClasses.
6150 * FIXME: It would be better to instead cache anonymous MonoGenericParams, and allow anonymous params to point directly to classes using the pklass field.
6151 * LOCKING: Takes the image lock depending on @take_lock.
6152 */
6153 static MonoClass *
get_anon_gparam_class(MonoGenericParam * param,gboolean take_lock)6154 get_anon_gparam_class (MonoGenericParam *param, gboolean take_lock)
6155 {
6156 int n = mono_generic_param_num (param);
6157 MonoImage *image = get_image_for_generic_param (param);
6158 gboolean is_mvar = mono_generic_param_owner (param)->is_method;
6159 MonoClass *klass = NULL;
6160 GHashTable *ht;
6161
6162 g_assert (image);
6163
6164 // For params with a small num and no constraints, we use a "fast" cache which does simple num lookup in an array.
6165 // For high numbers or constraints we have to use pointer hashes.
6166 if (param->gshared_constraint) {
6167 ht = is_mvar ? image->mvar_cache_constrained : image->var_cache_constrained;
6168 if (ht) {
6169 if (take_lock)
6170 mono_image_lock (image);
6171 klass = (MonoClass *)g_hash_table_lookup (ht, param);
6172 if (take_lock)
6173 mono_image_unlock (image);
6174 }
6175 return klass;
6176 }
6177
6178 if (n < FAST_CACHE_SIZE) {
6179 if (is_mvar)
6180 return image->mvar_cache_fast ? image->mvar_cache_fast [n] : NULL;
6181 else
6182 return image->var_cache_fast ? image->var_cache_fast [n] : NULL;
6183 } else {
6184 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6185 if (ht) {
6186 if (take_lock)
6187 mono_image_lock (image);
6188 klass = (MonoClass *)g_hash_table_lookup (ht, GINT_TO_POINTER (n));
6189 if (take_lock)
6190 mono_image_unlock (image);
6191 }
6192 return klass;
6193 }
6194 }
6195
6196 /*
6197 * LOCKING: Image lock (param->image) must be held
6198 */
6199 static void
set_anon_gparam_class(MonoGenericParam * param,MonoClass * klass)6200 set_anon_gparam_class (MonoGenericParam *param, MonoClass *klass)
6201 {
6202 int n = mono_generic_param_num (param);
6203 MonoImage *image = get_image_for_generic_param (param);
6204 gboolean is_mvar = mono_generic_param_owner (param)->is_method;
6205
6206 g_assert (image);
6207
6208 if (param->gshared_constraint) {
6209 GHashTable *ht = is_mvar ? image->mvar_cache_constrained : image->var_cache_constrained;
6210 if (!ht) {
6211 ht = g_hash_table_new ((GHashFunc)mono_metadata_generic_param_hash, (GEqualFunc)mono_metadata_generic_param_equal);
6212 mono_memory_barrier ();
6213 if (is_mvar)
6214 image->mvar_cache_constrained = ht;
6215 else
6216 image->var_cache_constrained = ht;
6217 }
6218 g_hash_table_insert (ht, param, klass);
6219 } else if (n < FAST_CACHE_SIZE) {
6220 if (is_mvar) {
6221 /* Requires locking to avoid droping an already published class */
6222 if (!image->mvar_cache_fast)
6223 image->mvar_cache_fast = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6224 image->mvar_cache_fast [n] = klass;
6225 } else {
6226 if (!image->var_cache_fast)
6227 image->var_cache_fast = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6228 image->var_cache_fast [n] = klass;
6229 }
6230 } else {
6231 GHashTable *ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6232 if (!ht) {
6233 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6234 if (!ht) {
6235 ht = g_hash_table_new (NULL, NULL);
6236 mono_memory_barrier ();
6237 if (is_mvar)
6238 image->mvar_cache_slow = ht;
6239 else
6240 image->var_cache_slow = ht;
6241 }
6242 }
6243 g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
6244 }
6245 }
6246
6247 /*
6248 * LOCKING: Acquires the image lock (@image).
6249 */
6250 MonoClass *
mono_class_from_generic_parameter_internal(MonoGenericParam * param)6251 mono_class_from_generic_parameter_internal (MonoGenericParam *param)
6252 {
6253 MonoImage *image = get_image_for_generic_param (param);
6254 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
6255 MonoClass *klass, *klass2;
6256
6257 // If a klass already exists for this object and is cached, return it.
6258 if (pinfo) // Non-anonymous
6259 klass = pinfo->pklass;
6260 else // Anonymous
6261 klass = get_anon_gparam_class (param, TRUE);
6262
6263 if (klass)
6264 return klass;
6265
6266 // Create a new klass
6267 klass = make_generic_param_class (param, pinfo);
6268
6269 // Now we need to cache the klass we created.
6270 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
6271 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
6272 // and allow our newly-created klass object to just leak.
6273 mono_memory_barrier ();
6274
6275 mono_image_lock (image);
6276
6277 // Here "klass2" refers to the klass potentially created by the other thread.
6278 if (pinfo) // Repeat check from above
6279 klass2 = pinfo->pklass;
6280 else
6281 klass2 = get_anon_gparam_class (param, FALSE);
6282
6283 if (klass2) {
6284 klass = klass2;
6285 } else {
6286 // Cache here
6287 if (pinfo)
6288 pinfo->pklass = klass;
6289 else
6290 set_anon_gparam_class (param, klass);
6291 }
6292 mono_image_unlock (image);
6293
6294 /* FIXME: Should this go inside 'make_generic_param_klass'? */
6295 if (klass2)
6296 MONO_PROFILER_RAISE (class_failed, (klass2));
6297 else
6298 MONO_PROFILER_RAISE (class_loaded, (klass));
6299
6300 return klass;
6301 }
6302
6303 /**
6304 * mono_class_from_generic_parameter:
6305 * \param param Parameter to find/construct a class for.
6306 * \param arg2 Is ignored.
6307 * \param arg3 Is ignored.
6308 */
6309 MonoClass *
mono_class_from_generic_parameter(MonoGenericParam * param,MonoImage * arg2 G_GNUC_UNUSED,gboolean arg3 G_GNUC_UNUSED)6310 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GNUC_UNUSED, gboolean arg3 G_GNUC_UNUSED)
6311 {
6312 return mono_class_from_generic_parameter_internal (param);
6313 }
6314
6315 /**
6316 * mono_ptr_class_get:
6317 */
6318 MonoClass *
mono_ptr_class_get(MonoType * type)6319 mono_ptr_class_get (MonoType *type)
6320 {
6321 MonoClass *result;
6322 MonoClass *el_class;
6323 MonoImage *image;
6324 char *name;
6325 MonoImageSet* image_set;
6326
6327 el_class = mono_class_from_mono_type (type);
6328 image = el_class->image;
6329 image_set = class_kind_may_contain_generic_instances (el_class->class_kind) ? mono_metadata_get_image_set_for_class (el_class) : NULL;
6330
6331 if (image_set) {
6332 mono_image_set_lock (image_set);
6333 if (image_set->ptr_cache) {
6334 if ((result = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
6335 mono_image_set_unlock (image_set);
6336 return result;
6337 }
6338 }
6339 mono_image_set_unlock (image_set);
6340 } else {
6341 mono_image_lock (image);
6342 if (image->ptr_cache) {
6343 if ((result = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
6344 mono_image_unlock (image);
6345 return result;
6346 }
6347 }
6348 mono_image_unlock (image);
6349 }
6350
6351 result = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassPointer)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
6352
6353 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
6354 ++class_pointer_count;
6355
6356 result->parent = NULL; /* no parent for PTR types */
6357 result->name_space = el_class->name_space;
6358 name = g_strdup_printf ("%s*", el_class->name);
6359 result->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
6360 result->class_kind = MONO_CLASS_POINTER;
6361 g_free (name);
6362
6363 MONO_PROFILER_RAISE (class_loading, (result));
6364
6365 result->image = el_class->image;
6366 result->inited = TRUE;
6367 result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
6368 result->min_align = sizeof (gpointer);
6369 result->cast_class = result->element_class = el_class;
6370 result->blittable = TRUE;
6371
6372 result->byval_arg.type = MONO_TYPE_PTR;
6373 result->this_arg.type = result->byval_arg.type;
6374 result->this_arg.data.type = result->byval_arg.data.type = &result->element_class->byval_arg;
6375 result->this_arg.byref = TRUE;
6376
6377 mono_class_setup_supertypes (result);
6378
6379 if (image_set) {
6380 mono_image_set_lock (image_set);
6381 if (image_set->ptr_cache) {
6382 MonoClass *result2;
6383 if ((result2 = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
6384 mono_image_set_unlock (image_set);
6385 MONO_PROFILER_RAISE (class_failed, (result));
6386 return result2;
6387 }
6388 }
6389 else {
6390 image_set->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6391 }
6392 g_hash_table_insert (image_set->ptr_cache, el_class, result);
6393 mono_image_set_unlock (image_set);
6394 } else {
6395 mono_image_lock (image);
6396 if (image->ptr_cache) {
6397 MonoClass *result2;
6398 if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
6399 mono_image_unlock (image);
6400 MONO_PROFILER_RAISE (class_failed, (result));
6401 return result2;
6402 }
6403 } else {
6404 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6405 }
6406 g_hash_table_insert (image->ptr_cache, el_class, result);
6407 mono_image_unlock (image);
6408 }
6409
6410 MONO_PROFILER_RAISE (class_loaded, (result));
6411
6412 return result;
6413 }
6414
6415 static MonoClass *
mono_fnptr_class_get(MonoMethodSignature * sig)6416 mono_fnptr_class_get (MonoMethodSignature *sig)
6417 {
6418 MonoClass *result, *cached;
6419 static GHashTable *ptr_hash = NULL;
6420
6421 /* FIXME: These should be allocate from a mempool as well, but which one ? */
6422
6423 mono_loader_lock ();
6424 if (!ptr_hash)
6425 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
6426 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
6427 mono_loader_unlock ();
6428 if (cached)
6429 return cached;
6430
6431 result = g_new0 (MonoClass, 1);
6432
6433 result->parent = NULL; /* no parent for PTR types */
6434 result->name_space = "System";
6435 result->name = "MonoFNPtrFakeClass";
6436 result->class_kind = MONO_CLASS_POINTER;
6437
6438 result->image = mono_defaults.corlib; /* need to fix... */
6439 result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
6440 result->min_align = sizeof (gpointer);
6441 result->cast_class = result->element_class = result;
6442 result->byval_arg.type = MONO_TYPE_FNPTR;
6443 result->this_arg.type = result->byval_arg.type;
6444 result->this_arg.data.method = result->byval_arg.data.method = sig;
6445 result->this_arg.byref = TRUE;
6446 result->blittable = TRUE;
6447 result->inited = TRUE;
6448
6449 mono_class_setup_supertypes (result);
6450
6451 mono_loader_lock ();
6452
6453 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
6454 if (cached) {
6455 g_free (result);
6456 mono_loader_unlock ();
6457 return cached;
6458 }
6459
6460 MONO_PROFILER_RAISE (class_loading, (result));
6461
6462 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
6463 ++class_pointer_count;
6464
6465 g_hash_table_insert (ptr_hash, sig, result);
6466
6467 mono_loader_unlock ();
6468
6469 MONO_PROFILER_RAISE (class_loaded, (result));
6470
6471 return result;
6472 }
6473
6474 /**
6475 * mono_class_from_mono_type:
6476 * \param type describes the type to return
6477 * \returns a \c MonoClass for the specified \c MonoType, the value is never NULL.
6478 */
6479 MonoClass *
mono_class_from_mono_type(MonoType * type)6480 mono_class_from_mono_type (MonoType *type)
6481 {
6482 switch (type->type) {
6483 case MONO_TYPE_OBJECT:
6484 return type->data.klass? type->data.klass: mono_defaults.object_class;
6485 case MONO_TYPE_VOID:
6486 return type->data.klass? type->data.klass: mono_defaults.void_class;
6487 case MONO_TYPE_BOOLEAN:
6488 return type->data.klass? type->data.klass: mono_defaults.boolean_class;
6489 case MONO_TYPE_CHAR:
6490 return type->data.klass? type->data.klass: mono_defaults.char_class;
6491 case MONO_TYPE_I1:
6492 return type->data.klass? type->data.klass: mono_defaults.sbyte_class;
6493 case MONO_TYPE_U1:
6494 return type->data.klass? type->data.klass: mono_defaults.byte_class;
6495 case MONO_TYPE_I2:
6496 return type->data.klass? type->data.klass: mono_defaults.int16_class;
6497 case MONO_TYPE_U2:
6498 return type->data.klass? type->data.klass: mono_defaults.uint16_class;
6499 case MONO_TYPE_I4:
6500 return type->data.klass? type->data.klass: mono_defaults.int32_class;
6501 case MONO_TYPE_U4:
6502 return type->data.klass? type->data.klass: mono_defaults.uint32_class;
6503 case MONO_TYPE_I:
6504 return type->data.klass? type->data.klass: mono_defaults.int_class;
6505 case MONO_TYPE_U:
6506 return type->data.klass? type->data.klass: mono_defaults.uint_class;
6507 case MONO_TYPE_I8:
6508 return type->data.klass? type->data.klass: mono_defaults.int64_class;
6509 case MONO_TYPE_U8:
6510 return type->data.klass? type->data.klass: mono_defaults.uint64_class;
6511 case MONO_TYPE_R4:
6512 return type->data.klass? type->data.klass: mono_defaults.single_class;
6513 case MONO_TYPE_R8:
6514 return type->data.klass? type->data.klass: mono_defaults.double_class;
6515 case MONO_TYPE_STRING:
6516 return type->data.klass? type->data.klass: mono_defaults.string_class;
6517 case MONO_TYPE_TYPEDBYREF:
6518 return type->data.klass? type->data.klass: mono_defaults.typed_reference_class;
6519 case MONO_TYPE_ARRAY:
6520 return mono_bounded_array_class_get (type->data.array->eklass, type->data.array->rank, TRUE);
6521 case MONO_TYPE_PTR:
6522 return mono_ptr_class_get (type->data.type);
6523 case MONO_TYPE_FNPTR:
6524 return mono_fnptr_class_get (type->data.method);
6525 case MONO_TYPE_SZARRAY:
6526 return mono_array_class_get (type->data.klass, 1);
6527 case MONO_TYPE_CLASS:
6528 case MONO_TYPE_VALUETYPE:
6529 return type->data.klass;
6530 case MONO_TYPE_GENERICINST:
6531 return mono_generic_class_get_class (type->data.generic_class);
6532 case MONO_TYPE_MVAR:
6533 case MONO_TYPE_VAR:
6534 return mono_class_from_generic_parameter_internal (type->data.generic_param);
6535 default:
6536 g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
6537 g_assert_not_reached ();
6538 }
6539
6540 // Yes, this returns NULL, even if it is documented as not doing so, but there
6541 // is no way for the code to make it this far, due to the assert above.
6542 return NULL;
6543 }
6544
6545 /**
6546 * mono_type_retrieve_from_typespec
6547 * \param image context where the image is created
6548 * \param type_spec typespec token
6549 * \param context the generic context used to evaluate generic instantiations in
6550 */
6551 static MonoType *
mono_type_retrieve_from_typespec(MonoImage * image,guint32 type_spec,MonoGenericContext * context,gboolean * did_inflate,MonoError * error)6552 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
6553 {
6554 MonoType *t = mono_type_create_from_typespec_checked (image, type_spec, error);
6555
6556 *did_inflate = FALSE;
6557
6558 if (!t)
6559 return NULL;
6560
6561 if (context && (context->class_inst || context->method_inst)) {
6562 MonoType *inflated = inflate_generic_type (NULL, t, context, error);
6563
6564 if (!mono_error_ok (error)) {
6565 return NULL;
6566 }
6567
6568 if (inflated) {
6569 t = inflated;
6570 *did_inflate = TRUE;
6571 }
6572 }
6573 return t;
6574 }
6575
6576 /**
6577 * mono_class_create_from_typespec
6578 * \param image context where the image is created
6579 * \param type_spec typespec token
6580 * \param context the generic context used to evaluate generic instantiations in
6581 */
6582 static MonoClass *
mono_class_create_from_typespec(MonoImage * image,guint32 type_spec,MonoGenericContext * context,MonoError * error)6583 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
6584 {
6585 MonoClass *ret;
6586 gboolean inflated = FALSE;
6587 MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
6588 return_val_if_nok (error, NULL);
6589 ret = mono_class_from_mono_type (t);
6590 if (inflated)
6591 mono_metadata_free_type (t);
6592 return ret;
6593 }
6594
6595 /**
6596 * mono_bounded_array_class_get:
6597 * \param element_class element class
6598 * \param rank the dimension of the array class
6599 * \param bounded whenever the array has non-zero bounds
6600 * \returns A class object describing the array with element type \p element_type and
6601 * dimension \p rank.
6602 */
6603 MonoClass *
mono_bounded_array_class_get(MonoClass * eclass,guint32 rank,gboolean bounded)6604 mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
6605 {
6606 MonoImage *image;
6607 MonoClass *klass, *cached, *k;
6608 MonoClass *parent = NULL;
6609 GSList *list, *rootlist = NULL;
6610 int nsize;
6611 char *name;
6612 MonoImageSet* image_set;
6613
6614 g_assert (rank <= 255);
6615
6616 if (rank > 1)
6617 /* bounded only matters for one-dimensional arrays */
6618 bounded = FALSE;
6619
6620 image = eclass->image;
6621 image_set = class_kind_may_contain_generic_instances (eclass->class_kind) ? mono_metadata_get_image_set_for_class (eclass) : NULL;
6622
6623 /* Check cache */
6624 cached = NULL;
6625 if (rank == 1 && !bounded) {
6626 if (image_set) {
6627 mono_image_set_lock (image_set);
6628 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
6629 mono_image_set_unlock (image_set);
6630 } else {
6631 /*
6632 * This case is very frequent not just during compilation because of calls
6633 * from mono_class_from_mono_type (), mono_array_new (),
6634 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
6635 */
6636 mono_os_mutex_lock (&image->szarray_cache_lock);
6637 if (!image->szarray_cache)
6638 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6639 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
6640 mono_os_mutex_unlock (&image->szarray_cache_lock);
6641 }
6642 } else {
6643 if (image_set) {
6644 mono_image_set_lock (image_set);
6645 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
6646 for (list = rootlist; list; list = list->next) {
6647 k = (MonoClass *)list->data;
6648 if ((k->rank == rank) && (k->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
6649 cached = k;
6650 break;
6651 }
6652 }
6653 mono_image_set_unlock (image_set);
6654 } else {
6655 mono_loader_lock ();
6656 if (!image->array_cache)
6657 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6658 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
6659 for (list = rootlist; list; list = list->next) {
6660 k = (MonoClass *)list->data;
6661 if ((k->rank == rank) && (k->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
6662 cached = k;
6663 break;
6664 }
6665 }
6666 mono_loader_unlock ();
6667 }
6668 }
6669 if (cached)
6670 return cached;
6671
6672 parent = mono_defaults.array_class;
6673 if (!parent->inited)
6674 mono_class_init (parent);
6675
6676 klass = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassArray)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
6677
6678 klass->image = image;
6679 klass->name_space = eclass->name_space;
6680 klass->class_kind = MONO_CLASS_ARRAY;
6681
6682 nsize = strlen (eclass->name);
6683 name = (char *)g_malloc (nsize + 2 + rank + 1);
6684 memcpy (name, eclass->name, nsize);
6685 name [nsize] = '[';
6686 if (rank > 1)
6687 memset (name + nsize + 1, ',', rank - 1);
6688 if (bounded)
6689 name [nsize + rank] = '*';
6690 name [nsize + rank + bounded] = ']';
6691 name [nsize + rank + bounded + 1] = 0;
6692 klass->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
6693 g_free (name);
6694
6695 klass->type_token = 0;
6696 klass->parent = parent;
6697 klass->instance_size = mono_class_instance_size (klass->parent);
6698
6699 if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF) {
6700 /*Arrays of those two types are invalid.*/
6701 MonoError prepared_error;
6702 error_init (&prepared_error);
6703 mono_error_set_invalid_program (&prepared_error, "Arrays of System.TypedReference types are invalid.");
6704 mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
6705 mono_error_cleanup (&prepared_error);
6706 } else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
6707 guint32 ref_info_handle = mono_class_get_ref_info_handle (eclass);
6708 if (!ref_info_handle || eclass->wastypebuilder) {
6709 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
6710 g_assert (ref_info_handle && !eclass->wastypebuilder);
6711 }
6712 /* element_size -1 is ok as this is not an instantitable type*/
6713 klass->sizes.element_size = -1;
6714 } else
6715 klass->sizes.element_size = -1;
6716
6717 mono_class_setup_supertypes (klass);
6718
6719 if (mono_class_is_ginst (eclass))
6720 mono_class_init (eclass);
6721 if (!eclass->size_inited)
6722 mono_class_setup_fields (eclass);
6723 mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
6724 /*FIXME we fail the array type, but we have to let other fields be set.*/
6725
6726 klass->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
6727
6728 klass->rank = rank;
6729
6730 if (eclass->enumtype)
6731 klass->cast_class = eclass->element_class;
6732 else
6733 klass->cast_class = eclass;
6734
6735 switch (klass->cast_class->byval_arg.type) {
6736 case MONO_TYPE_I1:
6737 klass->cast_class = mono_defaults.byte_class;
6738 break;
6739 case MONO_TYPE_U2:
6740 klass->cast_class = mono_defaults.int16_class;
6741 break;
6742 case MONO_TYPE_U4:
6743 #if SIZEOF_VOID_P == 4
6744 case MONO_TYPE_I:
6745 case MONO_TYPE_U:
6746 #endif
6747 klass->cast_class = mono_defaults.int32_class;
6748 break;
6749 case MONO_TYPE_U8:
6750 #if SIZEOF_VOID_P == 8
6751 case MONO_TYPE_I:
6752 case MONO_TYPE_U:
6753 #endif
6754 klass->cast_class = mono_defaults.int64_class;
6755 break;
6756 default:
6757 break;
6758 }
6759
6760 klass->element_class = eclass;
6761
6762 if ((rank > 1) || bounded) {
6763 MonoArrayType *at = image_set ? (MonoArrayType *)mono_image_set_alloc0 (image_set, sizeof (MonoArrayType)) : (MonoArrayType *)mono_image_alloc0 (image, sizeof (MonoArrayType));
6764 klass->byval_arg.type = MONO_TYPE_ARRAY;
6765 klass->byval_arg.data.array = at;
6766 at->eklass = eclass;
6767 at->rank = rank;
6768 /* FIXME: complete.... */
6769 } else {
6770 klass->byval_arg.type = MONO_TYPE_SZARRAY;
6771 klass->byval_arg.data.klass = eclass;
6772 }
6773 klass->this_arg = klass->byval_arg;
6774 klass->this_arg.byref = 1;
6775
6776 if (rank > 32) {
6777 MonoError prepared_error;
6778 error_init (&prepared_error);
6779 name = mono_type_get_full_name (klass);
6780 mono_error_set_type_load_class (&prepared_error, klass, "%s has too many dimensions.", name);
6781 mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
6782 mono_error_cleanup (&prepared_error);
6783 g_free (name);
6784 }
6785
6786 mono_loader_lock ();
6787
6788 /* Check cache again */
6789 cached = NULL;
6790 if (rank == 1 && !bounded) {
6791 if (image_set) {
6792 mono_image_set_lock (image_set);
6793 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
6794 mono_image_set_unlock (image_set);
6795 } else {
6796 mono_os_mutex_lock (&image->szarray_cache_lock);
6797 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
6798 mono_os_mutex_unlock (&image->szarray_cache_lock);
6799 }
6800 } else {
6801 if (image_set) {
6802 mono_image_set_lock (image_set);
6803 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
6804 for (list = rootlist; list; list = list->next) {
6805 k = (MonoClass *)list->data;
6806 if ((k->rank == rank) && (k->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
6807 cached = k;
6808 break;
6809 }
6810 }
6811 mono_image_set_unlock (image_set);
6812 } else {
6813 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
6814 for (list = rootlist; list; list = list->next) {
6815 k = (MonoClass *)list->data;
6816 if ((k->rank == rank) && (k->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
6817 cached = k;
6818 break;
6819 }
6820 }
6821 }
6822 }
6823 if (cached) {
6824 mono_loader_unlock ();
6825 return cached;
6826 }
6827
6828 MONO_PROFILER_RAISE (class_loading, (klass));
6829
6830 UnlockedAdd (&classes_size, sizeof (MonoClassArray));
6831 ++class_array_count;
6832
6833 if (rank == 1 && !bounded) {
6834 if (image_set) {
6835 mono_image_set_lock (image_set);
6836 g_hash_table_insert (image_set->szarray_cache, eclass, klass);
6837 mono_image_set_unlock (image_set);
6838 } else {
6839 mono_os_mutex_lock (&image->szarray_cache_lock);
6840 g_hash_table_insert (image->szarray_cache, eclass, klass);
6841 mono_os_mutex_unlock (&image->szarray_cache_lock);
6842 }
6843 } else {
6844 if (image_set) {
6845 mono_image_set_lock (image_set);
6846 list = g_slist_append (rootlist, klass);
6847 g_hash_table_insert (image_set->array_cache, eclass, list);
6848 mono_image_set_unlock (image_set);
6849 } else {
6850 list = g_slist_append (rootlist, klass);
6851 g_hash_table_insert (image->array_cache, eclass, list);
6852 }
6853 }
6854
6855 mono_loader_unlock ();
6856
6857 MONO_PROFILER_RAISE (class_loaded, (klass));
6858
6859 return klass;
6860 }
6861
6862 /**
6863 * mono_array_class_get:
6864 * \param element_class element class
6865 * \param rank the dimension of the array class
6866 * \returns A class object describing the array with element type \p element_type and
6867 * dimension \p rank.
6868 */
6869 MonoClass *
mono_array_class_get(MonoClass * eclass,guint32 rank)6870 mono_array_class_get (MonoClass *eclass, guint32 rank)
6871 {
6872 return mono_bounded_array_class_get (eclass, rank, FALSE);
6873 }
6874
6875 /**
6876 * mono_class_instance_size:
6877 * \param klass a class
6878 *
6879 * Use to get the size of a class in bytes.
6880 *
6881 * \returns The size of an object instance
6882 */
6883 gint32
mono_class_instance_size(MonoClass * klass)6884 mono_class_instance_size (MonoClass *klass)
6885 {
6886 if (!klass->size_inited)
6887 mono_class_init (klass);
6888
6889 return klass->instance_size;
6890 }
6891
6892 /**
6893 * mono_class_min_align:
6894 * \param klass a class
6895 *
6896 * Use to get the computed minimum alignment requirements for the specified class.
6897 *
6898 * Returns: minimum alignment requirements
6899 */
6900 gint32
mono_class_min_align(MonoClass * klass)6901 mono_class_min_align (MonoClass *klass)
6902 {
6903 if (!klass->size_inited)
6904 mono_class_init (klass);
6905
6906 return klass->min_align;
6907 }
6908
6909 /**
6910 * mono_class_value_size:
6911 * \param klass a class
6912 *
6913 * This function is used for value types, and return the
6914 * space and the alignment to store that kind of value object.
6915 *
6916 * \returns the size of a value of kind \p klass
6917 */
6918 gint32
mono_class_value_size(MonoClass * klass,guint32 * align)6919 mono_class_value_size (MonoClass *klass, guint32 *align)
6920 {
6921 gint32 size;
6922
6923 /* fixme: check disable, because we still have external revereces to
6924 * mscorlib and Dummy Objects
6925 */
6926 /*g_assert (klass->valuetype);*/
6927
6928 size = mono_class_instance_size (klass) - sizeof (MonoObject);
6929
6930 if (align)
6931 *align = klass->min_align;
6932
6933 return size;
6934 }
6935
6936 /**
6937 * mono_class_data_size:
6938 * \param klass a class
6939 *
6940 * \returns The size of the static class data
6941 */
6942 gint32
mono_class_data_size(MonoClass * klass)6943 mono_class_data_size (MonoClass *klass)
6944 {
6945 if (!klass->inited)
6946 mono_class_init (klass);
6947 /* This can happen with dynamically created types */
6948 if (!klass->fields_inited)
6949 mono_class_setup_fields (klass);
6950
6951 /* in arrays, sizes.class_size is unioned with element_size
6952 * and arrays have no static fields
6953 */
6954 if (klass->rank)
6955 return 0;
6956 return klass->sizes.class_size;
6957 }
6958
6959 /*
6960 * Auxiliary routine to mono_class_get_field
6961 *
6962 * Takes a field index instead of a field token.
6963 */
6964 static MonoClassField *
mono_class_get_field_idx(MonoClass * klass,int idx)6965 mono_class_get_field_idx (MonoClass *klass, int idx)
6966 {
6967 mono_class_setup_fields (klass);
6968 if (mono_class_has_failure (klass))
6969 return NULL;
6970
6971 while (klass) {
6972 int first_field_idx = mono_class_get_first_field_idx (klass);
6973 int fcount = mono_class_get_field_count (klass);
6974 if (klass->image->uncompressed_metadata) {
6975 /*
6976 * first_field_idx points to the FieldPtr table, while idx points into the
6977 * Field table, so we have to do a search.
6978 */
6979 /*FIXME this is broken for types with multiple fields with the same name.*/
6980 const char *name = mono_metadata_string_heap (klass->image, mono_metadata_decode_row_col (&klass->image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
6981 int i;
6982
6983 for (i = 0; i < fcount; ++i)
6984 if (mono_field_get_name (&klass->fields [i]) == name)
6985 return &klass->fields [i];
6986 g_assert_not_reached ();
6987 } else {
6988 if (fcount) {
6989 if ((idx >= first_field_idx) && (idx < first_field_idx + fcount)){
6990 return &klass->fields [idx - first_field_idx];
6991 }
6992 }
6993 }
6994 klass = klass->parent;
6995 }
6996 return NULL;
6997 }
6998
6999 /**
7000 * mono_class_get_field:
7001 * \param class the class to lookup the field.
7002 * \param field_token the field token
7003 *
7004 * \returns A \c MonoClassField representing the type and offset of
7005 * the field, or a NULL value if the field does not belong to this
7006 * class.
7007 */
7008 MonoClassField *
mono_class_get_field(MonoClass * klass,guint32 field_token)7009 mono_class_get_field (MonoClass *klass, guint32 field_token)
7010 {
7011 int idx = mono_metadata_token_index (field_token);
7012
7013 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
7014
7015 return mono_class_get_field_idx (klass, idx - 1);
7016 }
7017
7018 /**
7019 * mono_class_get_field_from_name:
7020 * \param klass the class to lookup the field.
7021 * \param name the field name
7022 *
7023 * Search the class \p klass and its parents for a field with the name \p name.
7024 *
7025 * \returns The \c MonoClassField pointer of the named field or NULL
7026 */
7027 MonoClassField *
mono_class_get_field_from_name(MonoClass * klass,const char * name)7028 mono_class_get_field_from_name (MonoClass *klass, const char *name)
7029 {
7030 return mono_class_get_field_from_name_full (klass, name, NULL);
7031 }
7032
7033 /**
7034 * mono_class_get_field_from_name_full:
7035 * \param klass the class to lookup the field.
7036 * \param name the field name
7037 * \param type the type of the fields. This optional.
7038 *
7039 * Search the class \p klass and it's parents for a field with the name \p name and type \p type.
7040 *
7041 * If \p klass is an inflated generic type, the type comparison is done with the equivalent field
7042 * of its generic type definition.
7043 *
7044 * \returns The MonoClassField pointer of the named field or NULL
7045 */
7046 MonoClassField *
mono_class_get_field_from_name_full(MonoClass * klass,const char * name,MonoType * type)7047 mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
7048 {
7049 int i;
7050
7051 mono_class_setup_fields (klass);
7052 if (mono_class_has_failure (klass))
7053 return NULL;
7054
7055 while (klass) {
7056 int fcount = mono_class_get_field_count (klass);
7057 for (i = 0; i < fcount; ++i) {
7058 MonoClassField *field = &klass->fields [i];
7059
7060 if (strcmp (name, mono_field_get_name (field)) != 0)
7061 continue;
7062
7063 if (type) {
7064 MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
7065 if (!mono_metadata_type_equal_full (type, field_type, TRUE))
7066 continue;
7067 }
7068 return field;
7069 }
7070 klass = klass->parent;
7071 }
7072 return NULL;
7073 }
7074
7075 /**
7076 * mono_class_get_field_token:
7077 * \param field the field we need the token of
7078 *
7079 * Get the token of a field. Note that the tokesn is only valid for the image
7080 * the field was loaded from. Don't use this function for fields in dynamic types.
7081 *
7082 * \returns The token representing the field in the image it was loaded from.
7083 */
7084 guint32
mono_class_get_field_token(MonoClassField * field)7085 mono_class_get_field_token (MonoClassField *field)
7086 {
7087 MonoClass *klass = field->parent;
7088 int i;
7089
7090 mono_class_setup_fields (klass);
7091
7092 while (klass) {
7093 if (!klass->fields)
7094 return 0;
7095 int first_field_idx = mono_class_get_first_field_idx (klass);
7096 int fcount = mono_class_get_field_count (klass);
7097 for (i = 0; i < fcount; ++i) {
7098 if (&klass->fields [i] == field) {
7099 int idx = first_field_idx + i + 1;
7100
7101 if (klass->image->uncompressed_metadata)
7102 idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx);
7103 return mono_metadata_make_token (MONO_TABLE_FIELD, idx);
7104 }
7105 }
7106 klass = klass->parent;
7107 }
7108
7109 g_assert_not_reached ();
7110 return 0;
7111 }
7112
7113 static int
mono_field_get_index(MonoClassField * field)7114 mono_field_get_index (MonoClassField *field)
7115 {
7116 int index = field - field->parent->fields;
7117 g_assert (index >= 0 && index < mono_class_get_field_count (field->parent));
7118
7119 return index;
7120 }
7121
7122 /*
7123 * mono_class_get_field_default_value:
7124 *
7125 * Return the default value of the field as a pointer into the metadata blob.
7126 */
7127 const char*
mono_class_get_field_default_value(MonoClassField * field,MonoTypeEnum * def_type)7128 mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
7129 {
7130 guint32 cindex;
7131 guint32 constant_cols [MONO_CONSTANT_SIZE];
7132 int field_index;
7133 MonoClass *klass = field->parent;
7134 MonoFieldDefaultValue *def_values;
7135
7136 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
7137
7138 def_values = mono_class_get_field_def_values (klass);
7139 if (!def_values) {
7140 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
7141
7142 mono_class_set_field_def_values (klass, def_values);
7143 }
7144
7145 field_index = mono_field_get_index (field);
7146
7147 if (!def_values [field_index].data) {
7148 cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
7149 if (!cindex)
7150 return NULL;
7151
7152 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
7153
7154 mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
7155 def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
7156 mono_memory_barrier ();
7157 def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
7158 }
7159
7160 *def_type = def_values [field_index].def_type;
7161 return def_values [field_index].data;
7162 }
7163
7164 static int
mono_property_get_index(MonoProperty * prop)7165 mono_property_get_index (MonoProperty *prop)
7166 {
7167 MonoClassPropertyInfo *info = mono_class_get_property_info (prop->parent);
7168 int index = prop - info->properties;
7169
7170 g_assert (index >= 0 && index < info->count);
7171
7172 return index;
7173 }
7174
7175 /*
7176 * mono_class_get_property_default_value:
7177 *
7178 * Return the default value of the field as a pointer into the metadata blob.
7179 */
7180 const char*
mono_class_get_property_default_value(MonoProperty * property,MonoTypeEnum * def_type)7181 mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type)
7182 {
7183 guint32 cindex;
7184 guint32 constant_cols [MONO_CONSTANT_SIZE];
7185 MonoClass *klass = property->parent;
7186
7187 g_assert (property->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT);
7188 /*
7189 * We don't cache here because it is not used by C# so it's quite rare, but
7190 * we still do the lookup in klass->ext because that is where the data
7191 * is stored for dynamic assemblies.
7192 */
7193
7194 if (image_is_dynamic (klass->image)) {
7195 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
7196 int prop_index = mono_property_get_index (property);
7197 if (info->def_values && info->def_values [prop_index].data) {
7198 *def_type = info->def_values [prop_index].def_type;
7199 return info->def_values [prop_index].data;
7200 }
7201 return NULL;
7202 }
7203 cindex = mono_metadata_get_constant_index (klass->image, mono_class_get_property_token (property), 0);
7204 if (!cindex)
7205 return NULL;
7206
7207 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
7208 *def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
7209 return (const char *)mono_metadata_blob_heap (klass->image, constant_cols [MONO_CONSTANT_VALUE]);
7210 }
7211
7212 /**
7213 * mono_class_get_event_token:
7214 */
7215 guint32
mono_class_get_event_token(MonoEvent * event)7216 mono_class_get_event_token (MonoEvent *event)
7217 {
7218 MonoClass *klass = event->parent;
7219 int i;
7220
7221 while (klass) {
7222 MonoClassEventInfo *info = mono_class_get_event_info (klass);
7223 if (info) {
7224 for (i = 0; i < info->count; ++i) {
7225 if (&info->events [i] == event)
7226 return mono_metadata_make_token (MONO_TABLE_EVENT, info->first + i + 1);
7227 }
7228 }
7229 klass = klass->parent;
7230 }
7231
7232 g_assert_not_reached ();
7233 return 0;
7234 }
7235
7236 /**
7237 * mono_class_get_property_from_name:
7238 * \param klass a class
7239 * \param name name of the property to lookup in the specified class
7240 *
7241 * Use this method to lookup a property in a class
7242 * \returns the \c MonoProperty with the given name, or NULL if the property
7243 * does not exist on the \p klass.
7244 */
7245 MonoProperty*
mono_class_get_property_from_name(MonoClass * klass,const char * name)7246 mono_class_get_property_from_name (MonoClass *klass, const char *name)
7247 {
7248 while (klass) {
7249 MonoProperty* p;
7250 gpointer iter = NULL;
7251 while ((p = mono_class_get_properties (klass, &iter))) {
7252 if (! strcmp (name, p->name))
7253 return p;
7254 }
7255 klass = klass->parent;
7256 }
7257 return NULL;
7258 }
7259
7260 /**
7261 * mono_class_get_property_token:
7262 * \param prop MonoProperty to query
7263 *
7264 * \returns The ECMA token for the specified property.
7265 */
7266 guint32
mono_class_get_property_token(MonoProperty * prop)7267 mono_class_get_property_token (MonoProperty *prop)
7268 {
7269 MonoClass *klass = prop->parent;
7270 while (klass) {
7271 MonoProperty* p;
7272 int i = 0;
7273 gpointer iter = NULL;
7274 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
7275 while ((p = mono_class_get_properties (klass, &iter))) {
7276 if (&info->properties [i] == prop)
7277 return mono_metadata_make_token (MONO_TABLE_PROPERTY, info->first + i + 1);
7278
7279 i ++;
7280 }
7281 klass = klass->parent;
7282 }
7283
7284 g_assert_not_reached ();
7285 return 0;
7286 }
7287
7288 /**
7289 * mono_class_name_from_token:
7290 */
7291 char *
mono_class_name_from_token(MonoImage * image,guint32 type_token)7292 mono_class_name_from_token (MonoImage *image, guint32 type_token)
7293 {
7294 const char *name, *nspace;
7295 if (image_is_dynamic (image))
7296 return g_strdup_printf ("DynamicType 0x%08x", type_token);
7297
7298 switch (type_token & 0xff000000){
7299 case MONO_TOKEN_TYPE_DEF: {
7300 guint32 cols [MONO_TYPEDEF_SIZE];
7301 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
7302 guint tidx = mono_metadata_token_index (type_token);
7303
7304 if (tidx > tt->rows)
7305 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7306
7307 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
7308 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7309 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7310 if (strlen (nspace) == 0)
7311 return g_strdup_printf ("%s", name);
7312 else
7313 return g_strdup_printf ("%s.%s", nspace, name);
7314 }
7315
7316 case MONO_TOKEN_TYPE_REF: {
7317 MonoError error;
7318 guint32 cols [MONO_TYPEREF_SIZE];
7319 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
7320 guint tidx = mono_metadata_token_index (type_token);
7321
7322 if (tidx > t->rows)
7323 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7324
7325 if (!mono_verifier_verify_typeref_row (image, tidx - 1, &error)) {
7326 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7327 mono_error_cleanup (&error);
7328 return msg;
7329 }
7330
7331 mono_metadata_decode_row (t, tidx-1, cols, MONO_TYPEREF_SIZE);
7332 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
7333 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
7334 if (strlen (nspace) == 0)
7335 return g_strdup_printf ("%s", name);
7336 else
7337 return g_strdup_printf ("%s.%s", nspace, name);
7338 }
7339
7340 case MONO_TOKEN_TYPE_SPEC:
7341 return g_strdup_printf ("Typespec 0x%08x", type_token);
7342 default:
7343 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7344 }
7345 }
7346
7347 static char *
mono_assembly_name_from_token(MonoImage * image,guint32 type_token)7348 mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
7349 {
7350 if (image_is_dynamic (image))
7351 return g_strdup_printf ("DynamicAssembly %s", image->name);
7352
7353 switch (type_token & 0xff000000){
7354 case MONO_TOKEN_TYPE_DEF:
7355 if (image->assembly)
7356 return mono_stringify_assembly_name (&image->assembly->aname);
7357 else if (image->assembly_name)
7358 return g_strdup (image->assembly_name);
7359 return g_strdup_printf ("%s", image->name ? image->name : "[Could not resolve assembly name");
7360 case MONO_TOKEN_TYPE_REF: {
7361 MonoError error;
7362 MonoAssemblyName aname;
7363 guint32 cols [MONO_TYPEREF_SIZE];
7364 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
7365 guint32 idx = mono_metadata_token_index (type_token);
7366
7367 if (idx > t->rows)
7368 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7369
7370 if (!mono_verifier_verify_typeref_row (image, idx - 1, &error)) {
7371 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7372 mono_error_cleanup (&error);
7373 return msg;
7374 }
7375 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
7376
7377 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
7378 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
7379 case MONO_RESOLUTION_SCOPE_MODULE:
7380 /* FIXME: */
7381 return g_strdup ("");
7382 case MONO_RESOLUTION_SCOPE_MODULEREF:
7383 /* FIXME: */
7384 return g_strdup ("");
7385 case MONO_RESOLUTION_SCOPE_TYPEREF:
7386 /* FIXME: */
7387 return g_strdup ("");
7388 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
7389 mono_assembly_get_assemblyref (image, idx - 1, &aname);
7390 return mono_stringify_assembly_name (&aname);
7391 default:
7392 g_assert_not_reached ();
7393 }
7394 break;
7395 }
7396 case MONO_TOKEN_TYPE_SPEC:
7397 /* FIXME: */
7398 return g_strdup ("");
7399 default:
7400 g_assert_not_reached ();
7401 }
7402
7403 return NULL;
7404 }
7405
7406 /**
7407 * mono_class_get_full:
7408 * \param image the image where the class resides
7409 * \param type_token the token for the class
7410 * \param context the generic context used to evaluate generic instantiations in
7411 * \deprecated Functions that expose \c MonoGenericContext are going away in mono 4.0
7412 * \returns The \c MonoClass that represents \p type_token in \p image
7413 */
7414 MonoClass *
mono_class_get_full(MonoImage * image,guint32 type_token,MonoGenericContext * context)7415 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
7416 {
7417 MonoError error;
7418 MonoClass *klass;
7419 klass = mono_class_get_checked (image, type_token, &error);
7420
7421 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
7422 klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7423
7424 g_assert (mono_error_ok (&error)); /* FIXME deprecate this function and forbit the runtime from using it. */
7425 return klass;
7426 }
7427
7428
7429 MonoClass *
mono_class_get_and_inflate_typespec_checked(MonoImage * image,guint32 type_token,MonoGenericContext * context,MonoError * error)7430 mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
7431 {
7432 MonoClass *klass;
7433
7434 error_init (error);
7435 klass = mono_class_get_checked (image, type_token, error);
7436
7437 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
7438 klass = mono_class_inflate_generic_class_checked (klass, context, error);
7439
7440 return klass;
7441 }
7442 /**
7443 * mono_class_get_checked:
7444 * \param image the image where the class resides
7445 * \param type_token the token for the class
7446 * \param error error object to return any error
7447 *
7448 * \returns The MonoClass that represents \p type_token in \p image, or NULL on error.
7449 */
7450 MonoClass *
mono_class_get_checked(MonoImage * image,guint32 type_token,MonoError * error)7451 mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
7452 {
7453 MonoClass *klass = NULL;
7454
7455 error_init (error);
7456
7457 if (image_is_dynamic (image)) {
7458 int table = mono_metadata_token_table (type_token);
7459
7460 if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
7461 mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
7462 return NULL;
7463 }
7464 klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
7465 goto done;
7466 }
7467
7468 switch (type_token & 0xff000000){
7469 case MONO_TOKEN_TYPE_DEF:
7470 klass = mono_class_create_from_typedef (image, type_token, error);
7471 break;
7472 case MONO_TOKEN_TYPE_REF:
7473 klass = mono_class_from_typeref_checked (image, type_token, error);
7474 break;
7475 case MONO_TOKEN_TYPE_SPEC:
7476 klass = mono_class_create_from_typespec (image, type_token, NULL, error);
7477 break;
7478 default:
7479 mono_error_set_bad_image (error, image, "Unknown type token %x", type_token & 0xff000000);
7480 }
7481
7482 done:
7483 /* Generic case, should be avoided for when a better error is possible. */
7484 if (!klass && mono_error_ok (error)) {
7485 char *name = mono_class_name_from_token (image, type_token);
7486 char *assembly = mono_assembly_name_from_token (image, type_token);
7487 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x (class/assembly %s, %s)", type_token, name, assembly);
7488 }
7489
7490 return klass;
7491 }
7492
7493
7494 /**
7495 * mono_type_get_checked:
7496 * \param image the image where the type resides
7497 * \param type_token the token for the type
7498 * \param context the generic context used to evaluate generic instantiations in
7499 * \param error Error handling context
7500 *
7501 * This functions exists to fullfill the fact that sometimes it's desirable to have access to the
7502 *
7503 * \returns The MonoType that represents \p type_token in \p image
7504 */
7505 MonoType *
mono_type_get_checked(MonoImage * image,guint32 type_token,MonoGenericContext * context,MonoError * error)7506 mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
7507 {
7508 MonoType *type = NULL;
7509 gboolean inflated = FALSE;
7510
7511 error_init (error);
7512
7513 //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
7514 if (image_is_dynamic (image)) {
7515 MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
7516 return_val_if_nok (error, NULL);
7517 return mono_class_get_type (klass);
7518 }
7519
7520 if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
7521 MonoClass *klass = mono_class_get_checked (image, type_token, error);
7522
7523 if (!klass) {
7524 return NULL;
7525 }
7526
7527 g_assert (klass);
7528 return mono_class_get_type (klass);
7529 }
7530
7531 type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
7532
7533 if (!type) {
7534 return NULL;
7535 }
7536
7537 if (inflated) {
7538 MonoType *tmp = type;
7539 type = mono_class_get_type (mono_class_from_mono_type (type));
7540 /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
7541 * A MonoClass::byval_arg of a generic type definion has type CLASS.
7542 * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with byval_arg.
7543 *
7544 * The long term solution is to chaise this places and make then set MonoType::type correctly.
7545 * */
7546 if (type->type != tmp->type)
7547 type = tmp;
7548 else
7549 mono_metadata_free_type (tmp);
7550 }
7551 return type;
7552 }
7553
7554 /**
7555 * mono_class_get:
7556 * \param image image where the class token will be looked up.
7557 * \param type_token a type token from the image
7558 * \returns the \c MonoClass with the given \p type_token on the \p image
7559 */
7560 MonoClass *
mono_class_get(MonoImage * image,guint32 type_token)7561 mono_class_get (MonoImage *image, guint32 type_token)
7562 {
7563 return mono_class_get_full (image, type_token, NULL);
7564 }
7565
7566 /**
7567 * mono_image_init_name_cache:
7568 *
7569 * Initializes the class name cache stored in image->name_cache.
7570 *
7571 * LOCKING: Acquires the corresponding image lock.
7572 */
7573 void
mono_image_init_name_cache(MonoImage * image)7574 mono_image_init_name_cache (MonoImage *image)
7575 {
7576 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7577 guint32 cols [MONO_TYPEDEF_SIZE];
7578 const char *name;
7579 const char *nspace;
7580 guint32 i, visib, nspace_index;
7581 GHashTable *name_cache2, *nspace_table, *the_name_cache;
7582
7583 if (image->name_cache)
7584 return;
7585
7586 the_name_cache = g_hash_table_new (g_str_hash, g_str_equal);
7587
7588 if (image_is_dynamic (image)) {
7589 mono_image_lock (image);
7590 if (image->name_cache) {
7591 /* Somebody initialized it before us */
7592 g_hash_table_destroy (the_name_cache);
7593 } else {
7594 mono_atomic_store_release (&image->name_cache, the_name_cache);
7595 }
7596 mono_image_unlock (image);
7597 return;
7598 }
7599
7600 /* Temporary hash table to avoid lookups in the nspace_table */
7601 name_cache2 = g_hash_table_new (NULL, NULL);
7602
7603 for (i = 1; i <= t->rows; ++i) {
7604 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7605 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7606 /*
7607 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7608 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7609 */
7610 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7611 continue;
7612 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7613 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7614
7615 nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
7616 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7617 if (!nspace_table) {
7618 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7619 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
7620 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7621 nspace_table);
7622 }
7623 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
7624 }
7625
7626 /* Load type names from EXPORTEDTYPES table */
7627 {
7628 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7629 guint32 cols [MONO_EXP_TYPE_SIZE];
7630 int i;
7631
7632 for (i = 0; i < t->rows; ++i) {
7633 mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
7634
7635 guint32 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
7636 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_EXP_TYPE)
7637 /* Nested type */
7638 continue;
7639
7640 name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
7641 nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
7642
7643 nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
7644 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7645 if (!nspace_table) {
7646 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7647 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
7648 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7649 nspace_table);
7650 }
7651 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
7652 }
7653 }
7654
7655 g_hash_table_destroy (name_cache2);
7656
7657 mono_image_lock (image);
7658 if (image->name_cache) {
7659 /* Somebody initialized it before us */
7660 g_hash_table_destroy (the_name_cache);
7661 } else {
7662 mono_atomic_store_release (&image->name_cache, the_name_cache);
7663 }
7664 mono_image_unlock (image);
7665 }
7666
7667 /*FIXME Only dynamic assemblies should allow this operation.*/
7668 /**
7669 * mono_image_add_to_name_cache:
7670 */
7671 void
mono_image_add_to_name_cache(MonoImage * image,const char * nspace,const char * name,guint32 index)7672 mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
7673 const char *name, guint32 index)
7674 {
7675 GHashTable *nspace_table;
7676 GHashTable *name_cache;
7677 guint32 old_index;
7678
7679 mono_image_init_name_cache (image);
7680 mono_image_lock (image);
7681
7682 name_cache = image->name_cache;
7683 if (!(nspace_table = (GHashTable *)g_hash_table_lookup (name_cache, nspace))) {
7684 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7685 g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
7686 }
7687
7688 if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
7689 g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
7690
7691 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
7692
7693 mono_image_unlock (image);
7694 }
7695
7696 typedef struct {
7697 gconstpointer key;
7698 gpointer value;
7699 } FindUserData;
7700
7701 static void
find_nocase(gpointer key,gpointer value,gpointer user_data)7702 find_nocase (gpointer key, gpointer value, gpointer user_data)
7703 {
7704 char *name = (char*)key;
7705 FindUserData *data = (FindUserData*)user_data;
7706
7707 if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
7708 data->value = value;
7709 }
7710
7711 /**
7712 * mono_class_from_name_case:
7713 * \param image The MonoImage where the type is looked up in
7714 * \param name_space the type namespace
7715 * \param name the type short name.
7716 * \deprecated use the mono_class_from_name_case_checked variant instead.
7717 *
7718 * Obtains a \c MonoClass with a given namespace and a given name which
7719 * is located in the given \c MonoImage. The namespace and name
7720 * lookups are case insensitive.
7721 */
7722 MonoClass *
mono_class_from_name_case(MonoImage * image,const char * name_space,const char * name)7723 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
7724 {
7725 MonoError error;
7726 MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error);
7727 mono_error_cleanup (&error);
7728
7729 return res;
7730 }
7731
7732 /**
7733 * mono_class_from_name_case_checked:
7734 * \param image The MonoImage where the type is looked up in
7735 * \param name_space the type namespace
7736 * \param name the type short name.
7737 * \param error if
7738 *
7739 * Obtains a MonoClass with a given namespace and a given name which
7740 * is located in the given MonoImage. The namespace and name
7741 * lookups are case insensitive.
7742 *
7743 * \returns The MonoClass if the given namespace and name were found, or NULL if it
7744 * was not found. The \p error object will contain information about the problem
7745 * in that case.
7746 */
7747 MonoClass *
mono_class_from_name_case_checked(MonoImage * image,const char * name_space,const char * name,MonoError * error)7748 mono_class_from_name_case_checked (MonoImage *image, const char *name_space, const char *name, MonoError *error)
7749 {
7750 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7751 guint32 cols [MONO_TYPEDEF_SIZE];
7752 const char *n;
7753 const char *nspace;
7754 guint32 i, visib;
7755
7756 error_init (error);
7757
7758 if (image_is_dynamic (image)) {
7759 guint32 token = 0;
7760 FindUserData user_data;
7761
7762 mono_image_init_name_cache (image);
7763 mono_image_lock (image);
7764
7765 user_data.key = name_space;
7766 user_data.value = NULL;
7767 g_hash_table_foreach (image->name_cache, find_nocase, &user_data);
7768
7769 if (user_data.value) {
7770 GHashTable *nspace_table = (GHashTable*)user_data.value;
7771
7772 user_data.key = name;
7773 user_data.value = NULL;
7774
7775 g_hash_table_foreach (nspace_table, find_nocase, &user_data);
7776
7777 if (user_data.value)
7778 token = GPOINTER_TO_UINT (user_data.value);
7779 }
7780
7781 mono_image_unlock (image);
7782
7783 if (token)
7784 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | token, error);
7785 else
7786 return NULL;
7787
7788 }
7789
7790 /* add a cache if needed */
7791 for (i = 1; i <= t->rows; ++i) {
7792 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7793 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7794 /*
7795 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7796 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7797 */
7798 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7799 continue;
7800 n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7801 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7802 if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
7803 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | i, error);
7804 }
7805 return NULL;
7806 }
7807
7808 static MonoClass*
return_nested_in(MonoClass * klass,char * nested)7809 return_nested_in (MonoClass *klass, char *nested)
7810 {
7811 MonoClass *found;
7812 char *s = strchr (nested, '/');
7813 gpointer iter = NULL;
7814
7815 if (s) {
7816 *s = 0;
7817 s++;
7818 }
7819
7820 while ((found = mono_class_get_nested_types (klass, &iter))) {
7821 if (strcmp (found->name, nested) == 0) {
7822 if (s)
7823 return return_nested_in (found, s);
7824 return found;
7825 }
7826 }
7827 return NULL;
7828 }
7829
7830 static MonoClass*
search_modules(MonoImage * image,const char * name_space,const char * name,MonoError * error)7831 search_modules (MonoImage *image, const char *name_space, const char *name, MonoError *error)
7832 {
7833 MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
7834 MonoImage *file_image;
7835 MonoClass *klass;
7836 int i;
7837
7838 error_init (error);
7839
7840 /*
7841 * The EXPORTEDTYPES table only contains public types, so have to search the
7842 * modules as well.
7843 * Note: image->modules contains the contents of the MODULEREF table, while
7844 * the real module list is in the FILE table.
7845 */
7846 for (i = 0; i < file_table->rows; i++) {
7847 guint32 cols [MONO_FILE_SIZE];
7848 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
7849 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
7850 continue;
7851
7852 file_image = mono_image_load_file_for_image_checked (image, i + 1, error);
7853 if (file_image) {
7854 klass = mono_class_from_name_checked (file_image, name_space, name, error);
7855 if (klass || !is_ok (error))
7856 return klass;
7857 }
7858 }
7859
7860 return NULL;
7861 }
7862
7863 static MonoClass *
mono_class_from_name_checked_aux(MonoImage * image,const char * name_space,const char * name,GHashTable * visited_images,MonoError * error)7864 mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, MonoError *error)
7865 {
7866 GHashTable *nspace_table;
7867 MonoImage *loaded_image;
7868 guint32 token = 0;
7869 int i;
7870 MonoClass *klass;
7871 char *nested;
7872 char buf [1024];
7873
7874 error_init (error);
7875
7876 // Checking visited images avoids stack overflows when cyclic references exist.
7877 if (g_hash_table_lookup (visited_images, image))
7878 return NULL;
7879
7880 g_hash_table_insert (visited_images, image, GUINT_TO_POINTER(1));
7881
7882 if ((nested = strchr (name, '/'))) {
7883 int pos = nested - name;
7884 int len = strlen (name);
7885 if (len > 1023)
7886 return NULL;
7887 memcpy (buf, name, len + 1);
7888 buf [pos] = 0;
7889 nested = buf + pos + 1;
7890 name = buf;
7891 }
7892
7893 /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */
7894 if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
7895 gboolean res = get_class_from_name (image, name_space, name, &klass);
7896 if (res) {
7897 if (!klass) {
7898 klass = search_modules (image, name_space, name, error);
7899 if (!is_ok (error))
7900 return NULL;
7901 }
7902 if (nested)
7903 return klass ? return_nested_in (klass, nested) : NULL;
7904 else
7905 return klass;
7906 }
7907 }
7908
7909 mono_image_init_name_cache (image);
7910 mono_image_lock (image);
7911
7912 nspace_table = (GHashTable *)g_hash_table_lookup (image->name_cache, name_space);
7913
7914 if (nspace_table)
7915 token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
7916
7917 mono_image_unlock (image);
7918
7919 if (!token && image_is_dynamic (image) && image->modules) {
7920 /* Search modules as well */
7921 for (i = 0; i < image->module_count; ++i) {
7922 MonoImage *module = image->modules [i];
7923
7924 klass = mono_class_from_name_checked (module, name_space, name, error);
7925 if (klass || !is_ok (error))
7926 return klass;
7927 }
7928 }
7929
7930 if (!token) {
7931 klass = search_modules (image, name_space, name, error);
7932 if (klass || !is_ok (error))
7933 return klass;
7934 return NULL;
7935 }
7936
7937 if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
7938 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7939 guint32 cols [MONO_EXP_TYPE_SIZE];
7940 guint32 idx, impl;
7941
7942 idx = mono_metadata_token_index (token);
7943
7944 mono_metadata_decode_row (t, idx - 1, cols, MONO_EXP_TYPE_SIZE);
7945
7946 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
7947 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
7948 loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error);
7949 if (!loaded_image)
7950 return NULL;
7951 klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, error);
7952 if (nested)
7953 return klass ? return_nested_in (klass, nested) : NULL;
7954 return klass;
7955 } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
7956 guint32 assembly_idx;
7957
7958 assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
7959
7960 mono_assembly_load_reference (image, assembly_idx - 1);
7961 g_assert (image->references [assembly_idx - 1]);
7962 if (image->references [assembly_idx - 1] == (gpointer)-1)
7963 return NULL;
7964 klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, error);
7965 if (nested)
7966 return klass ? return_nested_in (klass, nested) : NULL;
7967 return klass;
7968 } else {
7969 g_assert_not_reached ();
7970 }
7971 }
7972
7973 token = MONO_TOKEN_TYPE_DEF | token;
7974
7975 klass = mono_class_get_checked (image, token, error);
7976 if (nested)
7977 return return_nested_in (klass, nested);
7978 return klass;
7979 }
7980
7981 /**
7982 * mono_class_from_name_checked:
7983 * \param image The MonoImage where the type is looked up in
7984 * \param name_space the type namespace
7985 * \param name the type short name.
7986 *
7987 * Obtains a MonoClass with a given namespace and a given name which
7988 * is located in the given MonoImage.
7989 *
7990 * Works like mono_class_from_name, but error handling is tricky. It can return NULL and have no error
7991 * set if the class was not found or it will return NULL and set the error if there was a loading error.
7992 */
7993 MonoClass *
mono_class_from_name_checked(MonoImage * image,const char * name_space,const char * name,MonoError * error)7994 mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
7995 {
7996 MonoClass *klass;
7997 GHashTable *visited_images;
7998
7999 visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
8000
8001 klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, error);
8002
8003 g_hash_table_destroy (visited_images);
8004
8005 return klass;
8006 }
8007
8008 /**
8009 * mono_class_from_name:
8010 * \param image The \c MonoImage where the type is looked up in
8011 * \param name_space the type namespace
8012 * \param name the type short name.
8013 *
8014 * Obtains a \c MonoClass with a given namespace and a given name which
8015 * is located in the given \c MonoImage.
8016 *
8017 * To reference nested classes, use the "/" character as a separator.
8018 * For example use \c "Foo/Bar" to reference the class \c Bar that is nested
8019 * inside \c Foo, like this: "class Foo { class Bar {} }".
8020 */
8021 MonoClass *
mono_class_from_name(MonoImage * image,const char * name_space,const char * name)8022 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
8023 {
8024 MonoError error;
8025 MonoClass *klass;
8026
8027 klass = mono_class_from_name_checked (image, name_space, name, &error);
8028 mono_error_cleanup (&error); /* FIXME Don't swallow the error */
8029
8030 return klass;
8031 }
8032
8033 /**
8034 * mono_class_load_from_name:
8035 * \param image The MonoImage where the type is looked up in
8036 * \param name_space the type namespace
8037 * \param name the type short name.
8038 *
8039 * This function works exactly like mono_class_from_name but it will abort if the class is not found.
8040 * This function should be used by the runtime for critical types to which there's no way to recover but crash
8041 * If they are missing. Thing of System.Object or System.String.
8042 */
8043 MonoClass *
mono_class_load_from_name(MonoImage * image,const char * name_space,const char * name)8044 mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
8045 {
8046 MonoError error;
8047 MonoClass *klass;
8048
8049 klass = mono_class_from_name_checked (image, name_space, name, &error);
8050 if (!klass)
8051 g_error ("Runtime critical type %s.%s not found", name_space, name);
8052 if (!mono_error_ok (&error))
8053 g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
8054 return klass;
8055 }
8056
8057 /**
8058 * mono_class_try_load_from_name:
8059 * \param image The MonoImage where the type is looked up in
8060 * \param name_space the type namespace
8061 * \param name the type short name.
8062 *
8063 * This function tries to load a type, returning the class was found or NULL otherwise.
8064 * This function should be used by the runtime when probing for optional types, those that could have being linked out.
8065 *
8066 * Big design consideration. This function aborts if there was an error loading the type. This prevents us from missing
8067 * a type that we would otherwise assume to be available but was not due some error.
8068 *
8069 */
8070 MonoClass*
mono_class_try_load_from_name(MonoImage * image,const char * name_space,const char * name)8071 mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name)
8072 {
8073 MonoError error;
8074 MonoClass *klass;
8075
8076 klass = mono_class_from_name_checked (image, name_space, name, &error);
8077 if (!mono_error_ok (&error))
8078 g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
8079 return klass;
8080 }
8081
8082
8083 /**
8084 * mono_class_is_subclass_of:
8085 * \param klass class to probe if it is a subclass of another one
8086 * \param klassc the class we suspect is the base class
8087 * \param check_interfaces whether we should perform interface checks
8088 *
8089 * This method determines whether \p klass is a subclass of \p klassc.
8090 *
8091 * If the \p check_interfaces flag is set, then if \p klassc is an interface
8092 * this method return TRUE if the \p klass implements the interface or
8093 * if \p klass is an interface, if one of its base classes is \p klass.
8094 *
8095 * If \p check_interfaces is false, then if \p klass is not an interface,
8096 * it returns TRUE if the \p klass is a subclass of \p klassc.
8097 *
8098 * if \p klass is an interface and \p klassc is \c System.Object, then this function
8099 * returns TRUE.
8100 *
8101 */
8102 gboolean
mono_class_is_subclass_of(MonoClass * klass,MonoClass * klassc,gboolean check_interfaces)8103 mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
8104 gboolean check_interfaces)
8105 {
8106 /* FIXME test for interfaces with variant generic arguments */
8107 mono_class_init (klass);
8108 mono_class_init (klassc);
8109
8110 if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
8111 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
8112 return TRUE;
8113 } else if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && MONO_CLASS_IS_INTERFACE (klass)) {
8114 int i;
8115
8116 for (i = 0; i < klass->interface_count; i ++) {
8117 MonoClass *ic = klass->interfaces [i];
8118 if (ic == klassc)
8119 return TRUE;
8120 }
8121 } else {
8122 if (!MONO_CLASS_IS_INTERFACE (klass) && mono_class_has_parent (klass, klassc))
8123 return TRUE;
8124 }
8125
8126 /*
8127 * MS.NET thinks interfaces are a subclass of Object, so we think it as
8128 * well.
8129 */
8130 if (klassc == mono_defaults.object_class)
8131 return TRUE;
8132
8133 return FALSE;
8134 }
8135
8136 static gboolean
mono_type_is_generic_argument(MonoType * type)8137 mono_type_is_generic_argument (MonoType *type)
8138 {
8139 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
8140 }
8141
8142 gboolean
mono_class_has_variant_generic_params(MonoClass * klass)8143 mono_class_has_variant_generic_params (MonoClass *klass)
8144 {
8145 int i;
8146 MonoGenericContainer *container;
8147
8148 if (!mono_class_is_ginst (klass))
8149 return FALSE;
8150
8151 container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
8152
8153 for (i = 0; i < container->type_argc; ++i)
8154 if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
8155 return TRUE;
8156
8157 return FALSE;
8158 }
8159
8160 static gboolean
mono_gparam_is_reference_conversible(MonoClass * target,MonoClass * candidate,gboolean check_for_reference_conv)8161 mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
8162 {
8163 if (target == candidate)
8164 return TRUE;
8165
8166 if (check_for_reference_conv &&
8167 mono_type_is_generic_argument (&target->byval_arg) &&
8168 mono_type_is_generic_argument (&candidate->byval_arg)) {
8169 MonoGenericParam *gparam = candidate->byval_arg.data.generic_param;
8170 MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
8171
8172 if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
8173 return FALSE;
8174 }
8175 if (!mono_class_is_assignable_from (target, candidate))
8176 return FALSE;
8177 return TRUE;
8178 }
8179
8180 /**
8181 * @container the generic container from the GTD
8182 * @klass: the class to be assigned to
8183 * @oklass: the source class
8184 *
8185 * Both @klass and @oklass must be instances of the same generic interface.
8186 *
8187 * Returns: TRUE if @klass can be assigned to a @klass variable
8188 */
8189 gboolean
mono_class_is_variant_compatible(MonoClass * klass,MonoClass * oklass,gboolean check_for_reference_conv)8190 mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
8191 {
8192 int j;
8193 MonoType **klass_argv, **oklass_argv;
8194 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
8195 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
8196
8197 if (klass == oklass)
8198 return TRUE;
8199
8200 /*Viable candidates are instances of the same generic interface*/
8201 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
8202 return FALSE;
8203
8204 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
8205 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
8206
8207 for (j = 0; j < container->type_argc; ++j) {
8208 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
8209 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
8210
8211 if (param1_class->valuetype != param2_class->valuetype || (param1_class->valuetype && param1_class != param2_class))
8212 return FALSE;
8213
8214 /*
8215 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
8216 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
8217 */
8218 if (param1_class != param2_class) {
8219 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
8220 if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
8221 return FALSE;
8222 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
8223 if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
8224 return FALSE;
8225 } else
8226 return FALSE;
8227 }
8228 }
8229 return TRUE;
8230 }
8231
8232 static gboolean
mono_gparam_is_assignable_from(MonoClass * target,MonoClass * candidate)8233 mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
8234 {
8235 MonoGenericParam *gparam, *ogparam;
8236 MonoGenericParamInfo *tinfo, *cinfo;
8237 MonoClass **candidate_class;
8238 gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
8239 int tmask, cmask;
8240
8241 if (target == candidate)
8242 return TRUE;
8243 if (target->byval_arg.type != candidate->byval_arg.type)
8244 return FALSE;
8245
8246 gparam = target->byval_arg.data.generic_param;
8247 ogparam = candidate->byval_arg.data.generic_param;
8248 tinfo = mono_generic_param_info (gparam);
8249 cinfo = mono_generic_param_info (ogparam);
8250
8251 class_constraint_satisfied = FALSE;
8252 valuetype_constraint_satisfied = FALSE;
8253
8254 /*candidate must have a super set of target's special constraints*/
8255 tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
8256 cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
8257
8258 if (cinfo->constraints) {
8259 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8260 MonoClass *cc = *candidate_class;
8261
8262 if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
8263 class_constraint_satisfied = TRUE;
8264 else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
8265 valuetype_constraint_satisfied = TRUE;
8266 }
8267 }
8268 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
8269 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
8270
8271 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
8272 return FALSE;
8273 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
8274 return FALSE;
8275 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
8276 valuetype_constraint_satisfied)) {
8277 return FALSE;
8278 }
8279
8280
8281 /*candidate type constraints must be a superset of target's*/
8282 if (tinfo->constraints) {
8283 MonoClass **target_class;
8284 for (target_class = tinfo->constraints; *target_class; ++target_class) {
8285 MonoClass *tc = *target_class;
8286
8287 /*
8288 * A constraint from @target might inflate into @candidate itself and in that case we don't need
8289 * check it's constraints since it satisfy the constraint by itself.
8290 */
8291 if (mono_metadata_type_equal (&tc->byval_arg, &candidate->byval_arg))
8292 continue;
8293
8294 if (!cinfo->constraints)
8295 return FALSE;
8296
8297 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8298 MonoClass *cc = *candidate_class;
8299
8300 if (mono_class_is_assignable_from (tc, cc))
8301 break;
8302
8303 /*
8304 * This happens when we have the following:
8305 *
8306 * Bar<K> where K : IFace
8307 * Foo<T, U> where T : U where U : IFace
8308 * ...
8309 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
8310 *
8311 */
8312 if (mono_type_is_generic_argument (&cc->byval_arg)) {
8313 if (mono_gparam_is_assignable_from (target, cc))
8314 break;
8315 }
8316 }
8317 if (!*candidate_class)
8318 return FALSE;
8319 }
8320 }
8321
8322 /*candidate itself must have a constraint that satisfy target*/
8323 if (cinfo->constraints) {
8324 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8325 MonoClass *cc = *candidate_class;
8326 if (mono_class_is_assignable_from (target, cc))
8327 return TRUE;
8328 }
8329 }
8330 return FALSE;
8331 }
8332
8333 /**
8334 * mono_class_is_assignable_from:
8335 * \param klass the class to be assigned to
8336 * \param oklass the source class
8337 *
8338 * \returns TRUE if an instance of class \p oklass can be assigned to an
8339 * instance of class \p klass
8340 */
8341 gboolean
mono_class_is_assignable_from(MonoClass * klass,MonoClass * oklass)8342 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
8343 {
8344 MonoError error;
8345 /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
8346 if (!klass->inited)
8347 mono_class_init (klass);
8348
8349 if (!oklass->inited)
8350 mono_class_init (oklass);
8351
8352 if (mono_class_has_failure (klass) || mono_class_has_failure (oklass))
8353 return FALSE;
8354
8355 if (mono_type_is_generic_argument (&klass->byval_arg)) {
8356 if (!mono_type_is_generic_argument (&oklass->byval_arg))
8357 return FALSE;
8358 return mono_gparam_is_assignable_from (klass, oklass);
8359 }
8360
8361 /* This can happen if oklass is a tyvar that has a constraint which is another tyvar which in turn
8362 * has a constraint which is a class type:
8363 *
8364 * class Foo { }
8365 * class G<T1, T2> where T1 : T2 where T2 : Foo { }
8366 *
8367 * In this case, Foo is assignable from T1.
8368 */
8369 if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
8370 MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
8371 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
8372 int i;
8373
8374 if (constraints) {
8375 for (i = 0; constraints [i]; ++i) {
8376 if (mono_class_is_assignable_from (klass, constraints [i]))
8377 return TRUE;
8378 }
8379 }
8380
8381 return mono_class_has_parent (oklass, klass);
8382 }
8383
8384 if (MONO_CLASS_IS_INTERFACE (klass)) {
8385
8386 /* interface_offsets might not be set for dynamic classes */
8387 if (mono_class_get_ref_info_handle (oklass) && !oklass->interface_bitmap) {
8388 /*
8389 * oklass might be a generic type parameter but they have
8390 * interface_offsets set.
8391 */
8392 gboolean result = mono_reflection_call_is_assignable_to (oklass, klass, &error);
8393 if (!is_ok (&error)) {
8394 mono_error_cleanup (&error);
8395 return FALSE;
8396 }
8397 return result;
8398 }
8399 if (!oklass->interface_bitmap)
8400 /* Happens with generic instances of not-yet created dynamic types */
8401 return FALSE;
8402 if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
8403 return TRUE;
8404
8405 if (klass->is_array_special_interface && oklass->rank == 1) {
8406 if (mono_class_is_gtd (klass)) {
8407 /* klass is an array special gtd like
8408 * IList`1<>, and oklass is X[] for some X.
8409 * Moreover we know that X isn't !0 (the gparam
8410 * of IList`1) because in that case we would
8411 * have returned TRUE for
8412 * MONO_CLASS_IMPLEMENTS_INTERFACE, above.
8413 */
8414 return FALSE;
8415 }
8416 // FIXME: IEnumerator`1 should not be an array special interface.
8417 // The correct fix is to make
8418 // ((IEnumerable<U>) (new T[] {...})).GetEnumerator()
8419 // return an IEnumerator<U> (like .NET does) instead of IEnumerator<T>
8420 // and to stop marking IEnumerable`1 as an array_special_interface.
8421 if (mono_class_get_generic_type_definition (klass) == mono_defaults.generic_ienumerator_class)
8422 return FALSE;
8423
8424 //XXX we could offset this by having the cast target computed at JIT time
8425 //XXX we could go even further and emit a wrapper that would do the extra type check
8426 MonoClass *iface_klass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
8427 MonoClass *obj_klass = oklass->cast_class; //This gets us the cast class of element type of the array
8428
8429 // If the target we're trying to cast to is a valuetype, we must account of weird valuetype equivalences such as IntEnum <> int or uint <> int
8430 // We can't apply it for ref types as this would go wrong with arrays - IList<byte[]> would have byte tested
8431 if (!mono_class_is_nullable (iface_klass)) {
8432 if (iface_klass->valuetype)
8433 iface_klass = iface_klass->cast_class;
8434
8435 //array covariant casts only operates on scalar to scalar
8436 //This is so int[] can't be casted to IComparable<int>[]
8437 if (!(obj_klass->valuetype && !iface_klass->valuetype) && mono_class_is_assignable_from (iface_klass, obj_klass))
8438 return TRUE;
8439 }
8440 }
8441
8442 if (mono_class_has_variant_generic_params (klass)) {
8443 int i;
8444 mono_class_setup_interfaces (oklass, &error);
8445 if (!mono_error_ok (&error)) {
8446 mono_error_cleanup (&error);
8447 return FALSE;
8448 }
8449
8450 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
8451 for (i = 0; i < oklass->interface_offsets_count; ++i) {
8452 MonoClass *iface = oklass->interfaces_packed [i];
8453
8454 if (mono_class_is_variant_compatible (klass, iface, FALSE))
8455 return TRUE;
8456 }
8457 }
8458 return FALSE;
8459 } else if (klass->delegate) {
8460 if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE))
8461 return TRUE;
8462 }else if (klass->rank) {
8463 MonoClass *eclass, *eoclass;
8464
8465 if (oklass->rank != klass->rank)
8466 return FALSE;
8467
8468 /* vectors vs. one dimensional arrays */
8469 if (oklass->byval_arg.type != klass->byval_arg.type)
8470 return FALSE;
8471
8472 eclass = klass->cast_class;
8473 eoclass = oklass->cast_class;
8474
8475 /*
8476 * a is b does not imply a[] is b[] when a is a valuetype, and
8477 * b is a reference type.
8478 */
8479
8480 if (eoclass->valuetype) {
8481 if ((eclass == mono_defaults.enum_class) ||
8482 (eclass == mono_defaults.enum_class->parent) ||
8483 (eclass == mono_defaults.object_class))
8484 return FALSE;
8485 }
8486
8487 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
8488 } else if (mono_class_is_nullable (klass)) {
8489 if (mono_class_is_nullable (oklass))
8490 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
8491 else
8492 return mono_class_is_assignable_from (klass->cast_class, oklass);
8493 } else if (klass == mono_defaults.object_class)
8494 return TRUE;
8495
8496 return mono_class_has_parent (oklass, klass);
8497 }
8498
8499 /*Check if @oklass is variant compatible with @klass.*/
8500 static gboolean
mono_class_is_variant_compatible_slow(MonoClass * klass,MonoClass * oklass)8501 mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
8502 {
8503 int j;
8504 MonoType **klass_argv, **oklass_argv;
8505 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
8506 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
8507
8508 /*Viable candidates are instances of the same generic interface*/
8509 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
8510 return FALSE;
8511
8512 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
8513 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
8514
8515 for (j = 0; j < container->type_argc; ++j) {
8516 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
8517 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
8518
8519 if (param1_class->valuetype != param2_class->valuetype)
8520 return FALSE;
8521
8522 /*
8523 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
8524 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
8525 */
8526 if (param1_class != param2_class) {
8527 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
8528 if (!mono_class_is_assignable_from_slow (param1_class, param2_class))
8529 return FALSE;
8530 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
8531 if (!mono_class_is_assignable_from_slow (param2_class, param1_class))
8532 return FALSE;
8533 } else
8534 return FALSE;
8535 }
8536 }
8537 return TRUE;
8538 }
8539 /*Check if @candidate implements the interface @target*/
8540 static gboolean
mono_class_implement_interface_slow(MonoClass * target,MonoClass * candidate)8541 mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
8542 {
8543 MonoError error;
8544 int i;
8545 gboolean is_variant = mono_class_has_variant_generic_params (target);
8546
8547 if (is_variant && MONO_CLASS_IS_INTERFACE (candidate)) {
8548 if (mono_class_is_variant_compatible_slow (target, candidate))
8549 return TRUE;
8550 }
8551
8552 do {
8553 if (candidate == target)
8554 return TRUE;
8555
8556 /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
8557 if (image_is_dynamic (candidate->image) && !candidate->wastypebuilder) {
8558 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info_raw (candidate); /* FIXME use handles */
8559 int j;
8560 if (tb && tb->interfaces) {
8561 for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
8562 MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
8563 MonoClass *iface_class;
8564
8565 /* we can't realize the type here since it can do pretty much anything. */
8566 if (!iface->type)
8567 continue;
8568 iface_class = mono_class_from_mono_type (iface->type);
8569 if (iface_class == target)
8570 return TRUE;
8571 if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class))
8572 return TRUE;
8573 if (mono_class_implement_interface_slow (target, iface_class))
8574 return TRUE;
8575 }
8576 }
8577 } else {
8578 /*setup_interfaces don't mono_class_init anything*/
8579 /*FIXME this doesn't handle primitive type arrays.
8580 ICollection<sbyte> x byte [] won't work because candidate->interfaces, for byte[], won't have IList<sbyte>.
8581 A possible way to fix this would be to move that to setup_interfaces from setup_interface_offsets.
8582 */
8583 mono_class_setup_interfaces (candidate, &error);
8584 if (!mono_error_ok (&error)) {
8585 mono_error_cleanup (&error);
8586 return FALSE;
8587 }
8588
8589 for (i = 0; i < candidate->interface_count; ++i) {
8590 if (candidate->interfaces [i] == target)
8591 return TRUE;
8592
8593 if (is_variant && mono_class_is_variant_compatible_slow (target, candidate->interfaces [i]))
8594 return TRUE;
8595
8596 if (mono_class_implement_interface_slow (target, candidate->interfaces [i]))
8597 return TRUE;
8598 }
8599 }
8600 candidate = candidate->parent;
8601 } while (candidate);
8602
8603 return FALSE;
8604 }
8605
8606 /*
8607 * Check if @oklass can be assigned to @klass.
8608 * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context.
8609 */
8610 gboolean
mono_class_is_assignable_from_slow(MonoClass * target,MonoClass * candidate)8611 mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
8612 {
8613 if (candidate == target)
8614 return TRUE;
8615 if (target == mono_defaults.object_class)
8616 return TRUE;
8617
8618 if (mono_class_has_parent (candidate, target))
8619 return TRUE;
8620
8621 /*If target is not an interface there is no need to check them.*/
8622 if (MONO_CLASS_IS_INTERFACE (target))
8623 return mono_class_implement_interface_slow (target, candidate);
8624
8625 if (target->delegate && mono_class_has_variant_generic_params (target))
8626 return mono_class_is_variant_compatible (target, candidate, FALSE);
8627
8628 if (target->rank) {
8629 MonoClass *eclass, *eoclass;
8630
8631 if (target->rank != candidate->rank)
8632 return FALSE;
8633
8634 /* vectors vs. one dimensional arrays */
8635 if (target->byval_arg.type != candidate->byval_arg.type)
8636 return FALSE;
8637
8638 eclass = target->cast_class;
8639 eoclass = candidate->cast_class;
8640
8641 /*
8642 * a is b does not imply a[] is b[] when a is a valuetype, and
8643 * b is a reference type.
8644 */
8645
8646 if (eoclass->valuetype) {
8647 if ((eclass == mono_defaults.enum_class) ||
8648 (eclass == mono_defaults.enum_class->parent) ||
8649 (eclass == mono_defaults.object_class))
8650 return FALSE;
8651 }
8652
8653 return mono_class_is_assignable_from_slow (target->cast_class, candidate->cast_class);
8654 }
8655 /*FIXME properly handle nullables */
8656 /*FIXME properly handle (M)VAR */
8657 return FALSE;
8658 }
8659
8660 /**
8661 * mono_class_get_cctor:
8662 * \param klass A MonoClass pointer
8663 *
8664 * \returns The static constructor of \p klass if it exists, NULL otherwise.
8665 */
8666 MonoMethod*
mono_class_get_cctor(MonoClass * klass)8667 mono_class_get_cctor (MonoClass *klass)
8668 {
8669 MonoCachedClassInfo cached_info;
8670
8671 if (image_is_dynamic (klass->image)) {
8672 /*
8673 * has_cctor is not set for these classes because mono_class_init () is
8674 * not run for them.
8675 */
8676 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8677 }
8678
8679 mono_class_init (klass);
8680
8681 if (!klass->has_cctor)
8682 return NULL;
8683
8684 if (mono_class_is_ginst (klass) && !klass->methods)
8685 return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class));
8686
8687 if (mono_class_get_cached_class_info (klass, &cached_info)) {
8688 MonoError error;
8689 MonoMethod *result = mono_get_method_checked (klass->image, cached_info.cctor_token, klass, NULL, &error);
8690 if (!mono_error_ok (&error))
8691 g_error ("Could not lookup class cctor from cached metadata due to %s", mono_error_get_message (&error));
8692 return result;
8693 }
8694
8695 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8696 }
8697
8698 /**
8699 * mono_class_get_finalizer:
8700 * \param klass: The MonoClass pointer
8701 *
8702 * \returns The finalizer method of \p klass if it exists, NULL otherwise.
8703 */
8704 MonoMethod*
mono_class_get_finalizer(MonoClass * klass)8705 mono_class_get_finalizer (MonoClass *klass)
8706 {
8707 MonoCachedClassInfo cached_info;
8708
8709 if (!klass->inited)
8710 mono_class_init (klass);
8711 if (!mono_class_has_finalizer (klass))
8712 return NULL;
8713
8714 if (mono_class_get_cached_class_info (klass, &cached_info)) {
8715 MonoError error;
8716 MonoMethod *result = mono_get_method_checked (cached_info.finalize_image, cached_info.finalize_token, NULL, NULL, &error);
8717 if (!mono_error_ok (&error))
8718 g_error ("Could not lookup finalizer from cached metadata due to %s", mono_error_get_message (&error));
8719 return result;
8720 }else {
8721 mono_class_setup_vtable (klass);
8722 return klass->vtable [finalize_slot];
8723 }
8724 }
8725
8726 /**
8727 * mono_class_needs_cctor_run:
8728 * \param klass the MonoClass pointer
8729 * \param caller a MonoMethod describing the caller
8730 *
8731 * Determines whenever the class has a static constructor and whenever it
8732 * needs to be called when executing CALLER.
8733 */
8734 gboolean
mono_class_needs_cctor_run(MonoClass * klass,MonoMethod * caller)8735 mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
8736 {
8737 MonoMethod *method;
8738
8739 method = mono_class_get_cctor (klass);
8740 if (method)
8741 return (method == caller) ? FALSE : TRUE;
8742 else
8743 return FALSE;
8744 }
8745
8746 /**
8747 * mono_class_array_element_size:
8748 * \param klass
8749 *
8750 * \returns The number of bytes an element of type \p klass uses when stored into an array.
8751 */
8752 gint32
mono_class_array_element_size(MonoClass * klass)8753 mono_class_array_element_size (MonoClass *klass)
8754 {
8755 MonoType *type = &klass->byval_arg;
8756
8757 handle_enum:
8758 switch (type->type) {
8759 case MONO_TYPE_I1:
8760 case MONO_TYPE_U1:
8761 case MONO_TYPE_BOOLEAN:
8762 return 1;
8763 case MONO_TYPE_I2:
8764 case MONO_TYPE_U2:
8765 case MONO_TYPE_CHAR:
8766 return 2;
8767 case MONO_TYPE_I4:
8768 case MONO_TYPE_U4:
8769 case MONO_TYPE_R4:
8770 return 4;
8771 case MONO_TYPE_I:
8772 case MONO_TYPE_U:
8773 case MONO_TYPE_PTR:
8774 case MONO_TYPE_CLASS:
8775 case MONO_TYPE_STRING:
8776 case MONO_TYPE_OBJECT:
8777 case MONO_TYPE_SZARRAY:
8778 case MONO_TYPE_ARRAY:
8779 return sizeof (gpointer);
8780 case MONO_TYPE_I8:
8781 case MONO_TYPE_U8:
8782 case MONO_TYPE_R8:
8783 return 8;
8784 case MONO_TYPE_VALUETYPE:
8785 if (type->data.klass->enumtype) {
8786 type = mono_class_enum_basetype (type->data.klass);
8787 klass = klass->element_class;
8788 goto handle_enum;
8789 }
8790 return mono_class_instance_size (klass) - sizeof (MonoObject);
8791 case MONO_TYPE_GENERICINST:
8792 type = &type->data.generic_class->container_class->byval_arg;
8793 goto handle_enum;
8794 case MONO_TYPE_VAR:
8795 case MONO_TYPE_MVAR: {
8796 int align;
8797
8798 return mono_type_size (type, &align);
8799 }
8800 case MONO_TYPE_VOID:
8801 return 0;
8802
8803 default:
8804 g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
8805 }
8806 return -1;
8807 }
8808
8809 /**
8810 * mono_array_element_size:
8811 * \param ac pointer to a \c MonoArrayClass
8812 *
8813 * \returns The size of single array element.
8814 *
8815 * LOCKING: Acquires the loader lock.
8816 */
8817 gint32
mono_array_element_size(MonoClass * ac)8818 mono_array_element_size (MonoClass *ac)
8819 {
8820 g_assert (ac->rank);
8821 if (G_UNLIKELY (!ac->size_inited)) {
8822 mono_class_setup_fields (ac);
8823 }
8824 return ac->sizes.element_size;
8825 }
8826
8827 /**
8828 * mono_ldtoken:
8829 */
8830 gpointer
mono_ldtoken(MonoImage * image,guint32 token,MonoClass ** handle_class,MonoGenericContext * context)8831 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
8832 MonoGenericContext *context)
8833 {
8834 MonoError error;
8835 gpointer res = mono_ldtoken_checked (image, token, handle_class, context, &error);
8836 g_assert (mono_error_ok (&error));
8837 return res;
8838 }
8839
8840 gpointer
mono_ldtoken_checked(MonoImage * image,guint32 token,MonoClass ** handle_class,MonoGenericContext * context,MonoError * error)8841 mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
8842 MonoGenericContext *context, MonoError *error)
8843 {
8844 error_init (error);
8845
8846 if (image_is_dynamic (image)) {
8847 MonoClass *tmp_handle_class;
8848 gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
8849
8850 mono_error_assert_ok (error);
8851 g_assert (tmp_handle_class);
8852 if (handle_class)
8853 *handle_class = tmp_handle_class;
8854
8855 if (tmp_handle_class == mono_defaults.typehandle_class)
8856 return &((MonoClass*)obj)->byval_arg;
8857 else
8858 return obj;
8859 }
8860
8861 switch (token & 0xff000000) {
8862 case MONO_TOKEN_TYPE_DEF:
8863 case MONO_TOKEN_TYPE_REF:
8864 case MONO_TOKEN_TYPE_SPEC: {
8865 MonoType *type;
8866 if (handle_class)
8867 *handle_class = mono_defaults.typehandle_class;
8868 type = mono_type_get_checked (image, token, context, error);
8869 if (!type)
8870 return NULL;
8871
8872 mono_class_init (mono_class_from_mono_type (type));
8873 /* We return a MonoType* as handle */
8874 return type;
8875 }
8876 case MONO_TOKEN_FIELD_DEF: {
8877 MonoClass *klass;
8878 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
8879 if (!type) {
8880 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
8881 return NULL;
8882 }
8883 if (handle_class)
8884 *handle_class = mono_defaults.fieldhandle_class;
8885 klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_DEF | type, context, error);
8886 if (!klass)
8887 return NULL;
8888
8889 mono_class_init (klass);
8890 return mono_class_get_field (klass, token);
8891 }
8892 case MONO_TOKEN_METHOD_DEF:
8893 case MONO_TOKEN_METHOD_SPEC: {
8894 MonoMethod *meth;
8895 meth = mono_get_method_checked (image, token, NULL, context, error);
8896 if (handle_class)
8897 *handle_class = mono_defaults.methodhandle_class;
8898 if (!meth)
8899 return NULL;
8900
8901 return meth;
8902 }
8903 case MONO_TOKEN_MEMBER_REF: {
8904 guint32 cols [MONO_MEMBERREF_SIZE];
8905 const char *sig;
8906 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE);
8907 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
8908 mono_metadata_decode_blob_size (sig, &sig);
8909 if (*sig == 0x6) { /* it's a field */
8910 MonoClass *klass;
8911 MonoClassField *field;
8912 field = mono_field_from_token_checked (image, token, &klass, context, error);
8913 if (handle_class)
8914 *handle_class = mono_defaults.fieldhandle_class;
8915 return field;
8916 } else {
8917 MonoMethod *meth;
8918 meth = mono_get_method_checked (image, token, NULL, context, error);
8919 if (handle_class)
8920 *handle_class = mono_defaults.methodhandle_class;
8921 return meth;
8922 }
8923 }
8924 default:
8925 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
8926 }
8927 return NULL;
8928 }
8929
8930 gpointer
mono_lookup_dynamic_token(MonoImage * image,guint32 token,MonoGenericContext * context,MonoError * error)8931 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
8932 {
8933 MonoClass *handle_class;
8934 error_init (error);
8935 return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
8936 }
8937
8938 gpointer
mono_lookup_dynamic_token_class(MonoImage * image,guint32 token,gboolean valid_token,MonoClass ** handle_class,MonoGenericContext * context,MonoError * error)8939 mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
8940 {
8941 return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
8942 }
8943
8944 static MonoGetCachedClassInfo get_cached_class_info = NULL;
8945
8946 void
mono_install_get_cached_class_info(MonoGetCachedClassInfo func)8947 mono_install_get_cached_class_info (MonoGetCachedClassInfo func)
8948 {
8949 get_cached_class_info = func;
8950 }
8951
8952 static gboolean
mono_class_get_cached_class_info(MonoClass * klass,MonoCachedClassInfo * res)8953 mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
8954 {
8955 if (!get_cached_class_info)
8956 return FALSE;
8957 else
8958 return get_cached_class_info (klass, res);
8959 }
8960
8961 void
mono_install_get_class_from_name(MonoGetClassFromName func)8962 mono_install_get_class_from_name (MonoGetClassFromName func)
8963 {
8964 get_class_from_name = func;
8965 }
8966
8967 /**
8968 * mono_class_get_image:
8969 *
8970 * Use this method to get the \c MonoImage* where this class came from.
8971 *
8972 * \returns The image where this class is defined.
8973 */
8974 MonoImage*
mono_class_get_image(MonoClass * klass)8975 mono_class_get_image (MonoClass *klass)
8976 {
8977 return klass->image;
8978 }
8979
8980 /**
8981 * mono_class_get_element_class:
8982 * \param klass the \c MonoClass to act on
8983 *
8984 * Use this function to get the element class of an array.
8985 *
8986 * \returns The element class of an array.
8987 */
8988 MonoClass*
mono_class_get_element_class(MonoClass * klass)8989 mono_class_get_element_class (MonoClass *klass)
8990 {
8991 return klass->element_class;
8992 }
8993
8994 /**
8995 * mono_class_is_valuetype:
8996 * \param klass the \c MonoClass to act on
8997 *
8998 * Use this method to determine if the provided \c MonoClass* represents a value type,
8999 * or a reference type.
9000 *
9001 * \returns TRUE if the \c MonoClass represents a \c ValueType, FALSE if it represents a reference type.
9002 */
9003 gboolean
mono_class_is_valuetype(MonoClass * klass)9004 mono_class_is_valuetype (MonoClass *klass)
9005 {
9006 return klass->valuetype;
9007 }
9008
9009 /**
9010 * mono_class_is_enum:
9011 * \param klass the \c MonoClass to act on
9012 *
9013 * Use this function to determine if the provided \c MonoClass* represents an enumeration.
9014 *
9015 * \returns TRUE if the \c MonoClass represents an enumeration.
9016 */
9017 gboolean
mono_class_is_enum(MonoClass * klass)9018 mono_class_is_enum (MonoClass *klass)
9019 {
9020 return klass->enumtype;
9021 }
9022
9023 /**
9024 * mono_class_enum_basetype:
9025 * \param klass the \c MonoClass to act on
9026 *
9027 * Use this function to get the underlying type for an enumeration value.
9028 *
9029 * \returns The underlying type representation for an enumeration.
9030 */
9031 MonoType*
mono_class_enum_basetype(MonoClass * klass)9032 mono_class_enum_basetype (MonoClass *klass)
9033 {
9034 if (klass->element_class == klass)
9035 /* SRE or broken types */
9036 return NULL;
9037 else
9038 return &klass->element_class->byval_arg;
9039 }
9040
9041 /**
9042 * mono_class_get_parent
9043 * \param klass the \c MonoClass to act on
9044 *
9045 * \returns The parent class for this class.
9046 */
9047 MonoClass*
mono_class_get_parent(MonoClass * klass)9048 mono_class_get_parent (MonoClass *klass)
9049 {
9050 return klass->parent;
9051 }
9052
9053 /**
9054 * mono_class_get_nesting_type:
9055 * \param klass the \c MonoClass to act on
9056 *
9057 * Use this function to obtain the class that the provided \c MonoClass* is nested on.
9058 *
9059 * If the return is NULL, this indicates that this class is not nested.
9060 *
9061 * \returns The container type where this type is nested or NULL if this type is not a nested type.
9062 */
9063 MonoClass*
mono_class_get_nesting_type(MonoClass * klass)9064 mono_class_get_nesting_type (MonoClass *klass)
9065 {
9066 return klass->nested_in;
9067 }
9068
9069 /**
9070 * mono_class_get_rank:
9071 * \param klass the MonoClass to act on
9072 *
9073 * \returns The rank for the array (the number of dimensions).
9074 */
9075 int
mono_class_get_rank(MonoClass * klass)9076 mono_class_get_rank (MonoClass *klass)
9077 {
9078 return klass->rank;
9079 }
9080
9081 /**
9082 * mono_class_get_name
9083 * \param klass the \c MonoClass to act on
9084 *
9085 * \returns The name of the class.
9086 */
9087 const char*
mono_class_get_name(MonoClass * klass)9088 mono_class_get_name (MonoClass *klass)
9089 {
9090 return klass->name;
9091 }
9092
9093 /**
9094 * mono_class_get_namespace:
9095 * \param klass the \c MonoClass to act on
9096 *
9097 * \returns The namespace of the class.
9098 */
9099 const char*
mono_class_get_namespace(MonoClass * klass)9100 mono_class_get_namespace (MonoClass *klass)
9101 {
9102 return klass->name_space;
9103 }
9104
9105 /**
9106 * mono_class_get_type:
9107 * \param klass the \c MonoClass to act on
9108 *
9109 * This method returns the internal \c MonoType representation for the class.
9110 *
9111 * \returns The \c MonoType from the class.
9112 */
9113 MonoType*
mono_class_get_type(MonoClass * klass)9114 mono_class_get_type (MonoClass *klass)
9115 {
9116 return &klass->byval_arg;
9117 }
9118
9119 /**
9120 * mono_class_get_type_token:
9121 * \param klass the \c MonoClass to act on
9122 *
9123 * This method returns type token for the class.
9124 *
9125 * \returns The type token for the class.
9126 */
9127 guint32
mono_class_get_type_token(MonoClass * klass)9128 mono_class_get_type_token (MonoClass *klass)
9129 {
9130 return klass->type_token;
9131 }
9132
9133 /**
9134 * mono_class_get_byref_type:
9135 * \param klass the \c MonoClass to act on
9136 *
9137 *
9138 */
9139 MonoType*
mono_class_get_byref_type(MonoClass * klass)9140 mono_class_get_byref_type (MonoClass *klass)
9141 {
9142 return &klass->this_arg;
9143 }
9144
9145 /**
9146 * mono_class_num_fields:
9147 * \param klass the \c MonoClass to act on
9148 *
9149 * \returns The number of static and instance fields in the class.
9150 */
9151 int
mono_class_num_fields(MonoClass * klass)9152 mono_class_num_fields (MonoClass *klass)
9153 {
9154 return mono_class_get_field_count (klass);
9155 }
9156
9157 /**
9158 * mono_class_num_methods:
9159 * \param klass the \c MonoClass to act on
9160 *
9161 * \returns The number of methods in the class.
9162 */
9163 int
mono_class_num_methods(MonoClass * klass)9164 mono_class_num_methods (MonoClass *klass)
9165 {
9166 return mono_class_get_method_count (klass);
9167 }
9168
9169 /**
9170 * mono_class_num_properties
9171 * \param klass the \c MonoClass to act on
9172 *
9173 * \returns The number of properties in the class.
9174 */
9175 int
mono_class_num_properties(MonoClass * klass)9176 mono_class_num_properties (MonoClass *klass)
9177 {
9178 mono_class_setup_properties (klass);
9179
9180 return mono_class_get_property_info (klass)->count;
9181 }
9182
9183 /**
9184 * mono_class_num_events:
9185 * \param klass the \c MonoClass to act on
9186 *
9187 * \returns The number of events in the class.
9188 */
9189 int
mono_class_num_events(MonoClass * klass)9190 mono_class_num_events (MonoClass *klass)
9191 {
9192 mono_class_setup_events (klass);
9193
9194 return mono_class_get_event_info (klass)->count;
9195 }
9196
9197 /**
9198 * mono_class_get_fields:
9199 * \param klass the \c MonoClass to act on
9200 *
9201 * This routine is an iterator routine for retrieving the fields in a class.
9202 *
9203 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
9204 * iterate over all of the elements. When no more values are
9205 * available, the return value is NULL.
9206 *
9207 * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
9208 */
9209 MonoClassField*
mono_class_get_fields(MonoClass * klass,gpointer * iter)9210 mono_class_get_fields (MonoClass* klass, gpointer *iter)
9211 {
9212 MonoClassField* field;
9213 if (!iter)
9214 return NULL;
9215 if (!*iter) {
9216 mono_class_setup_fields (klass);
9217 if (mono_class_has_failure (klass))
9218 return NULL;
9219 /* start from the first */
9220 if (mono_class_get_field_count (klass)) {
9221 *iter = &klass->fields [0];
9222 return &klass->fields [0];
9223 } else {
9224 /* no fields */
9225 return NULL;
9226 }
9227 }
9228 field = (MonoClassField *)*iter;
9229 field++;
9230 if (field < &klass->fields [mono_class_get_field_count (klass)]) {
9231 *iter = field;
9232 return field;
9233 }
9234 return NULL;
9235 }
9236
9237 /**
9238 * mono_class_get_methods:
9239 * \param klass the \c MonoClass to act on
9240 *
9241 * This routine is an iterator routine for retrieving the fields in a class.
9242 *
9243 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
9244 * iterate over all of the elements. When no more values are
9245 * available, the return value is NULL.
9246 *
9247 * \returns a \c MonoMethod on each iteration or NULL when no more methods are available.
9248 */
9249 MonoMethod*
mono_class_get_methods(MonoClass * klass,gpointer * iter)9250 mono_class_get_methods (MonoClass* klass, gpointer *iter)
9251 {
9252 MonoMethod** method;
9253 if (!iter)
9254 return NULL;
9255 if (!*iter) {
9256 mono_class_setup_methods (klass);
9257
9258 /*
9259 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9260 * FIXME we should better report this error to the caller
9261 */
9262 if (!klass->methods)
9263 return NULL;
9264 /* start from the first */
9265 if (mono_class_get_method_count (klass)) {
9266 *iter = &klass->methods [0];
9267 return klass->methods [0];
9268 } else {
9269 /* no method */
9270 return NULL;
9271 }
9272 }
9273 method = (MonoMethod **)*iter;
9274 method++;
9275 if (method < &klass->methods [mono_class_get_method_count (klass)]) {
9276 *iter = method;
9277 return *method;
9278 }
9279 return NULL;
9280 }
9281
9282 /*
9283 * mono_class_get_virtual_methods:
9284 *
9285 * Iterate over the virtual methods of KLASS.
9286 *
9287 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
9288 */
9289 static MonoMethod*
mono_class_get_virtual_methods(MonoClass * klass,gpointer * iter)9290 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
9291 {
9292 gboolean static_iter = FALSE;
9293
9294 if (!iter)
9295 return NULL;
9296
9297 /*
9298 * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
9299 * and the upper bits contain an index. Otherwise, the iterator is a pointer into
9300 * klass->methods.
9301 */
9302 if ((gsize)(*iter) & 1)
9303 static_iter = TRUE;
9304 /* Use the static metadata only if klass->methods is not yet initialized */
9305 if (!static_iter && !(klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)))
9306 static_iter = TRUE;
9307
9308 if (!static_iter) {
9309 MonoMethod** methodptr;
9310
9311 if (!*iter) {
9312 mono_class_setup_methods (klass);
9313 /*
9314 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9315 * FIXME we should better report this error to the caller
9316 */
9317 if (!klass->methods)
9318 return NULL;
9319 /* start from the first */
9320 methodptr = &klass->methods [0];
9321 } else {
9322 methodptr = (MonoMethod **)*iter;
9323 methodptr++;
9324 }
9325 if (*iter)
9326 g_assert ((guint64)(*iter) > 0x100);
9327 int mcount = mono_class_get_method_count (klass);
9328 while (methodptr < &klass->methods [mcount]) {
9329 if (*methodptr && ((*methodptr)->flags & METHOD_ATTRIBUTE_VIRTUAL))
9330 break;
9331 methodptr ++;
9332 }
9333 if (methodptr < &klass->methods [mcount]) {
9334 *iter = methodptr;
9335 return *methodptr;
9336 } else {
9337 return NULL;
9338 }
9339 } else {
9340 /* Search directly in metadata to avoid calling setup_methods () */
9341 MonoMethod *res = NULL;
9342 int i, start_index;
9343
9344 if (!*iter) {
9345 start_index = 0;
9346 } else {
9347 start_index = GPOINTER_TO_UINT (*iter) >> 1;
9348 }
9349
9350 int first_idx = mono_class_get_first_method_idx (klass);
9351 int mcount = mono_class_get_method_count (klass);
9352 for (i = start_index; i < mcount; ++i) {
9353 guint32 flags;
9354
9355 /* first_idx points into the methodptr table */
9356 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
9357
9358 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
9359 break;
9360 }
9361
9362 if (i < mcount) {
9363 MonoError error;
9364 res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
9365 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9366
9367 /* Add 1 here so the if (*iter) check fails */
9368 *iter = GUINT_TO_POINTER (((i + 1) << 1) | 1);
9369 return res;
9370 } else {
9371 return NULL;
9372 }
9373 }
9374 }
9375
9376 /**
9377 * mono_class_get_properties:
9378 * \param klass the \c MonoClass to act on
9379 *
9380 * This routine is an iterator routine for retrieving the properties in a class.
9381 *
9382 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9383 * iterate over all of the elements. When no more values are
9384 * available, the return value is NULL.
9385 *
9386 * Returns: a \c MonoProperty* on each invocation, or NULL when no more are available.
9387 */
9388 MonoProperty*
mono_class_get_properties(MonoClass * klass,gpointer * iter)9389 mono_class_get_properties (MonoClass* klass, gpointer *iter)
9390 {
9391 MonoProperty* property;
9392 if (!iter)
9393 return NULL;
9394 if (!*iter) {
9395 mono_class_setup_properties (klass);
9396 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
9397 /* start from the first */
9398 if (info->count) {
9399 *iter = &info->properties [0];
9400 return (MonoProperty *)*iter;
9401 } else {
9402 /* no fields */
9403 return NULL;
9404 }
9405 }
9406 property = (MonoProperty *)*iter;
9407 property++;
9408 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
9409 if (property < &info->properties [info->count]) {
9410 *iter = property;
9411 return (MonoProperty *)*iter;
9412 }
9413 return NULL;
9414 }
9415
9416 /**
9417 * mono_class_get_events:
9418 * \param klass the \c MonoClass to act on
9419 *
9420 * This routine is an iterator routine for retrieving the properties in a class.
9421 *
9422 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
9423 * iterate over all of the elements. When no more values are
9424 * available, the return value is NULL.
9425 *
9426 * \returns a \c MonoEvent* on each invocation, or NULL when no more are available.
9427 */
9428 MonoEvent*
mono_class_get_events(MonoClass * klass,gpointer * iter)9429 mono_class_get_events (MonoClass* klass, gpointer *iter)
9430 {
9431 MonoEvent* event;
9432 if (!iter)
9433 return NULL;
9434 if (!*iter) {
9435 mono_class_setup_events (klass);
9436 MonoClassEventInfo *info = mono_class_get_event_info (klass);
9437 /* start from the first */
9438 if (info->count) {
9439 *iter = &info->events [0];
9440 return (MonoEvent *)*iter;
9441 } else {
9442 /* no fields */
9443 return NULL;
9444 }
9445 }
9446 event = (MonoEvent *)*iter;
9447 event++;
9448 MonoClassEventInfo *info = mono_class_get_event_info (klass);
9449 if (event < &info->events [info->count]) {
9450 *iter = event;
9451 return (MonoEvent *)*iter;
9452 }
9453 return NULL;
9454 }
9455
9456 /**
9457 * mono_class_get_interfaces
9458 * \param klass the \c MonoClass to act on
9459 *
9460 * This routine is an iterator routine for retrieving the interfaces implemented by this class.
9461 *
9462 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
9463 * iterate over all of the elements. When no more values are
9464 * available, the return value is NULL.
9465 *
9466 * \returns a \c MonoClass* on each invocation, or NULL when no more are available.
9467 */
9468 MonoClass*
mono_class_get_interfaces(MonoClass * klass,gpointer * iter)9469 mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
9470 {
9471 MonoError error;
9472 MonoClass** iface;
9473 if (!iter)
9474 return NULL;
9475 if (!*iter) {
9476 if (!klass->inited)
9477 mono_class_init (klass);
9478 if (!klass->interfaces_inited) {
9479 mono_class_setup_interfaces (klass, &error);
9480 if (!mono_error_ok (&error)) {
9481 mono_error_cleanup (&error);
9482 return NULL;
9483 }
9484 }
9485 /* start from the first */
9486 if (klass->interface_count) {
9487 *iter = &klass->interfaces [0];
9488 return klass->interfaces [0];
9489 } else {
9490 /* no interface */
9491 return NULL;
9492 }
9493 }
9494 iface = (MonoClass **)*iter;
9495 iface++;
9496 if (iface < &klass->interfaces [klass->interface_count]) {
9497 *iter = iface;
9498 return *iface;
9499 }
9500 return NULL;
9501 }
9502
9503 static void
setup_nested_types(MonoClass * klass)9504 setup_nested_types (MonoClass *klass)
9505 {
9506 MonoError error;
9507 GList *classes, *nested_classes, *l;
9508 int i;
9509
9510 if (klass->nested_classes_inited)
9511 return;
9512
9513 if (!klass->type_token) {
9514 mono_loader_lock ();
9515 klass->nested_classes_inited = TRUE;
9516 mono_loader_unlock ();
9517 return;
9518 }
9519
9520 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
9521 classes = NULL;
9522 while (i) {
9523 MonoClass* nclass;
9524 guint32 cols [MONO_NESTED_CLASS_SIZE];
9525 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
9526 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error);
9527 if (!mono_error_ok (&error)) {
9528 /*FIXME don't swallow the error message*/
9529 mono_error_cleanup (&error);
9530
9531 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
9532 continue;
9533 }
9534
9535 classes = g_list_prepend (classes, nclass);
9536
9537 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
9538 }
9539
9540 nested_classes = NULL;
9541 for (l = classes; l; l = l->next)
9542 nested_classes = g_list_prepend_image (klass->image, nested_classes, l->data);
9543 g_list_free (classes);
9544
9545 mono_loader_lock ();
9546 if (!klass->nested_classes_inited) {
9547 mono_class_set_nested_classes_property (klass, nested_classes);
9548 mono_memory_barrier ();
9549 klass->nested_classes_inited = TRUE;
9550 }
9551 mono_loader_unlock ();
9552 }
9553
9554 /**
9555 * mono_class_get_nested_types
9556 * \param klass the \c MonoClass to act on
9557 *
9558 * This routine is an iterator routine for retrieving the nested types of a class.
9559 * This works only if \p klass is non-generic, or a generic type definition.
9560 *
9561 * You must pass a \c gpointer that points to zero and is treated as an opaque handle to
9562 * iterate over all of the elements. When no more values are
9563 * available, the return value is NULL.
9564 *
9565 * \returns a \c Monoclass* on each invocation, or NULL when no more are available.
9566 */
9567 MonoClass*
mono_class_get_nested_types(MonoClass * klass,gpointer * iter)9568 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
9569 {
9570 GList *item;
9571
9572 if (!iter)
9573 return NULL;
9574 if (!klass->nested_classes_inited)
9575 setup_nested_types (klass);
9576
9577 if (!*iter) {
9578 GList *nested_classes = mono_class_get_nested_classes_property (klass);
9579 /* start from the first */
9580 if (nested_classes) {
9581 *iter = nested_classes;
9582 return (MonoClass *)nested_classes->data;
9583 } else {
9584 /* no nested types */
9585 return NULL;
9586 }
9587 }
9588 item = (GList *)*iter;
9589 item = item->next;
9590 if (item) {
9591 *iter = item;
9592 return (MonoClass *)item->data;
9593 }
9594 return NULL;
9595 }
9596
9597
9598 /**
9599 * mono_class_is_delegate
9600 * \param klass the \c MonoClass to act on
9601 *
9602 * \returns TRUE if the \c MonoClass represents a \c System.Delegate.
9603 */
9604 mono_bool
mono_class_is_delegate(MonoClass * klass)9605 mono_class_is_delegate (MonoClass *klass)
9606 {
9607 return klass->delegate;
9608 }
9609
9610 /**
9611 * mono_class_implements_interface
9612 * \param klass The MonoClass to act on
9613 * \param interface The interface to check if \p klass implements.
9614 *
9615 * \returns TRUE if \p klass implements \p interface.
9616 */
9617 mono_bool
mono_class_implements_interface(MonoClass * klass,MonoClass * iface)9618 mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
9619 {
9620 return mono_class_is_assignable_from (iface, klass);
9621 }
9622
9623 /**
9624 * mono_field_get_name:
9625 * \param field the \c MonoClassField to act on
9626 *
9627 * \returns The name of the field.
9628 */
9629 const char*
mono_field_get_name(MonoClassField * field)9630 mono_field_get_name (MonoClassField *field)
9631 {
9632 return field->name;
9633 }
9634
9635 /**
9636 * mono_field_get_type:
9637 * \param field the \c MonoClassField to act on
9638 * \returns \c MonoType of the field.
9639 */
9640 MonoType*
mono_field_get_type(MonoClassField * field)9641 mono_field_get_type (MonoClassField *field)
9642 {
9643 MonoError error;
9644 MonoType *type = mono_field_get_type_checked (field, &error);
9645 if (!mono_error_ok (&error)) {
9646 mono_trace_warning (MONO_TRACE_TYPE, "Could not load field's type due to %s", mono_error_get_message (&error));
9647 mono_error_cleanup (&error);
9648 }
9649 return type;
9650 }
9651
9652
9653 /**
9654 * mono_field_get_type_checked:
9655 * \param field the \c MonoClassField to act on
9656 * \param error used to return any error found while retrieving \p field type
9657 *
9658 * \returns \c MonoType of the field.
9659 */
9660 MonoType*
mono_field_get_type_checked(MonoClassField * field,MonoError * error)9661 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
9662 {
9663 error_init (error);
9664 if (!field->type)
9665 mono_field_resolve_type (field, error);
9666 return field->type;
9667 }
9668
9669 /**
9670 * mono_field_get_parent:
9671 * \param field the \c MonoClassField to act on
9672 *
9673 * \returns \c MonoClass where the field was defined.
9674 */
9675 MonoClass*
mono_field_get_parent(MonoClassField * field)9676 mono_field_get_parent (MonoClassField *field)
9677 {
9678 return field->parent;
9679 }
9680
9681 /**
9682 * mono_field_get_flags;
9683 * \param field the \c MonoClassField to act on
9684 *
9685 * The metadata flags for a field are encoded using the
9686 * \c FIELD_ATTRIBUTE_* constants. See the \c tabledefs.h file for details.
9687 *
9688 * \returns The flags for the field.
9689 */
9690 guint32
mono_field_get_flags(MonoClassField * field)9691 mono_field_get_flags (MonoClassField *field)
9692 {
9693 if (!field->type)
9694 return mono_field_resolve_flags (field);
9695 return field->type->attrs;
9696 }
9697
9698 /**
9699 * mono_field_get_offset:
9700 * \param field the \c MonoClassField to act on
9701 *
9702 * \returns The field offset.
9703 */
9704 guint32
mono_field_get_offset(MonoClassField * field)9705 mono_field_get_offset (MonoClassField *field)
9706 {
9707 return field->offset;
9708 }
9709
9710 static const char *
mono_field_get_rva(MonoClassField * field)9711 mono_field_get_rva (MonoClassField *field)
9712 {
9713 guint32 rva;
9714 int field_index;
9715 MonoClass *klass = field->parent;
9716 MonoFieldDefaultValue *def_values;
9717
9718 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
9719
9720 def_values = mono_class_get_field_def_values (klass);
9721 if (!def_values) {
9722 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
9723
9724 mono_class_set_field_def_values (klass, def_values);
9725 }
9726
9727 field_index = mono_field_get_index (field);
9728
9729 if (!def_values [field_index].data && !image_is_dynamic (klass->image)) {
9730 int first_field_idx = mono_class_get_first_field_idx (klass);
9731 mono_metadata_field_info (field->parent->image, first_field_idx + field_index, NULL, &rva, NULL);
9732 if (!rva)
9733 g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
9734 def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
9735 }
9736
9737 return def_values [field_index].data;
9738 }
9739
9740 /**
9741 * mono_field_get_data:
9742 * \param field the \c MonoClassField to act on
9743 *
9744 * \returns A pointer to the metadata constant value or to the field
9745 * data if it has an RVA flag.
9746 */
9747 const char *
mono_field_get_data(MonoClassField * field)9748 mono_field_get_data (MonoClassField *field)
9749 {
9750 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
9751 MonoTypeEnum def_type;
9752
9753 return mono_class_get_field_default_value (field, &def_type);
9754 } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
9755 return mono_field_get_rva (field);
9756 } else {
9757 return NULL;
9758 }
9759 }
9760
9761 /**
9762 * mono_property_get_name:
9763 * \param prop the \c MonoProperty to act on
9764 * \returns The name of the property
9765 */
9766 const char*
mono_property_get_name(MonoProperty * prop)9767 mono_property_get_name (MonoProperty *prop)
9768 {
9769 return prop->name;
9770 }
9771
9772 /**
9773 * mono_property_get_set_method
9774 * \param prop the \c MonoProperty to act on.
9775 * \returns The setter method of the property, a \c MonoMethod.
9776 */
9777 MonoMethod*
mono_property_get_set_method(MonoProperty * prop)9778 mono_property_get_set_method (MonoProperty *prop)
9779 {
9780 return prop->set;
9781 }
9782
9783 /**
9784 * mono_property_get_get_method
9785 * \param prop the MonoProperty to act on.
9786 * \returns The getter method of the property (A \c MonoMethod)
9787 */
9788 MonoMethod*
mono_property_get_get_method(MonoProperty * prop)9789 mono_property_get_get_method (MonoProperty *prop)
9790 {
9791 return prop->get;
9792 }
9793
9794 /**
9795 * mono_property_get_parent:
9796 * \param prop the \c MonoProperty to act on.
9797 * \returns The \c MonoClass where the property was defined.
9798 */
9799 MonoClass*
mono_property_get_parent(MonoProperty * prop)9800 mono_property_get_parent (MonoProperty *prop)
9801 {
9802 return prop->parent;
9803 }
9804
9805 /**
9806 * mono_property_get_flags:
9807 * \param prop the \c MonoProperty to act on.
9808 *
9809 * The metadata flags for a property are encoded using the
9810 * \c PROPERTY_ATTRIBUTE_* constants. See the \c tabledefs.h file for details.
9811 *
9812 * \returns The flags for the property.
9813 */
9814 guint32
mono_property_get_flags(MonoProperty * prop)9815 mono_property_get_flags (MonoProperty *prop)
9816 {
9817 return prop->attrs;
9818 }
9819
9820 /**
9821 * mono_event_get_name:
9822 * \param event the MonoEvent to act on
9823 * \returns The name of the event.
9824 */
9825 const char*
mono_event_get_name(MonoEvent * event)9826 mono_event_get_name (MonoEvent *event)
9827 {
9828 return event->name;
9829 }
9830
9831 /**
9832 * mono_event_get_add_method:
9833 * \param event The \c MonoEvent to act on.
9834 * \returns The \c add method for the event, a \c MonoMethod.
9835 */
9836 MonoMethod*
mono_event_get_add_method(MonoEvent * event)9837 mono_event_get_add_method (MonoEvent *event)
9838 {
9839 return event->add;
9840 }
9841
9842 /**
9843 * mono_event_get_remove_method:
9844 * \param event The \c MonoEvent to act on.
9845 * \returns The \c remove method for the event, a \c MonoMethod.
9846 */
9847 MonoMethod*
mono_event_get_remove_method(MonoEvent * event)9848 mono_event_get_remove_method (MonoEvent *event)
9849 {
9850 return event->remove;
9851 }
9852
9853 /**
9854 * mono_event_get_raise_method:
9855 * \param event The \c MonoEvent to act on.
9856 * \returns The \c raise method for the event, a \c MonoMethod.
9857 */
9858 MonoMethod*
mono_event_get_raise_method(MonoEvent * event)9859 mono_event_get_raise_method (MonoEvent *event)
9860 {
9861 return event->raise;
9862 }
9863
9864 /**
9865 * mono_event_get_parent:
9866 * \param event the MonoEvent to act on.
9867 * \returns The \c MonoClass where the event is defined.
9868 */
9869 MonoClass*
mono_event_get_parent(MonoEvent * event)9870 mono_event_get_parent (MonoEvent *event)
9871 {
9872 return event->parent;
9873 }
9874
9875 /**
9876 * mono_event_get_flags
9877 * \param event the \c MonoEvent to act on.
9878 *
9879 * The metadata flags for an event are encoded using the
9880 * \c EVENT_* constants. See the \c tabledefs.h file for details.
9881 *
9882 * \returns The flags for the event.
9883 */
9884 guint32
mono_event_get_flags(MonoEvent * event)9885 mono_event_get_flags (MonoEvent *event)
9886 {
9887 return event->attrs;
9888 }
9889
9890 /**
9891 * mono_class_get_method_from_name:
9892 * \param klass where to look for the method
9893 * \param name name of the method
9894 * \param param_count number of parameters. -1 for any number.
9895 *
9896 * Obtains a \c MonoMethod with a given name and number of parameters.
9897 * It only works if there are no multiple signatures for any given method name.
9898 */
9899 MonoMethod *
mono_class_get_method_from_name(MonoClass * klass,const char * name,int param_count)9900 mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_count)
9901 {
9902 return mono_class_get_method_from_name_flags (klass, name, param_count, 0);
9903 }
9904
9905 static MonoMethod*
find_method_in_metadata(MonoClass * klass,const char * name,int param_count,int flags)9906 find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
9907 {
9908 MonoMethod *res = NULL;
9909 int i;
9910
9911 /* Search directly in the metadata to avoid calling setup_methods () */
9912 int first_idx = mono_class_get_first_method_idx (klass);
9913 int mcount = mono_class_get_method_count (klass);
9914 for (i = 0; i < mcount; ++i) {
9915 MonoError error;
9916 guint32 cols [MONO_METHOD_SIZE];
9917 MonoMethod *method;
9918 MonoMethodSignature *sig;
9919
9920 /* first_idx points into the methodptr table */
9921 mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE);
9922
9923 if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
9924 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
9925 if (!method) {
9926 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9927 continue;
9928 }
9929 if (param_count == -1) {
9930 res = method;
9931 break;
9932 }
9933 sig = mono_method_signature_checked (method, &error);
9934 if (!sig) {
9935 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9936 continue;
9937 }
9938 if (sig->param_count == param_count) {
9939 res = method;
9940 break;
9941 }
9942 }
9943 }
9944
9945 return res;
9946 }
9947
9948 /**
9949 * mono_class_get_method_from_name_flags:
9950 * \param klass where to look for the method
9951 * \param name_space name of the method
9952 * \param param_count number of parameters. -1 for any number.
9953 * \param flags flags which must be set in the method
9954 *
9955 * Obtains a \c MonoMethod with a given name and number of parameters.
9956 * It only works if there are no multiple signatures for any given method name.
9957 */
9958 MonoMethod *
mono_class_get_method_from_name_flags(MonoClass * klass,const char * name,int param_count,int flags)9959 mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int param_count, int flags)
9960 {
9961 MonoMethod *res = NULL;
9962 int i;
9963
9964 mono_class_init (klass);
9965
9966 if (mono_class_is_ginst (klass) && !klass->methods) {
9967 res = mono_class_get_method_from_name_flags (mono_class_get_generic_class (klass)->container_class, name, param_count, flags);
9968 if (res) {
9969 MonoError error;
9970 res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), &error);
9971 if (!mono_error_ok (&error))
9972 mono_error_cleanup (&error); /*FIXME don't swallow the error */
9973 }
9974 return res;
9975 }
9976
9977 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
9978 mono_class_setup_methods (klass);
9979 /*
9980 We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9981 See mono/tests/array_load_exception.il
9982 FIXME we should better report this error to the caller
9983 */
9984 if (!klass->methods)
9985 return NULL;
9986 int mcount = mono_class_get_method_count (klass);
9987 for (i = 0; i < mcount; ++i) {
9988 MonoMethod *method = klass->methods [i];
9989
9990 if (method->name[0] == name [0] &&
9991 !strcmp (name, method->name) &&
9992 (param_count == -1 || mono_method_signature (method)->param_count == param_count) &&
9993 ((method->flags & flags) == flags)) {
9994 res = method;
9995 break;
9996 }
9997 }
9998 }
9999 else {
10000 res = find_method_in_metadata (klass, name, param_count, flags);
10001 }
10002
10003 return res;
10004 }
10005
10006 /**
10007 * mono_class_set_failure:
10008 * \param klass class in which the failure was detected
10009 * \param ex_type the kind of exception/error to be thrown (later)
10010 * \param ex_data exception data (specific to each type of exception/error)
10011 *
10012 * Keep a detected failure informations in the class for later processing.
10013 * Note that only the first failure is kept.
10014 *
10015 * LOCKING: Acquires the loader lock.
10016 */
10017 static gboolean
mono_class_set_failure(MonoClass * klass,MonoErrorBoxed * boxed_error)10018 mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error)
10019 {
10020 g_assert (boxed_error != NULL);
10021
10022 if (mono_class_has_failure (klass))
10023 return FALSE;
10024
10025 mono_loader_lock ();
10026 klass->has_failure = 1;
10027 mono_class_set_exception_data (klass, boxed_error);
10028 mono_loader_unlock ();
10029
10030 return TRUE;
10031 }
10032
10033 gboolean
mono_class_has_failure(const MonoClass * klass)10034 mono_class_has_failure (const MonoClass *klass)
10035 {
10036 g_assert (klass != NULL);
10037 return klass->has_failure != 0;
10038 }
10039
10040
10041 /**
10042 * mono_class_set_type_load_failure:
10043 * \param klass class in which the failure was detected
10044 * \param fmt \c printf -style error message string.
10045 *
10046 * Collect detected failure informaion in the class for later processing.
10047 * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class()
10048 * Note that only the first failure is kept.
10049 *
10050 * LOCKING: Acquires the loader lock.
10051 *
10052 * \returns FALSE if a failure was already set on the class, or TRUE otherwise.
10053 */
10054 gboolean
mono_class_set_type_load_failure(MonoClass * klass,const char * fmt,...)10055 mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
10056 {
10057 MonoError prepare_error;
10058 va_list args;
10059
10060 if (mono_class_has_failure (klass))
10061 return FALSE;
10062
10063 error_init (&prepare_error);
10064
10065 va_start (args, fmt);
10066 mono_error_vset_type_load_class (&prepare_error, klass, fmt, args);
10067 va_end (args);
10068
10069 MonoErrorBoxed *box = mono_error_box (&prepare_error, klass->image);
10070 mono_error_cleanup (&prepare_error);
10071 return mono_class_set_failure (klass, box);
10072 }
10073
10074 /**
10075 * mono_classes_init:
10076 *
10077 * Initialize the resources used by this module.
10078 * Known racy counters: `class_gparam_count`, `classes_size` and `inflated_methods_size`
10079 */
10080 MONO_NO_SANITIZE_THREAD
10081 void
mono_classes_init(void)10082 mono_classes_init (void)
10083 {
10084 mono_os_mutex_init (&classes_mutex);
10085
10086 mono_native_tls_alloc (&setup_fields_tls_id, NULL);
10087 mono_native_tls_alloc (&init_pending_tls_id, NULL);
10088
10089 mono_counters_register ("MonoClassDef count",
10090 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
10091 mono_counters_register ("MonoClassGtd count",
10092 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
10093 mono_counters_register ("MonoClassGenericInst count",
10094 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
10095 mono_counters_register ("MonoClassGenericParam count",
10096 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
10097 mono_counters_register ("MonoClassArray count",
10098 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
10099 mono_counters_register ("MonoClassPointer count",
10100 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
10101 mono_counters_register ("Inflated methods size",
10102 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
10103 mono_counters_register ("Inflated classes size",
10104 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
10105 mono_counters_register ("MonoClass size",
10106 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
10107 }
10108
10109 /**
10110 * mono_classes_cleanup:
10111 *
10112 * Free the resources used by this module.
10113 */
10114 void
mono_classes_cleanup(void)10115 mono_classes_cleanup (void)
10116 {
10117 mono_native_tls_free (setup_fields_tls_id);
10118 mono_native_tls_free (init_pending_tls_id);
10119
10120 if (global_interface_bitset)
10121 mono_bitset_free (global_interface_bitset);
10122 global_interface_bitset = NULL;
10123 mono_os_mutex_destroy (&classes_mutex);
10124 }
10125
10126 /**
10127 * mono_class_get_exception_for_failure:
10128 * \param klass class in which the failure was detected
10129 *
10130 * \returns a constructed MonoException than the caller can then throw
10131 * using mono_raise_exception - or NULL if no failure is present (or
10132 * doesn't result in an exception).
10133 */
10134 MonoException*
mono_class_get_exception_for_failure(MonoClass * klass)10135 mono_class_get_exception_for_failure (MonoClass *klass)
10136 {
10137 if (!mono_class_has_failure (klass))
10138 return NULL;
10139 MonoError unboxed_error;
10140 error_init (&unboxed_error);
10141 mono_error_set_for_class_failure (&unboxed_error, klass);
10142 return mono_error_convert_to_exception (&unboxed_error);
10143 }
10144
10145 static gboolean
is_nesting_type(MonoClass * outer_klass,MonoClass * inner_klass)10146 is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
10147 {
10148 outer_klass = mono_class_get_generic_type_definition (outer_klass);
10149 inner_klass = mono_class_get_generic_type_definition (inner_klass);
10150 do {
10151 if (outer_klass == inner_klass)
10152 return TRUE;
10153 inner_klass = inner_klass->nested_in;
10154 } while (inner_klass);
10155 return FALSE;
10156 }
10157
10158 MonoClass *
mono_class_get_generic_type_definition(MonoClass * klass)10159 mono_class_get_generic_type_definition (MonoClass *klass)
10160 {
10161 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
10162 return gklass ? gklass->container_class : klass;
10163 }
10164
10165 /*
10166 * Check if @klass is a subtype of @parent ignoring generic instantiations.
10167 *
10168 * Generic instantiations are ignored for all super types of @klass.
10169 *
10170 * Visibility checks ignoring generic instantiations.
10171 */
10172 gboolean
mono_class_has_parent_and_ignore_generics(MonoClass * klass,MonoClass * parent)10173 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
10174 {
10175 int i;
10176 klass = mono_class_get_generic_type_definition (klass);
10177 parent = mono_class_get_generic_type_definition (parent);
10178 mono_class_setup_supertypes (klass);
10179
10180 for (i = 0; i < klass->idepth; ++i) {
10181 if (parent == mono_class_get_generic_type_definition (klass->supertypes [i]))
10182 return TRUE;
10183 }
10184 return FALSE;
10185 }
10186 /*
10187 * Subtype can only access parent members with family protection if the site object
10188 * is subclass of Subtype. For example:
10189 * class A { protected int x; }
10190 * class B : A {
10191 * void valid_access () {
10192 * B b;
10193 * b.x = 0;
10194 * }
10195 * void invalid_access () {
10196 * A a;
10197 * a.x = 0;
10198 * }
10199 * }
10200 * */
10201 static gboolean
is_valid_family_access(MonoClass * access_klass,MonoClass * member_klass,MonoClass * context_klass)10202 is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
10203 {
10204 if (MONO_CLASS_IS_INTERFACE (member_klass) && !MONO_CLASS_IS_INTERFACE (access_klass)) {
10205 /* Can happen with default interface methods */
10206 if (!mono_class_implements_interface (access_klass, member_klass))
10207 return FALSE;
10208 } else {
10209 if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
10210 return FALSE;
10211 }
10212
10213 if (context_klass == NULL)
10214 return TRUE;
10215 /*if access_klass is not member_klass context_klass must be type compat*/
10216 if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
10217 return FALSE;
10218 return TRUE;
10219 }
10220
10221 static gboolean
can_access_internals(MonoAssembly * accessing,MonoAssembly * accessed)10222 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
10223 {
10224 GSList *tmp;
10225 if (accessing == accessed)
10226 return TRUE;
10227 if (!accessed || !accessing)
10228 return FALSE;
10229
10230 /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
10231 * anywhere so untrusted friends are not safe to access platform's code internals */
10232 if (mono_security_core_clr_enabled ()) {
10233 if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
10234 return FALSE;
10235 }
10236
10237 mono_assembly_load_friends (accessed);
10238 for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
10239 MonoAssemblyName *friend_ = (MonoAssemblyName *)tmp->data;
10240 /* Be conservative with checks */
10241 if (!friend_->name)
10242 continue;
10243 if (g_ascii_strcasecmp (accessing->aname.name, friend_->name))
10244 continue;
10245 if (friend_->public_key_token [0]) {
10246 if (!accessing->aname.public_key_token [0])
10247 continue;
10248 if (!mono_public_tokens_are_equal (friend_->public_key_token, accessing->aname.public_key_token))
10249 continue;
10250 }
10251 return TRUE;
10252 }
10253 return FALSE;
10254 }
10255
10256 /*
10257 * If klass is a generic type or if it is derived from a generic type, return the
10258 * MonoClass of the generic definition
10259 * Returns NULL if not found
10260 */
10261 static MonoClass*
get_generic_definition_class(MonoClass * klass)10262 get_generic_definition_class (MonoClass *klass)
10263 {
10264 while (klass) {
10265 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
10266 if (gklass && gklass->container_class)
10267 return gklass->container_class;
10268 klass = klass->parent;
10269 }
10270 return NULL;
10271 }
10272
10273 static gboolean
can_access_instantiation(MonoClass * access_klass,MonoGenericInst * ginst)10274 can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
10275 {
10276 int i;
10277 for (i = 0; i < ginst->type_argc; ++i) {
10278 MonoType *type = ginst->type_argv[i];
10279 switch (type->type) {
10280 case MONO_TYPE_SZARRAY:
10281 if (!can_access_type (access_klass, type->data.klass))
10282 return FALSE;
10283 break;
10284 case MONO_TYPE_ARRAY:
10285 if (!can_access_type (access_klass, type->data.array->eklass))
10286 return FALSE;
10287 break;
10288 case MONO_TYPE_PTR:
10289 if (!can_access_type (access_klass, mono_class_from_mono_type (type->data.type)))
10290 return FALSE;
10291 break;
10292 case MONO_TYPE_CLASS:
10293 case MONO_TYPE_VALUETYPE:
10294 case MONO_TYPE_GENERICINST:
10295 if (!can_access_type (access_klass, mono_class_from_mono_type (type)))
10296 return FALSE;
10297 default:
10298 break;
10299 }
10300 }
10301 return TRUE;
10302 }
10303
10304 static gboolean
can_access_type(MonoClass * access_klass,MonoClass * member_klass)10305 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
10306 {
10307 int access_level;
10308
10309 if (access_klass == member_klass)
10310 return TRUE;
10311
10312 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
10313 return TRUE;
10314
10315 if (access_klass->element_class && !access_klass->enumtype)
10316 access_klass = access_klass->element_class;
10317
10318 if (member_klass->element_class && !member_klass->enumtype)
10319 member_klass = member_klass->element_class;
10320
10321 access_level = mono_class_get_flags (member_klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
10322
10323 if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
10324 return TRUE;
10325
10326 if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst))
10327 return FALSE;
10328
10329 if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
10330 return TRUE;
10331
10332 /*Non nested type with nested visibility. We just fail it.*/
10333 if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL)
10334 return FALSE;
10335
10336 MonoClass *member_klass_nested_in = member_klass->nested_in;
10337 switch (access_level) {
10338 case TYPE_ATTRIBUTE_NOT_PUBLIC:
10339 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10340
10341 case TYPE_ATTRIBUTE_PUBLIC:
10342 return TRUE;
10343
10344 case TYPE_ATTRIBUTE_NESTED_PUBLIC:
10345 return member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
10346
10347 case TYPE_ATTRIBUTE_NESTED_PRIVATE:
10348 return is_nesting_type (member_klass, access_klass) && member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
10349
10350 case TYPE_ATTRIBUTE_NESTED_FAMILY:
10351 return mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10352
10353 case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
10354 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly) && member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
10355
10356 case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
10357 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) &&
10358 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10359
10360 case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
10361 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) ||
10362 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10363 }
10364 return FALSE;
10365 }
10366
10367 /* FIXME: check visibility of type, too */
10368 static gboolean
can_access_member(MonoClass * access_klass,MonoClass * member_klass,MonoClass * context_klass,int access_level)10369 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
10370 {
10371 MonoClass *member_generic_def;
10372 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
10373 return TRUE;
10374
10375 MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass);
10376 if (((access_gklass && access_gklass->container_class) ||
10377 mono_class_is_gtd (access_klass)) &&
10378 (member_generic_def = get_generic_definition_class (member_klass))) {
10379 MonoClass *access_container;
10380
10381 if (mono_class_is_gtd (access_klass))
10382 access_container = access_klass;
10383 else
10384 access_container = access_gklass->container_class;
10385
10386 if (can_access_member (access_container, member_generic_def, context_klass, access_level))
10387 return TRUE;
10388 }
10389
10390 /* Partition I 8.5.3.2 */
10391 /* the access level values are the same for fields and methods */
10392 switch (access_level) {
10393 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
10394 /* same compilation unit */
10395 return access_klass->image == member_klass->image;
10396 case FIELD_ATTRIBUTE_PRIVATE:
10397 return access_klass == member_klass;
10398 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
10399 if (is_valid_family_access (access_klass, member_klass, context_klass) &&
10400 can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
10401 return TRUE;
10402 return FALSE;
10403 case FIELD_ATTRIBUTE_ASSEMBLY:
10404 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10405 case FIELD_ATTRIBUTE_FAMILY:
10406 if (is_valid_family_access (access_klass, member_klass, context_klass))
10407 return TRUE;
10408 return FALSE;
10409 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
10410 if (is_valid_family_access (access_klass, member_klass, context_klass))
10411 return TRUE;
10412 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10413 case FIELD_ATTRIBUTE_PUBLIC:
10414 return TRUE;
10415 }
10416 return FALSE;
10417 }
10418
10419 /**
10420 * mono_method_can_access_field:
10421 * \param method Method that will attempt to access the field
10422 * \param field the field to access
10423 *
10424 * Used to determine if a method is allowed to access the specified field.
10425 *
10426 * \returns TRUE if the given \p method is allowed to access the \p field while following
10427 * the accessibility rules of the CLI.
10428 */
10429 gboolean
mono_method_can_access_field(MonoMethod * method,MonoClassField * field)10430 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
10431 {
10432 /* FIXME: check all overlapping fields */
10433 int can = can_access_member (method->klass, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10434 if (!can) {
10435 MonoClass *nested = method->klass->nested_in;
10436 while (nested) {
10437 can = can_access_member (nested, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10438 if (can)
10439 return TRUE;
10440 nested = nested->nested_in;
10441 }
10442 }
10443 return can;
10444 }
10445
10446 /**
10447 * mono_method_can_access_method:
10448 * \param method Method that will attempt to access the other method
10449 * \param called the method that we want to probe for accessibility.
10450 *
10451 * Used to determine if the \p method is allowed to access the specified \p called method.
10452 *
10453 * \returns TRUE if the given \p method is allowed to invoke the \p called while following
10454 * the accessibility rules of the CLI.
10455 */
10456 gboolean
mono_method_can_access_method(MonoMethod * method,MonoMethod * called)10457 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
10458 {
10459 method = mono_method_get_method_definition (method);
10460 called = mono_method_get_method_definition (called);
10461 return mono_method_can_access_method_full (method, called, NULL);
10462 }
10463
10464 /*
10465 * mono_method_can_access_method_full:
10466 * @method: The caller method
10467 * @called: The called method
10468 * @context_klass: The static type on stack of the owner @called object used
10469 *
10470 * This function must be used with instance calls, as they have more strict family accessibility.
10471 * It can be used with static methods, but context_klass should be NULL.
10472 *
10473 * Returns: TRUE if caller have proper visibility and acessibility to @called
10474 */
10475 gboolean
mono_method_can_access_method_full(MonoMethod * method,MonoMethod * called,MonoClass * context_klass)10476 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
10477 {
10478 /* Wrappers are except from access checks */
10479 if (method->wrapper_type != MONO_WRAPPER_NONE || called->wrapper_type != MONO_WRAPPER_NONE)
10480 return TRUE;
10481
10482 MonoClass *access_class = method->klass;
10483 MonoClass *member_class = called->klass;
10484 int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10485 if (!can) {
10486 MonoClass *nested = access_class->nested_in;
10487 while (nested) {
10488 can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10489 if (can)
10490 break;
10491 nested = nested->nested_in;
10492 }
10493 }
10494
10495 if (!can)
10496 return FALSE;
10497
10498 can = can_access_type (access_class, member_class);
10499 if (!can) {
10500 MonoClass *nested = access_class->nested_in;
10501 while (nested) {
10502 can = can_access_type (nested, member_class);
10503 if (can)
10504 break;
10505 nested = nested->nested_in;
10506 }
10507 }
10508
10509 if (!can)
10510 return FALSE;
10511
10512 if (called->is_inflated) {
10513 MonoMethodInflated * infl = (MonoMethodInflated*)called;
10514 if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
10515 return FALSE;
10516 }
10517
10518 return TRUE;
10519 }
10520
10521
10522 /*
10523 * mono_method_can_access_field_full:
10524 * @method: The caller method
10525 * @field: The accessed field
10526 * @context_klass: The static type on stack of the owner @field object used
10527 *
10528 * This function must be used with instance fields, as they have more strict family accessibility.
10529 * It can be used with static fields, but context_klass should be NULL.
10530 *
10531 * Returns: TRUE if caller have proper visibility and acessibility to @field
10532 */
10533 gboolean
mono_method_can_access_field_full(MonoMethod * method,MonoClassField * field,MonoClass * context_klass)10534 mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
10535 {
10536 MonoClass *access_class = method->klass;
10537 MonoClass *member_class = field->parent;
10538 /* FIXME: check all overlapping fields */
10539 int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10540 if (!can) {
10541 MonoClass *nested = access_class->nested_in;
10542 while (nested) {
10543 can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10544 if (can)
10545 break;
10546 nested = nested->nested_in;
10547 }
10548 }
10549
10550 if (!can)
10551 return FALSE;
10552
10553 can = can_access_type (access_class, member_class);
10554 if (!can) {
10555 MonoClass *nested = access_class->nested_in;
10556 while (nested) {
10557 can = can_access_type (nested, member_class);
10558 if (can)
10559 break;
10560 nested = nested->nested_in;
10561 }
10562 }
10563
10564 if (!can)
10565 return FALSE;
10566 return TRUE;
10567 }
10568
10569 /*
10570 * mono_class_can_access_class:
10571 * @source_class: The source class
10572 * @target_class: The accessed class
10573 *
10574 * This function returns is @target_class is visible to @source_class
10575 *
10576 * Returns: TRUE if source have proper visibility and acessibility to target
10577 */
10578 gboolean
mono_class_can_access_class(MonoClass * source_class,MonoClass * target_class)10579 mono_class_can_access_class (MonoClass *source_class, MonoClass *target_class)
10580 {
10581 return can_access_type (source_class, target_class);
10582 }
10583
10584 /**
10585 * mono_type_is_valid_enum_basetype:
10586 * \param type The MonoType to check
10587 * \returns TRUE if the type can be used as the basetype of an enum
10588 */
mono_type_is_valid_enum_basetype(MonoType * type)10589 gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
10590 switch (type->type) {
10591 case MONO_TYPE_I1:
10592 case MONO_TYPE_U1:
10593 case MONO_TYPE_BOOLEAN:
10594 case MONO_TYPE_I2:
10595 case MONO_TYPE_U2:
10596 case MONO_TYPE_CHAR:
10597 case MONO_TYPE_I4:
10598 case MONO_TYPE_U4:
10599 case MONO_TYPE_I8:
10600 case MONO_TYPE_U8:
10601 case MONO_TYPE_I:
10602 case MONO_TYPE_U:
10603 return TRUE;
10604 default:
10605 return FALSE;
10606 }
10607 }
10608
10609 /**
10610 * mono_class_is_valid_enum:
10611 * \param klass An enum class to be validated
10612 *
10613 * This method verify the required properties an enum should have.
10614 *
10615 * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
10616 * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
10617 * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
10618 *
10619 * \returns TRUE if the informed enum class is valid
10620 */
10621 gboolean
mono_class_is_valid_enum(MonoClass * klass)10622 mono_class_is_valid_enum (MonoClass *klass)
10623 {
10624 MonoClassField * field;
10625 gpointer iter = NULL;
10626 gboolean found_base_field = FALSE;
10627
10628 g_assert (klass->enumtype);
10629 /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
10630 if (!klass->parent || strcmp (klass->parent->name, "Enum") || strcmp (klass->parent->name_space, "System") ) {
10631 return FALSE;
10632 }
10633
10634 if (!mono_class_is_auto_layout (klass))
10635 return FALSE;
10636
10637 while ((field = mono_class_get_fields (klass, &iter))) {
10638 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
10639 if (found_base_field)
10640 return FALSE;
10641 found_base_field = TRUE;
10642 if (!mono_type_is_valid_enum_basetype (field->type))
10643 return FALSE;
10644 }
10645 }
10646
10647 if (!found_base_field)
10648 return FALSE;
10649
10650 if (mono_class_get_method_count (klass) > 0)
10651 return FALSE;
10652
10653 return TRUE;
10654 }
10655
10656 gboolean
mono_generic_class_is_generic_type_definition(MonoGenericClass * gklass)10657 mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
10658 {
10659 return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst;
10660 }
10661
10662 /*
10663 * mono_class_setup_interface_id:
10664 *
10665 * Initializes MonoClass::interface_id if required.
10666 *
10667 * LOCKING: Acquires the loader lock.
10668 */
10669 void
mono_class_setup_interface_id(MonoClass * klass)10670 mono_class_setup_interface_id (MonoClass *klass)
10671 {
10672 g_assert (MONO_CLASS_IS_INTERFACE (klass));
10673 mono_loader_lock ();
10674 if (!klass->interface_id)
10675 klass->interface_id = mono_get_unique_iid (klass);
10676 mono_loader_unlock ();
10677 }
10678
10679 /*
10680 * mono_class_setup_interfaces:
10681 *
10682 * Initialize klass->interfaces/interfaces_count.
10683 * LOCKING: Acquires the loader lock.
10684 * This function can fail the type.
10685 */
10686 void
mono_class_setup_interfaces(MonoClass * klass,MonoError * error)10687 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
10688 {
10689 int i, interface_count;
10690 MonoClass **interfaces;
10691
10692 error_init (error);
10693
10694 if (klass->interfaces_inited)
10695 return;
10696
10697 if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY) {
10698 MonoType *args [1];
10699
10700 /* IList and IReadOnlyList -> 2x if enum*/
10701 interface_count = klass->element_class->enumtype ? 4 : 2;
10702 interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
10703
10704 args [0] = &klass->element_class->byval_arg;
10705 interfaces [0] = mono_class_bind_generic_parameters (
10706 mono_defaults.generic_ilist_class, 1, args, FALSE);
10707 interfaces [1] = mono_class_bind_generic_parameters (
10708 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
10709 if (klass->element_class->enumtype) {
10710 args [0] = mono_class_enum_basetype (klass->element_class);
10711 interfaces [2] = mono_class_bind_generic_parameters (
10712 mono_defaults.generic_ilist_class, 1, args, FALSE);
10713 interfaces [3] = mono_class_bind_generic_parameters (
10714 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
10715 }
10716 } else if (mono_class_is_ginst (klass)) {
10717 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
10718
10719 mono_class_setup_interfaces (gklass, error);
10720 if (!mono_error_ok (error)) {
10721 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
10722 return;
10723 }
10724
10725 interface_count = gklass->interface_count;
10726 interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
10727 for (i = 0; i < interface_count; i++) {
10728 interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
10729 if (!mono_error_ok (error)) {
10730 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
10731 return;
10732 }
10733 }
10734 } else {
10735 interface_count = 0;
10736 interfaces = NULL;
10737 }
10738
10739 mono_loader_lock ();
10740 if (!klass->interfaces_inited) {
10741 klass->interface_count = interface_count;
10742 klass->interfaces = interfaces;
10743
10744 mono_memory_barrier ();
10745
10746 klass->interfaces_inited = TRUE;
10747 }
10748 mono_loader_unlock ();
10749 }
10750
10751 static void
mono_field_resolve_type(MonoClassField * field,MonoError * error)10752 mono_field_resolve_type (MonoClassField *field, MonoError *error)
10753 {
10754 MonoClass *klass = field->parent;
10755 MonoImage *image = klass->image;
10756 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
10757 MonoType *ftype;
10758 int field_idx = field - klass->fields;
10759
10760 error_init (error);
10761
10762 if (gtd) {
10763 MonoClassField *gfield = >d->fields [field_idx];
10764 MonoType *gtype = mono_field_get_type_checked (gfield, error);
10765 if (!mono_error_ok (error)) {
10766 char *full_name = mono_type_get_full_name (gtd);
10767 mono_class_set_type_load_failure (klass, "Could not load generic type of field '%s:%s' (%d) due to: %s", full_name, gfield->name, field_idx, mono_error_get_message (error));
10768 g_free (full_name);
10769 }
10770
10771 ftype = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
10772 if (!mono_error_ok (error)) {
10773 char *full_name = mono_type_get_full_name (klass);
10774 mono_class_set_type_load_failure (klass, "Could not load instantiated type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
10775 g_free (full_name);
10776 }
10777 } else {
10778 const char *sig;
10779 guint32 cols [MONO_FIELD_SIZE];
10780 MonoGenericContainer *container = NULL;
10781 int idx = mono_class_get_first_field_idx (klass) + field_idx;
10782
10783 /*FIXME, in theory we do not lazy load SRE fields*/
10784 g_assert (!image_is_dynamic (image));
10785
10786 if (mono_class_is_gtd (klass)) {
10787 container = mono_class_get_generic_container (klass);
10788 } else if (gtd) {
10789 container = mono_class_get_generic_container (gtd);
10790 g_assert (container);
10791 }
10792
10793 /* first_field_idx and idx points into the fieldptr table */
10794 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
10795
10796 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) {
10797 char *full_name = mono_type_get_full_name (klass);
10798 mono_error_set_type_load_class (error, klass, "Could not verify field '%s:%s' signature", full_name, field->name);;
10799 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
10800 g_free (full_name);
10801 return;
10802 }
10803
10804 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
10805
10806 mono_metadata_decode_value (sig, &sig);
10807 /* FIELD signature == 0x06 */
10808 g_assert (*sig == 0x06);
10809
10810 ftype = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
10811 if (!ftype) {
10812 char *full_name = mono_type_get_full_name (klass);
10813 mono_class_set_type_load_failure (klass, "Could not load type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
10814 g_free (full_name);
10815 }
10816 }
10817 mono_memory_barrier ();
10818 field->type = ftype;
10819 }
10820
10821 static guint32
mono_field_resolve_flags(MonoClassField * field)10822 mono_field_resolve_flags (MonoClassField *field)
10823 {
10824 MonoClass *klass = field->parent;
10825 MonoImage *image = klass->image;
10826 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
10827 int field_idx = field - klass->fields;
10828
10829 if (gtd) {
10830 MonoClassField *gfield = >d->fields [field_idx];
10831 return mono_field_get_flags (gfield);
10832 } else {
10833 int idx = mono_class_get_first_field_idx (klass) + field_idx;
10834
10835 /*FIXME, in theory we do not lazy load SRE fields*/
10836 g_assert (!image_is_dynamic (image));
10837
10838 return mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_FLAGS);
10839 }
10840 }
10841
10842 /**
10843 * mono_class_get_fields_lazy:
10844 * \param klass the MonoClass to act on
10845 *
10846 * This routine is an iterator routine for retrieving the fields in a class.
10847 * Only minimal information about fields are loaded. Accessors must be used
10848 * for all MonoClassField returned.
10849 *
10850 * You must pass a gpointer that points to zero and is treated as an opaque handle to
10851 * iterate over all of the elements. When no more values are
10852 * available, the return value is NULL.
10853 *
10854 * \returns a \c MonoClassField* on each iteration, or NULL when no more fields are available.
10855 */
10856 MonoClassField*
mono_class_get_fields_lazy(MonoClass * klass,gpointer * iter)10857 mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
10858 {
10859 MonoClassField* field;
10860 if (!iter)
10861 return NULL;
10862 if (!*iter) {
10863 mono_class_setup_basic_field_info (klass);
10864 if (!klass->fields)
10865 return NULL;
10866 /* start from the first */
10867 if (mono_class_get_field_count (klass)) {
10868 *iter = &klass->fields [0];
10869 return (MonoClassField *)*iter;
10870 } else {
10871 /* no fields */
10872 return NULL;
10873 }
10874 }
10875 field = (MonoClassField *)*iter;
10876 field++;
10877 if (field < &klass->fields [mono_class_get_field_count (klass)]) {
10878 *iter = field;
10879 return (MonoClassField *)*iter;
10880 }
10881 return NULL;
10882 }
10883
10884 char*
mono_class_full_name(MonoClass * klass)10885 mono_class_full_name (MonoClass *klass)
10886 {
10887 return mono_type_full_name (&klass->byval_arg);
10888 }
10889
10890 /* Declare all shared lazy type lookup functions */
10891 GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, "System.Runtime.InteropServices", "SafeHandle")
10892
10893 /**
10894 * mono_method_get_base_method:
10895 * \param method a method
10896 * \param definition if true, get the definition
10897 * \param error set on failure
10898 *
10899 * Given a virtual method associated with a subclass, return the corresponding
10900 * method from an ancestor. If \p definition is FALSE, returns the method in the
10901 * superclass of the given method. If \p definition is TRUE, return the method
10902 * in the ancestor class where it was first declared. The type arguments will
10903 * be inflated in the ancestor classes. If the method is not associated with a
10904 * class, or isn't virtual, returns the method itself. On failure returns NULL
10905 * and sets \p error.
10906 */
10907 MonoMethod*
mono_method_get_base_method(MonoMethod * method,gboolean definition,MonoError * error)10908 mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error)
10909 {
10910 MonoClass *klass, *parent;
10911 MonoGenericContext *generic_inst = NULL;
10912 MonoMethod *result = NULL;
10913 int slot;
10914
10915 if (method->klass == NULL)
10916 return method;
10917
10918 if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
10919 MONO_CLASS_IS_INTERFACE (method->klass) ||
10920 method->flags & METHOD_ATTRIBUTE_NEW_SLOT)
10921 return method;
10922
10923 slot = mono_method_get_vtable_slot (method);
10924 if (slot == -1)
10925 return method;
10926
10927 klass = method->klass;
10928 if (mono_class_is_ginst (klass)) {
10929 generic_inst = mono_class_get_context (klass);
10930 klass = mono_class_get_generic_class (klass)->container_class;
10931 }
10932
10933 retry:
10934 if (definition) {
10935 /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */
10936 for (parent = klass->parent; parent != NULL; parent = parent->parent) {
10937 /* on entry, klass is either a plain old non-generic class and generic_inst == NULL
10938 or klass is the generic container class and generic_inst is the instantiation.
10939
10940 when we go to the parent, if the parent is an open constructed type, we need to
10941 replace the type parameters by the definitions from the generic_inst, and then take it
10942 apart again into the klass and the generic_inst.
10943
10944 For cases like this:
10945 class C<T> : B<T, int> {
10946 public override void Foo () { ... }
10947 }
10948 class B<U,V> : A<HashMap<U,V>> {
10949 public override void Foo () { ... }
10950 }
10951 class A<X> {
10952 public virtual void Foo () { ... }
10953 }
10954
10955 if at each iteration the parent isn't open, we can skip inflating it. if at some
10956 iteration the parent isn't generic (after possible inflation), we set generic_inst to
10957 NULL;
10958 */
10959 MonoGenericContext *parent_inst = NULL;
10960 if (mono_class_is_open_constructed_type (mono_class_get_type (parent))) {
10961 parent = mono_class_inflate_generic_class_checked (parent, generic_inst, error);
10962 return_val_if_nok (error, NULL);
10963 }
10964 if (mono_class_is_ginst (parent)) {
10965 parent_inst = mono_class_get_context (parent);
10966 parent = mono_class_get_generic_class (parent)->container_class;
10967 }
10968
10969 mono_class_setup_vtable (parent);
10970 if (parent->vtable_size <= slot)
10971 break;
10972 klass = parent;
10973 generic_inst = parent_inst;
10974 }
10975 } else {
10976 klass = klass->parent;
10977 if (!klass)
10978 return method;
10979 if (mono_class_is_open_constructed_type (mono_class_get_type (klass))) {
10980 klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
10981 return_val_if_nok (error, NULL);
10982
10983 generic_inst = NULL;
10984 }
10985 if (mono_class_is_ginst (klass)) {
10986 generic_inst = mono_class_get_context (klass);
10987 klass = mono_class_get_generic_class (klass)->container_class;
10988 }
10989
10990 }
10991
10992 if (generic_inst) {
10993 klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
10994 return_val_if_nok (error, NULL);
10995 }
10996
10997 if (klass == method->klass)
10998 return method;
10999
11000 /*This is possible if definition == FALSE.
11001 * Do it here to be really sure we don't read invalid memory.
11002 */
11003 if (slot >= klass->vtable_size)
11004 return method;
11005
11006 mono_class_setup_vtable (klass);
11007
11008 result = klass->vtable [slot];
11009 if (result == NULL) {
11010 /* It is an abstract method */
11011 gboolean found = FALSE;
11012 gpointer iter = NULL;
11013 while ((result = mono_class_get_methods (klass, &iter))) {
11014 if (result->slot == slot) {
11015 found = TRUE;
11016 break;
11017 }
11018 }
11019 /* found might be FALSE if we looked in an abstract class
11020 * that doesn't override an abstract method of its
11021 * parent:
11022 * abstract class Base {
11023 * public abstract void Foo ();
11024 * }
11025 * abstract class Derived : Base { }
11026 * class Child : Derived {
11027 * public override void Foo () { }
11028 * }
11029 *
11030 * if m was Child.Foo and we ask for the base method,
11031 * then we get here with klass == Derived and found == FALSE
11032 */
11033 /* but it shouldn't be the case that if we're looking
11034 * for the definition and didn't find a result; the
11035 * loop above should've taken us as far as we could
11036 * go! */
11037 g_assert (!(definition && !found));
11038 if (!found)
11039 goto retry;
11040 }
11041
11042 g_assert (result != NULL);
11043 return result;
11044 }
11045
11046
11047 static gboolean
class_kind_may_contain_generic_instances(MonoTypeKind kind)11048 class_kind_may_contain_generic_instances (MonoTypeKind kind)
11049 {
11050 /* classes of type generic inst may contain generic arguments from other images,
11051 * as well as arrays and pointers whose element types (recursively) may be a generic inst */
11052 return (kind == MONO_CLASS_GINST || kind == MONO_CLASS_ARRAY || kind == MONO_CLASS_POINTER);
11053 }
11054