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/cli/cli.h>
25 #include <mono/cli/class.h>
26 #include <mono/cli/types.h>
27 #include <mono/cli/object.h>
29 #define CSIZE(x) (sizeof (x) / 4)
32 typedef_from_typeref (MonoImage *image, guint32 type_token, MonoImage **rimage, guint32 *index)
34 guint32 cols[MONO_TYPEDEF_SIZE];
35 MonoMetadata *m = &image->metadata;
36 MonoTableInfo *t = &m->tables[MONO_TABLE_TYPEREF];
38 const char *name, *nspace;
40 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, 3);
41 g_assert ((cols [0] & 0x3) == 2);
43 name = mono_metadata_string_heap (m, cols [1]);
44 nspace = mono_metadata_string_heap (m, cols [2]);
45 /* load referenced assembly */
46 image = image->references [idx-1]->image;
48 t = &m->tables [MONO_TABLE_TYPEDEF];
49 /* dumb search for now */
50 for (i=0; i < t->rows; ++i) {
51 mono_metadata_decode_row (t, i, cols, MONO_TYPEDEF_SIZE);
53 if (!strcmp (name, mono_metadata_string_heap (m, cols [1])) &&
54 !strcmp (nspace, mono_metadata_string_heap (m, cols [2]))) {
56 *index = MONO_TOKEN_TYPE_DEF | (i + 1);
60 g_assert_not_reached ();
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 (MonoMetadata *m, MonoClass *class)
77 const int top = class->field.count;
78 guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
79 MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD];
83 * Fetch all the field information.
85 for (i = 0; i < top; i++){
88 int idx = class->field.first + i;
90 mono_metadata_decode_row (t, idx, cols, CSIZE (cols));
91 sig = mono_metadata_blob_heap (m, cols [2]);
92 mono_metadata_decode_value (sig, &sig);
93 /* FIELD signature == 0x06 */
94 g_assert (*sig == 0x06);
95 class->fields [i].type = mono_metadata_parse_field_type (
97 class->fields [i].flags = cols [0];
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->type, &align);
109 if (class->fields [i].flags & 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->type, &align);
137 if (class->fields [i].flags & 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 * @image: context where the image is created
153 * @type_token: typedef token
156 mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
158 MonoMetadata *m = &image->metadata;
159 MonoTableInfo *tt = &m->tables [MONO_TABLE_TYPEDEF];
160 MonoClass stack_class;
161 MonoClass *class = &stack_class;
162 guint32 cols [MONO_TYPEDEF_SIZE], parent_token;
163 guint tidx = mono_metadata_token_index (type_token);
164 const char *name, *nspace;
166 g_assert (mono_metadata_token_table (type_token) == MONO_TABLE_TYPEDEF);
168 memset (class, 0, sizeof (MonoClass));
170 mono_metadata_decode_row (tt, tidx-1, cols, CSIZE (cols));
171 name = mono_metadata_string_heap (m, cols[1]);
172 nspace = mono_metadata_string_heap (m, cols[2]);
173 /*g_print ("Init class %s\n", name);*/
175 /* if root of the hierarchy */
176 if (!strcmp (nspace, "System") && !strcmp (name, "Object")) {
177 class->instance_size = sizeof (MonoObject);
178 class->parent = NULL;
180 parent_token = mono_metadata_token_from_dor (cols [3]);
181 class->parent = mono_class_get (image, parent_token);
182 class->instance_size = class->parent->instance_size;
183 class->valuetype = class->parent->valuetype;
185 if (!strcmp (nspace, "System") && !strcmp (name, "ValueType"))
186 class->valuetype = 1;
188 g_assert (class->instance_size);
189 class->image = image;
190 class->type_token = type_token;
191 class->flags = cols [0];
192 class->class_size = sizeof (MonoClass);
195 * Compute the field and method lists
197 class->field.first = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
198 class->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
200 if (tt->rows > tidx){
201 guint32 cols_next [MONO_TYPEDEF_SIZE];
203 mono_metadata_decode_row (tt, tidx, cols_next, CSIZE (cols_next));
204 class->field.last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
205 class->method.last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
207 class->field.last = m->tables [MONO_TABLE_FIELD].rows;
208 class->method.last = m->tables [MONO_TABLE_METHOD].rows;
211 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
212 cols [MONO_TYPEDEF_FIELD_LIST] <= m->tables [MONO_TABLE_FIELD].rows)
213 class->field.count = class->field.last - class->field.first;
215 class->field.count = 0;
217 if (cols [MONO_TYPEDEF_METHOD_LIST] <= m->tables [MONO_TABLE_METHOD].rows)
218 class->method.count = class->method.last - class->method.first;
220 class->method.count = 0;
223 * Computes the size used by the fields, and their locations
225 if (class->field.count > 0){
226 class->fields = g_new (MonoClassField, class->field.count);
227 class_compute_field_layout (m, class);
230 /* reserve space to store vector pointer in arrays */
231 if (!strcmp (nspace, "System") && !strcmp (name, "Array")) {
232 class->instance_size += 2 * sizeof (gpointer);
233 g_assert (class->field.count == 0);
234 g_assert (class->instance_size == sizeof (MonoArrayObject));
237 class = g_malloc0 (class->class_size);
238 *class = stack_class;
243 mono_type_to_tydedef (MonoImage *image, MonoType *type, MonoImage **rimage)
245 MonoImage *corlib, *res;
248 res = corlib = mono_get_corlib ();
250 switch (type->type) {
251 case MONO_TYPE_BOOLEAN:
252 etype = mono_typedef_from_name (corlib, "Boolean", "System", NULL);
255 etype = mono_typedef_from_name (corlib, "Char", "System", NULL);
258 etype = mono_typedef_from_name (corlib, "Byte", "System", NULL);
261 etype = mono_typedef_from_name (corlib, "Int16", "System", NULL);
264 etype = mono_typedef_from_name (corlib, "UInt16", "System", NULL);
267 etype = mono_typedef_from_name (corlib, "Int32", "System", NULL);
270 etype = mono_typedef_from_name (corlib, "UInt32", "System", NULL);
273 etype = mono_typedef_from_name (corlib, "Int64", "System", NULL);
276 etype = mono_typedef_from_name (corlib, "UInt64", "System", NULL);
279 etype = mono_typedef_from_name (corlib, "Double", "System", NULL);
281 case MONO_TYPE_STRING:
282 etype = mono_typedef_from_name (corlib, "String", "System", NULL);
284 case MONO_TYPE_CLASS:
285 etype = type->data.token;
289 g_warning ("implement me %08x\n", type->type);
290 g_assert_not_reached ();
298 * @image: context where the image is created
299 * @type_spec: typespec token
300 * @at: an optional pointer to return the array type
303 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec)
305 MonoMetadata *m = &image->metadata;
306 guint32 idx = mono_metadata_token_index (type_spec);
308 guint32 cols [MONO_TYPESPEC_SIZE];
315 t = &m->tables [MONO_TABLE_TYPESPEC];
317 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE);
318 ptr = mono_metadata_blob_heap (m, cols [MONO_TYPESPEC_SIGNATURE]);
319 len = mono_metadata_decode_value (ptr, &ptr);
320 type = mono_metadata_parse_type (m, ptr, &ptr);
322 switch (type->type) {
323 case MONO_TYPE_ARRAY:
324 etype = mono_type_to_tydedef (image, type->data.array->type, &rimage);
325 class = mono_array_class_get (rimage, etype, type->data.array->rank);
327 case MONO_TYPE_SZARRAY:
328 g_assert (!type->custom_mod);
329 etype = mono_type_to_tydedef (image, type->data.type, &rimage);
330 class = mono_array_class_get (rimage, etype, 1);
333 g_assert_not_reached ();
336 mono_metadata_free_type (type);
342 mono_array_class_get (MonoImage *image, guint32 etype, guint32 rank)
344 MonoClass *class, *eclass;
345 static MonoClass *parent = NULL;
346 MonoArrayClass *aclass;
349 g_assert (rank <= 255);
355 mono_get_array_class_info (&arr_token, &corlib);
356 parent = mono_class_get (corlib, arr_token);
357 g_assert (parent != NULL);
360 eclass = mono_class_get (image, etype);
361 g_assert (eclass != NULL);
363 image = eclass->image;
365 esize = eclass->instance_size;
367 g_assert (!eclass->type_token ||
368 mono_metadata_token_table (eclass->type_token) == MONO_TABLE_TYPEDEF);
370 key = ((rank & 0xff) << 24) | (eclass->type_token & 0xffffff);
371 if ((class = g_hash_table_lookup (image->array_cache, GUINT_TO_POINTER (key))))
374 if (eclass->valuetype)
375 esize -= sizeof (MonoObject);
377 aclass = g_new0 (MonoArrayClass, 1);
378 class = (MonoClass *)aclass;
380 class->image = image;
381 class->type_token = 0;
382 class->flags = TYPE_ATTRIBUTE_CLASS;
383 class->parent = parent;
384 class->instance_size = class->parent->instance_size;
385 class->class_size = sizeof (MonoArrayClass);
388 aclass->etype_token = eclass->type_token;
389 aclass->esize = esize;
391 g_hash_table_insert (image->array_cache, GUINT_TO_POINTER (key), class);
396 * Auxiliary routine to mono_class_get_field
398 * Takes a field index instead of a field token.
400 static MonoClassField *
401 mono_class_get_field_idx (MonoClass *class, int idx)
403 if (class->field.count){
404 if ((idx >= class->field.first) && (idx < class->field.last)){
405 return &class->fields [idx - class->field.first];
412 return mono_class_get_field_idx (class->parent, idx);
416 * mono_class_get_field:
417 * @class: the class to lookup the field.
418 * @field_token: the field token
420 * Returns: A MonoClassField representing the type and offset of
421 * the field, or a NULL value if the field does not belong to this
425 mono_class_get_field (MonoClass *class, guint32 field_token)
427 int idx = mono_metadata_token_index (field_token);
429 if (mono_metadata_token_code (field_token) == MONO_TOKEN_MEMBER_REF)
430 g_error ("Unsupported Field Token is a MemberRef, implement me");
432 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
434 return mono_class_get_field_idx (class, idx - 1);
439 * @image: the image where the class resides
440 * @type_token: the token for the class
441 * @at: an optional pointer to return the array element type
443 * Returns: the MonoClass that represents @type_token in @image
446 mono_class_get (MonoImage *image, guint32 type_token)
450 switch (type_token & 0xff000000){
451 case MONO_TOKEN_TYPE_DEF:
452 if ((class = g_hash_table_lookup (image->class_cache,
453 GUINT_TO_POINTER (type_token))))
456 class = mono_class_create_from_typedef (image, type_token);
459 case MONO_TOKEN_TYPE_REF: {
460 typedef_from_typeref (image, type_token, &image, &type_token);
461 return mono_class_get (image, type_token);
463 case MONO_TOKEN_TYPE_SPEC:
464 if ((class = g_hash_table_lookup (image->class_cache,
465 GUINT_TO_POINTER (type_token))))
468 class = mono_class_create_from_typespec (image, type_token);
471 g_assert_not_reached ();
474 g_hash_table_insert (image->class_cache, GUINT_TO_POINTER (type_token), class);