8253b5ecaaa49d8603c9888c2d2af78cc97c530b
[mono.git] / mono / metadata / class.c
1 /*
2  * class.c: Class management for the Mono runtime
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  *
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.
13  *
14  * 
15  */
16 #include <config.h>
17 #include <glib.h>
18 #include <stdio.h>
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/class.h>
25 #include <mono/cli/types.h>
26 #include <mono/cli/object.h>
27
28 #define CSIZE(x) (sizeof (x) / 4)
29
30 /*
31  * mono_field_type_size:
32  * @t: the type to return the size of
33  *
34  * Returns: the number of bytes required to hold an instance of this
35  * type in memory
36  */
37 int
38 mono_field_type_size (MonoFieldType *ft)
39 {
40         MonoType *t = ft->type;
41
42         switch (t->type){
43         case ELEMENT_TYPE_BOOLEAN:
44                 return sizeof (m_boolean);
45                 
46         case ELEMENT_TYPE_CHAR:
47                 return sizeof (m_char);
48                 
49         case ELEMENT_TYPE_I1:
50         case ELEMENT_TYPE_U1:
51                 return 1;
52                 
53         case ELEMENT_TYPE_I2:
54         case ELEMENT_TYPE_U2:
55                 return 2;
56                 
57         case ELEMENT_TYPE_I4:
58         case ELEMENT_TYPE_U4:
59         case ELEMENT_TYPE_R4:
60                 return 4;
61                 
62         case ELEMENT_TYPE_I8:
63         case ELEMENT_TYPE_U8:
64         case ELEMENT_TYPE_R8:
65                 return 8;
66                 
67         case ELEMENT_TYPE_I:
68                 return sizeof (m_i);
69                 
70         case ELEMENT_TYPE_U:
71                 return sizeof (m_u);
72                 
73         case ELEMENT_TYPE_STRING:
74                 return sizeof (m_string);
75                 
76         case ELEMENT_TYPE_OBJECT:
77                 return sizeof (m_object);
78                 
79         case ELEMENT_TYPE_VALUETYPE:
80                 g_error ("FIXME: Add computation of size for ELEMENT_TYPE_VALUETYPE");
81                 
82         case ELEMENT_TYPE_CLASS:
83                 g_error ("FIXME: Add computation of size for ELEMENT_TYPE_CLASS");
84                 break;
85                 
86         case ELEMENT_TYPE_SZARRAY:
87                 g_error ("FIXME: Add computation of size for ELEMENT_TYPE_SZARRAY");
88                 break;
89                 
90         case ELEMENT_TYPE_PTR:
91                 g_error ("FIXME: Add computation of size for ELEMENT_TYPE_PTR");
92                 break;
93                 
94         case ELEMENT_TYPE_FNPTR:
95                 g_error ("FIXME: Add computation of size for ELEMENT_TYPE_FNPTR");
96                 break;
97                 
98         case ELEMENT_TYPE_ARRAY:
99                 g_error ("FIXME: Add computation of size for ELEMENT_TYPE_ARRAY");
100                 break;
101         default:
102                 g_error ("type 0x%02x unknown", t->type);
103         }
104         return 0;
105 }
106
107 /** 
108  * class_compute_field_layout:
109  * @m: pointer to the metadata.
110  * @class: The class to initialize
111  *
112  * Initializes the class->fields.
113  *
114  * Currently we only support AUTO_LAYOUT, and do not even try to do
115  * a good job at it.  This is temporary to get the code for Paolo.
116  */
117 static void
118 class_compute_field_layout (metadata_t *m, MonoClass *class)
119 {
120         const int top = class->field.count;
121         guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
122         metadata_tableinfo_t *t = &m->tables [META_TABLE_FIELD];
123         int i;
124         
125         /*
126          * Fetch all the field information.
127          */
128         for (i = 0; i < top; i++){
129                 const char *sig;
130                 guint32 cols [3];
131                 int idx = class->field.first + i;
132                 
133                 mono_metadata_decode_row (t, idx, cols, CSIZE (cols));
134                 sig = mono_metadata_blob_heap (m, cols [2]);
135                 mono_metadata_decode_value (sig, &sig);
136
137                 /* FIELD signature == 0x06 */
138                 g_assert (*sig == 0x06);
139                 
140                 class->fields [i].type = mono_metadata_parse_field_type (
141                         m, sig, &sig);
142                 class->fields [i].flags = cols [0];
143         }
144
145         /*
146          * Compute field layout and total size.
147          */
148         switch (layout){
149         case TYPE_ATTRIBUTE_AUTO_LAYOUT:
150         case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
151                 for (i = 0; i < top; i++){
152                         int size;
153                         
154                         size = mono_field_type_size (class->fields [i].type);
155                         size += (size % 4);
156                         if (class->fields [i].flags & FIELD_ATTRIBUTE_STATIC) {
157                                 class->fields [i].offset = class->class_size;
158                                 class->class_size += size;
159                         } else {
160                                 class->fields [i].offset = class->instance_size;
161                                 class->instance_size += size;
162                         }
163                 }
164                 break;
165         case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
166                 g_error ("TODO: Explicit layout not supported yet");
167         }
168 }
169
170 /**
171  * @image: context where the image is created
172  * @tidx:  index of the type to create
173  */
174 static MonoClass *
175 mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
176 {
177         metadata_t *m = &image->metadata;
178         metadata_tableinfo_t *tt = &m->tables [META_TABLE_TYPEDEF];
179         MonoClass stack_class;
180         MonoClass *class = &stack_class;
181         guint32 cols [6], parent_token;
182         guint tidx = type_token & 0xffffff;
183         const char *name;
184         
185         mono_metadata_decode_row (tt, tidx-1, cols, CSIZE (cols));
186         name = mono_metadata_string_heap (m, cols[1]);
187         /*g_print ("Init class %s\n", name);*/
188
189         /*
190          * If root of the hierarchy
191          */
192         if (cols [3] == 0){
193                 class->instance_size = sizeof (MonoObject);
194                 class->parent = NULL;
195         } else {
196                 parent_token = mono_metadata_token_from_dor (cols [3]);
197                 class->parent = mono_class_get (image, parent_token);
198                 class->instance_size = class->parent->instance_size;
199         }
200         
201         class->image = image;
202         class->type_token = tidx;
203         class->flags = cols [0];
204         class->class_size = sizeof (MonoClass);
205         
206         /*
207          * Compute the field and method lists
208          */
209         class->field.first  = cols [4] - 1;
210         class->method.first = cols [5] - 1;
211
212         if (tt->rows > tidx + 1){
213                 guint32 cols_next [6];
214                 
215                 mono_metadata_decode_row (tt, tidx + 1, cols_next, CSIZE (cols_next));
216                 class->field.last  = cols_next [4] - 1;
217                 class->method.last = cols_next [5] - 1;
218         } else {
219                 class->field.last  = m->tables [META_TABLE_FIELD].rows;
220                 class->method.last = m->tables [META_TABLE_METHOD].rows;
221         }
222
223         if (cols [4] && cols [4] <= m->tables [META_TABLE_FIELD].rows)
224                 class->field.count = class->field.last - class->field.first;
225         else
226                 class->field.count = 0;
227
228         if (cols [5] <= m->tables [META_TABLE_METHOD].rows)
229                 class->method.count = class->method.last - class->method.first;
230         else
231                 class->method.count = 0;
232
233         /*
234          * Computes the size used by the fields, and their locations
235          */
236         if (class->field.count > 0){
237                 class->fields = g_new (MonoClassField, class->field.count);
238                 class_compute_field_layout (m, class);
239         }
240
241         class = g_malloc0 (class->class_size);
242         *class = stack_class;
243         return class;
244 }
245
246 /*
247  * Auxiliary routine to mono_class_get_field
248  *
249  * Takes a field index instead of a field token.
250  */
251 static MonoClassField *
252 mono_class_get_field_idx (MonoClass *class, int idx)
253 {
254         if (class->field.count){
255                 if ((idx >= class->field.first) && (idx < class->field.last)){
256                         return &class->fields [idx - class->field.first];
257                 }
258         }
259
260         if (!class->parent)
261                 return NULL;
262         
263         return mono_class_get_field_idx (class->parent, idx);
264 }
265
266 /**
267  * mono_class_get_field:
268  * @class: the class to lookup the field.
269  * @field_token: the field token
270  *
271  * Returns: A MonoClassField representing the type and offset of
272  * the field, or a NULL value if the field does not belong to this
273  * class.
274  */
275 MonoClassField *
276 mono_class_get_field (MonoClass *class, guint32 field_token)
277 {
278         int idx = mono_metadata_token_index (field_token);
279
280         if (mono_metadata_token_code (field_token) == TOKEN_TYPE_MEMBER_REF)
281                 g_error ("Unsupported Field Token is a MemberRef, implement me");
282
283         g_assert (mono_metadata_token_code (field_token) == TOKEN_TYPE_FIELD_DEF);
284
285         return mono_class_get_field_idx (class, idx - 1);
286 }
287
288 static void
289 typedef_from_typeref (MonoImage *image, guint32 type_token, MonoImage **rimage, guint32 *index)
290 {
291         guint32 cols[6];
292         metadata_t *m = &image->metadata;
293         metadata_tableinfo_t  *t = &m->tables[META_TABLE_TYPEREF];
294         guint32 idx, i;
295         const char *name, *nspace;
296         
297         mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, 3);
298         g_assert ((cols [0] & 0x3) == 2);
299         idx = cols [0] >> 2;
300         name = mono_metadata_string_heap (m, cols [1]);
301         nspace = mono_metadata_string_heap (m, cols [2]);
302         /* load referenced assembly */
303         image = image->references [idx-1]->image;
304         m = &image->metadata;
305         t = &m->tables [META_TABLE_TYPEDEF];
306         /* dumb search for now */
307         for (i=0; i < t->rows; ++i) {
308                 mono_metadata_decode_row (t, i, cols, 6);
309                 if (strcmp (name, mono_metadata_string_heap (m, cols [1])) == 0 
310                                 && strcmp (nspace, mono_metadata_string_heap (m, cols [2])) == 0) {
311                         *rimage = image;
312                         *index = i + 1;
313                         return;
314                 }
315         }
316         g_assert_not_reached ();
317         
318 }
319
320 /**
321  * mono_class_get:
322  * @image: the image where the class resides
323  * @type_token: the token for the class
324  *
325  * Returns: the MonoClass that represents @type_token in @image
326  */
327 MonoClass *
328 mono_class_get (MonoImage *image, guint32 type_token)
329 {
330         MonoClass *class;
331
332         if ((type_token & 0xff000000) == TOKEN_TYPE_TYPE_DEF 
333                                         && (class = g_hash_table_lookup (image->class_cache, GUINT_TO_POINTER (type_token))))
334                         return class;
335
336         switch (type_token & 0xff000000){
337         case TOKEN_TYPE_TYPE_DEF:
338                 class = mono_class_create_from_typedef (image, type_token);
339                 break;
340                 
341         case TOKEN_TYPE_TYPE_REF: {
342                 typedef_from_typeref (image, type_token, &image, &type_token);
343                 class = mono_class_create_from_typedef (image, type_token);
344                 break;
345         }
346         case TOKEN_TYPE_TYPE_SPEC:
347                 g_error ("Can not handle class creation of TypeSpecs yet");
348                 
349         default:
350                 g_assert_not_reached ();
351         }
352         
353         g_hash_table_insert (image->class_cache, GUINT_TO_POINTER (type_token), class);
354
355         return class;
356 }
357