2 * class.c: Class management for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
7 * (C) 2001 Ximian, Inc.
9 * Possible Optimizations:
10 * in mono_class_create, do not allocate the class right away,
11 * but wait until you know the size of the FieldMap, so that
12 * the class embeds directly the FieldMap after the vtable.
19 #include <mono/metadata/image.h>
20 #include <mono/metadata/cil-coff.h>
21 #include <mono/metadata/metadata.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/metadata/class.h>
25 #include <mono/metadata/object.h>
27 #define CSIZE(x) (sizeof (x) / 4)
30 mono_class_create_from_typeref (MonoImage *image, guint32 type_token)
32 guint32 cols [MONO_TYPEREF_SIZE];
33 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
35 const char *name, *nspace;
38 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
39 g_assert ((cols [MONO_TYPEREF_SCOPE] & 0x3) == 2);
40 idx = cols [MONO_TYPEREF_SCOPE] >> 2;
42 if (!image->references || !image->references [idx-1]) {
44 * detected a reference to mscorlib, we simply return a reference to a dummy
45 * until we have a better solution.
47 res = mono_class_from_name (image, "System", "MonoDummy");
48 /* prevent method loading */
50 /* some storage if the type is used - very ugly hack */
51 res->instance_size = 2*sizeof (gpointer);
55 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
56 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
58 /* load referenced assembly */
59 image = image->references [idx-1]->image;
61 return mono_class_from_name (image, nspace, name);
65 * class_compute_field_layout:
66 * @m: pointer to the metadata.
67 * @class: The class to initialize
69 * Initializes the class->fields.
71 * Currently we only support AUTO_LAYOUT, and do not even try to do
72 * a good job at it. This is temporary to get the code for Paolo.
75 class_compute_field_layout (MonoClass *class)
77 MonoImage *m = class->image;
78 const int top = class->field.count;
79 guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
80 MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD];
84 * Fetch all the field information.
86 for (i = 0; i < top; i++){
89 int idx = class->field.first + i;
91 mono_metadata_decode_row (t, idx, cols, CSIZE (cols));
92 sig = mono_metadata_blob_heap (m, cols [2]);
93 mono_metadata_decode_value (sig, &sig);
94 /* FIELD signature == 0x06 */
95 g_assert (*sig == 0x06);
96 class->fields [i].type = mono_metadata_parse_field_type (
97 m, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
100 * Compute field layout and total size.
103 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
104 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
105 for (i = 0; i < top; i++){
108 size = mono_type_size (class->fields [i].type, &align);
109 if (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC) {
110 class->fields [i].offset = class->class_size;
111 class->class_size += (class->class_size % align);
112 class->class_size += size;
114 class->fields [i].offset = class->instance_size;
115 class->instance_size += (class->instance_size % align);
116 class->instance_size += size;
120 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
121 for (i = 0; i < top; i++){
124 int idx = class->field.first + i;
126 t = &m->tables [MONO_TABLE_FIELDLAYOUT];
128 for (j = 0; j < t->rows; j++) {
130 mono_metadata_decode_row (t, j, cols, CSIZE (cols));
131 if (cols [1] == idx) {
132 g_warning ("TODO: Explicit layout not supported yet");
136 size = mono_type_size (class->fields [i].type, &align);
137 if (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC) {
138 class->fields [i].offset = class->class_size;
139 class->class_size += (class->class_size % align);
140 class->class_size += size;
142 class->fields [i].offset = class->instance_size;
143 class->instance_size += (class->instance_size % align);
144 class->instance_size += size;
152 mono_class_metadata_init (MonoClass *class)
156 if (class->metadata_inited)
160 if (!class->parent->metadata_inited)
161 mono_class_metadata_init (class->parent);
162 class->instance_size = class->parent->instance_size;
163 class->class_size = class->parent->class_size;
166 class->metadata_inited = 1;
169 * Computes the size used by the fields, and their locations
171 if (class->field.count > 0){
172 class->fields = g_new (MonoClassField, class->field.count);
173 class_compute_field_layout (class);
176 if (!class->method.count)
179 class->methods = g_new (MonoMethod*, class->method.count);
180 for (i = class->method.first; i < class->method.last; ++i)
181 class->methods [i - class->method.first] =
182 mono_get_method (class->image,
183 MONO_TOKEN_METHOD_DEF | (i + 1),
188 * @image: context where the image is created
189 * @type_token: typedef token
192 mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
194 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
196 guint32 cols [MONO_TYPEDEF_SIZE], parent_token;
197 guint tidx = mono_metadata_token_index (type_token);
198 const char *name, *nspace;
200 g_assert (mono_metadata_token_table (type_token) == MONO_TABLE_TYPEDEF);
202 class = g_malloc0 (sizeof (MonoClass));
204 class->this_arg.byref = 1;
205 class->this_arg.data.klass = class;
206 class->this_arg.type = MONO_TYPE_CLASS;
208 mono_metadata_decode_row (tt, tidx-1, cols, CSIZE (cols));
209 class->name = name = mono_metadata_string_heap (image, cols[1]);
210 class->name_space = nspace = mono_metadata_string_heap (image, cols[2]);
212 class->image = image;
213 class->type_token = type_token;
214 class->flags = cols [0];
216 /*g_print ("Init class %s\n", name);*/
218 /* if root of the hierarchy */
219 if (!strcmp (nspace, "System") && !strcmp (name, "Object")) {
220 class->parent = NULL;
221 class->instance_size = sizeof (MonoObject);
222 } else if (!(cols [0] & TYPE_ATTRIBUTE_INTERFACE)) {
223 parent_token = mono_metadata_token_from_dor (cols [3]);
224 class->parent = mono_class_get (image, parent_token);
225 class->valuetype = class->parent->valuetype;
226 class->enumtype = class->parent->enumtype;
229 if (!strcmp (nspace, "System")) {
230 if (!strcmp (name, "ValueType")) {
231 class->valuetype = 1;
232 } else if (!strcmp (name, "Enum")) {
233 class->valuetype = 1;
237 if (class->valuetype)
238 class->this_arg.type = MONO_TYPE_VALUETYPE;
241 * Compute the field and method lists
243 class->field.first = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
244 class->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
246 if (tt->rows > tidx){
247 guint32 cols_next [MONO_TYPEDEF_SIZE];
249 mono_metadata_decode_row (tt, tidx, cols_next, CSIZE (cols_next));
250 class->field.last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
251 class->method.last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
253 class->field.last = image->tables [MONO_TABLE_FIELD].rows;
254 class->method.last = image->tables [MONO_TABLE_METHOD].rows;
257 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
258 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
259 class->field.count = class->field.last - class->field.first;
261 class->field.count = 0;
263 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
264 class->method.count = class->method.last - class->method.first;
266 class->method.count = 0;
268 /* reserve space to store vector pointer in arrays */
269 if (!strcmp (nspace, "System") && !strcmp (name, "Array")) {
270 class->instance_size += 2 * sizeof (gpointer);
271 g_assert (class->field.count == 0);
274 class->interfaces = mono_metadata_interfaces_from_typedef (image, type_token);
279 mono_class_from_mono_type (MonoType *type)
281 switch (type->type) {
282 case MONO_TYPE_OBJECT:
283 return mono_defaults.object_class;
285 return mono_defaults.void_class;
286 case MONO_TYPE_BOOLEAN:
287 return mono_defaults.boolean_class;
289 return mono_defaults.char_class;
291 return mono_defaults.byte_class;
293 return mono_defaults.sbyte_class;
295 return mono_defaults.int16_class;
297 return mono_defaults.uint16_class;
299 return mono_defaults.int32_class;
301 return mono_defaults.uint32_class;
303 return mono_defaults.int_class;
305 return mono_defaults.uint_class;
307 return mono_defaults.int64_class;
309 return mono_defaults.uint64_class;
311 return mono_defaults.single_class;
313 return mono_defaults.double_class;
314 case MONO_TYPE_STRING:
315 return mono_defaults.string_class;
316 case MONO_TYPE_ARRAY:
317 return mono_defaults.array_class;
318 case MONO_TYPE_SZARRAY:
320 /* Not really sure about these. */
321 return mono_class_from_mono_type (type->data.type);
322 case MONO_TYPE_CLASS:
323 case MONO_TYPE_VALUETYPE:
324 return type->data.klass;
326 g_warning ("implement me %02x\n", type->type);
327 g_assert_not_reached ();
334 * @image: context where the image is created
335 * @type_spec: typespec token
336 * @at: an optional pointer to return the array type
339 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec)
341 guint32 idx = mono_metadata_token_index (type_spec);
343 guint32 cols [MONO_TYPESPEC_SIZE];
347 MonoClass *class, *eclass;
349 t = &image->tables [MONO_TABLE_TYPESPEC];
351 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE);
352 ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
353 len = mono_metadata_decode_value (ptr, &ptr);
354 type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
356 switch (type->type) {
357 case MONO_TYPE_ARRAY:
358 eclass = mono_class_from_mono_type (type->data.array->type);
359 class = mono_array_class_get (eclass, type->data.array->rank);
361 case MONO_TYPE_SZARRAY:
362 eclass = mono_class_from_mono_type (type->data.type);
363 class = mono_array_class_get (eclass, 1);
366 g_warning ("implement me: %08x", type->type);
367 g_assert_not_reached ();
370 mono_metadata_free_type (type);
376 * mono_array_class_get:
377 * @eclass: element type class
378 * @rank: the dimension of the array class
380 * Returns: a class object describing the array with element type @etype and
384 mono_array_class_get (MonoClass *eclass, guint32 rank)
388 static MonoClass *parent = NULL;
389 MonoArrayClass *aclass;
392 g_assert (rank <= 255);
395 parent = mono_defaults.array_class;
397 image = eclass->image;
399 g_assert (!eclass->type_token ||
400 mono_metadata_token_table (eclass->type_token) == MONO_TABLE_TYPEDEF);
402 key = ((rank & 0xff) << 24) | (eclass->type_token & 0xffffff);
403 if ((class = g_hash_table_lookup (image->array_cache, GUINT_TO_POINTER (key))))
406 aclass = g_new0 (MonoArrayClass, 1);
407 class = (MonoClass *)aclass;
409 class->image = image;
410 class->name_space = "System";
411 class->name = "Array";
412 class->type_token = 0;
413 class->flags = TYPE_ATTRIBUTE_CLASS;
414 class->parent = parent;
415 class->instance_size = mono_class_instance_size (class->parent);
416 class->class_size = 0;
419 aclass->element_class = eclass;
421 g_hash_table_insert (image->array_cache, GUINT_TO_POINTER (key), class);
426 * mono_class_instance_size:
429 * Returns: the size of an object instance
432 mono_class_instance_size (MonoClass *klass)
435 if (!klass->metadata_inited)
436 mono_class_metadata_init (klass);
438 return klass->instance_size;
442 * mono_class_value_size:
445 * This function is used for value types, and return the
446 * space and the alignment to store that kind of value object.
448 * Returns: the size of a value of kind @klass
451 mono_class_value_size (MonoClass *klass, guint32 *align)
455 /* fixme: check disable, because we still have external revereces to
456 * mscorlib and Dummy Objects
458 //g_assert (klass->valuetype);
460 size = mono_class_instance_size (klass) - sizeof (MonoObject);
473 * mono_class_data_size:
476 * Returns: the size of the static class data
479 mono_class_data_size (MonoClass *klass)
482 if (!klass->metadata_inited)
483 mono_class_metadata_init (klass);
485 return klass->class_size;
489 * Auxiliary routine to mono_class_get_field
491 * Takes a field index instead of a field token.
493 static MonoClassField *
494 mono_class_get_field_idx (MonoClass *class, int idx)
496 if (class->field.count){
497 if ((idx >= class->field.first) && (idx < class->field.last)){
498 return &class->fields [idx - class->field.first];
505 return mono_class_get_field_idx (class->parent, idx);
509 * mono_class_get_field:
510 * @class: the class to lookup the field.
511 * @field_token: the field token
513 * Returns: A MonoClassField representing the type and offset of
514 * the field, or a NULL value if the field does not belong to this
518 mono_class_get_field (MonoClass *class, guint32 field_token)
520 int idx = mono_metadata_token_index (field_token);
522 if (mono_metadata_token_code (field_token) == MONO_TOKEN_MEMBER_REF)
523 g_error ("Unsupported Field Token is a MemberRef, implement me");
525 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
527 return mono_class_get_field_idx (class, idx - 1);
532 * @image: the image where the class resides
533 * @type_token: the token for the class
534 * @at: an optional pointer to return the array element type
536 * Returns: the MonoClass that represents @type_token in @image
539 mono_class_get (MonoImage *image, guint32 type_token)
543 switch (type_token & 0xff000000){
544 case MONO_TOKEN_TYPE_DEF:
545 if ((class = g_hash_table_lookup (image->class_cache,
546 GUINT_TO_POINTER (type_token))))
548 class = mono_class_create_from_typedef (image, type_token);
550 case MONO_TOKEN_TYPE_REF:
551 return mono_class_create_from_typeref (image, type_token);
552 case MONO_TOKEN_TYPE_SPEC:
553 if ((class = g_hash_table_lookup (image->class_cache,
554 GUINT_TO_POINTER (type_token))))
557 class = mono_class_create_from_typespec (image, type_token);
560 g_assert_not_reached ();
563 g_hash_table_insert (image->class_cache, GUINT_TO_POINTER (type_token), class);
569 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
571 GHashTable *nspace_table;
574 nspace_table = g_hash_table_lookup (image->name_cache, name_space);
577 token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
580 g_error ("token not found for %s.%s in image %s", name_space, name, image->name);
582 token = MONO_TOKEN_TYPE_DEF | token;
584 return mono_class_get (image, token);
588 * mono_array_element_size:
589 * @ac: pointer to a #MonoArrayClass
591 * Returns: the size of single array element.
594 mono_array_element_size (MonoArrayClass *ac)
598 esize = mono_class_instance_size (ac->element_class);
600 if (ac->element_class->valuetype)
601 esize -= sizeof (MonoObject);