Fri Jul 27 11:46:09 CEST 2001 Paolo Molaro <lupus@ximian.com>
[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 instance_size = sizeof (MonoObject);
124         int i;
125         
126         /*
127          * Fetch all the field information.
128          */
129         for (i = 0; i < top; i++){
130                 const char *sig;
131                 guint32 cols [3];
132                 int idx = class->field.first + i;
133                 
134                 mono_metadata_decode_row (t, idx, cols, CSIZE (cols));
135                 sig = mono_metadata_blob_heap (m, cols [2]);
136                 mono_metadata_decode_value (sig, &sig);
137
138                 /* FIELD signature == 0x06 */
139                 g_assert (*sig == 0x06);
140                 
141                 class->fields [i].type = mono_metadata_parse_field_type (
142                         m, sig, &sig);
143                 class->fields [i].flags = cols [0];
144         }
145
146         /*
147          * Compute field layout and total size.
148          */
149         switch (layout){
150         case TYPE_ATTRIBUTE_AUTO_LAYOUT:
151                 for (i = 0; i < top; i++){
152                         int size;
153                         
154                         class->fields [i].offset = instance_size;
155                         
156                         size = mono_field_type_size (class->fields [i].type);
157                         size += (size % 4);
158                         instance_size += size;
159                 }
160                 break;
161                 
162         case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
163                 for (i = 0; i < top; i++){
164                         int size;
165                         
166                         class->fields [i].offset = instance_size;
167                         
168                         size = mono_field_type_size (class->fields [i].type);
169                         size += (size % 4);
170                         instance_size += size;
171                 }
172                 break;
173                 
174         case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
175                 g_error ("TODO: Explicit layout not supported yet");
176         }
177 }
178
179 /**
180  * @image: context where the image is created
181  * @tidx:  index of the type to create
182  */
183 static MonoClass *
184 mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
185 {
186         metadata_t *m = &image->metadata;
187         metadata_tableinfo_t *tt = &m->tables [META_TABLE_TYPEDEF];
188         MonoClass *class;
189         guint32 cols [6], parent_token;
190         guint tidx = type_token & 0xffffff;
191         const char *name;
192         
193         mono_metadata_decode_row (tt, tidx-1, cols, CSIZE (cols));
194         name = mono_metadata_string_heap (m, cols[1]);
195         /*g_print ("Init class %s\n", name);*/
196
197         class = g_new0 (MonoClass, 1);
198
199         /*
200          * If root of the hierarchy
201          */
202         if (cols [3] == 0){
203                 class->instance_size = sizeof (MonoObject);
204                 class->parent = NULL;
205         } else {
206                 parent_token = mono_metadata_token_from_dor (cols [3]);
207                 class->parent = mono_class_get (image, parent_token);
208                 class->instance_size = class->parent->instance_size;
209         }
210         
211         class->image = image;
212         class->type_token = tidx;
213         class->flags = cols [0];
214         
215         /*
216          * Compute the field and method lists
217          */
218         class->field.first  = cols [4] - 1;
219         class->method.first = cols [5] - 1;
220
221         if (tt->rows > tidx + 1){
222                 guint32 cols_next [6];
223                 
224                 mono_metadata_decode_row (tt, tidx + 1, cols_next, CSIZE (cols_next));
225                 class->field.last  = cols_next [4] - 1;
226                 class->method.last = cols_next [5] - 1;
227         } else {
228                 class->field.last  = m->tables [META_TABLE_FIELD].rows;
229                 class->method.last = m->tables [META_TABLE_METHOD].rows;
230         }
231
232         if (cols [4] && cols [4] <= m->tables [META_TABLE_FIELD].rows)
233                 class->field.count = class->field.last - class->field.first;
234         else
235                 class->field.count = 0;
236
237         if (cols [5] <= m->tables [META_TABLE_METHOD].rows)
238                 class->method.count = class->method.last - class->method.first;
239         else
240                 class->method.count = 0;
241
242         /*
243          * Computes the size used by the fields, and their locations
244          */
245         if (class->field.count > 0){
246                 class->fields = g_new (MonoClassField, class->field.count);
247                 class_compute_field_layout (m, class);
248         }
249
250         return class;
251 }
252
253 /*
254  * Auxiliary routine to mono_class_get_field
255  *
256  * Takes a field index instead of a field token.
257  */
258 static MonoClassField *
259 mono_class_get_field_idx (MonoClass *class, int idx)
260 {
261         if (class->field.count){
262                 if ((idx >= class->field.first) && (idx < class->field.last)){
263                         return &class->fields [idx - class->field.first];
264                 }
265         }
266
267         if (!class->parent)
268                 return NULL;
269         
270         return mono_class_get_field_idx (class->parent, idx);
271 }
272
273 /**
274  * mono_class_get_field:
275  * @class: the class to lookup the field.
276  * @field_token: the field token
277  *
278  * Returns: A MonoClassField representing the type and offset of
279  * the field, or a NULL value if the field does not belong to this
280  * class.
281  */
282 MonoClassField *
283 mono_class_get_field (MonoClass *class, guint32 field_token)
284 {
285         int idx = mono_metadata_token_index (field_token);
286
287         if (mono_metadata_token_code (field_token) == TOKEN_TYPE_MEMBER_REF)
288                 g_error ("Unsupported Field Token is a MemberRef, implement me");
289
290         g_assert (mono_metadata_token_code (field_token) == TOKEN_TYPE_FIELD_DEF);
291
292         return mono_class_get_field_idx (class, idx - 1);
293 }
294
295 static void
296 typedef_from_typeref (MonoImage *image, guint32 type_token, MonoImage **rimage, guint32 *index)
297 {
298         guint32 cols[6];
299         metadata_t *m = &image->metadata;
300         metadata_tableinfo_t  *t = &m->tables[META_TABLE_TYPEREF];
301         guint32 idx, i;
302         const char *name, *nspace;
303         
304         mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, 3);
305         g_assert ((cols [0] & 0x3) == 2);
306         idx = cols [0] >> 2;
307         name = mono_metadata_string_heap (m, cols [1]);
308         nspace = mono_metadata_string_heap (m, cols [2]);
309         /* load referenced assembly */
310         image = image->references [idx-1]->image;
311         m = &image->metadata;
312         t = &m->tables [META_TABLE_TYPEDEF];
313         /* dumb search for now */
314         for (i=0; i < t->rows; ++i) {
315                 mono_metadata_decode_row (t, i, cols, 6);
316                 if (strcmp (name, mono_metadata_string_heap (m, cols [1])) == 0 
317                                 && strcmp (nspace, mono_metadata_string_heap (m, cols [2])) == 0) {
318                         *rimage = image;
319                         *index = i + 1;
320                         return;
321                 }
322         }
323         g_assert_not_reached ();
324         
325 }
326
327 /**
328  * mono_class_get:
329  * @image: the image where the class resides
330  * @type_token: the token for the class
331  *
332  * Returns: the MonoClass that represents @type_token in @image
333  */
334 MonoClass *
335 mono_class_get (MonoImage *image, guint32 type_token)
336 {
337         MonoClass *class;
338
339         if ((type_token & 0xff000000) == TOKEN_TYPE_TYPE_DEF 
340                                         && (class = g_hash_table_lookup (image->class_cache, GUINT_TO_POINTER (type_token))))
341                         return class;
342
343         switch (type_token & 0xff000000){
344         case TOKEN_TYPE_TYPE_DEF:
345                 class = mono_class_create_from_typedef (image, type_token);
346                 break;
347                 
348         case TOKEN_TYPE_TYPE_REF: {
349                 typedef_from_typeref (image, type_token, &image, &type_token);
350                 class = mono_class_create_from_typedef (image, type_token);
351                 break;
352         }
353         case TOKEN_TYPE_TYPE_SPEC:
354                 g_error ("Can not handle class creation of TypeSpecs yet");
355                 
356         default:
357                 g_assert_not_reached ();
358         }
359         
360         g_hash_table_insert (image->class_cache, GUINT_TO_POINTER (type_token), class);
361
362         return class;
363 }
364