Tue Jul 31 20:13:59 CEST 2001 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / loader.c
1 /*
2  * loader.c: Image Loader 
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Miguel de Icaza (miguel@ximian.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  *
10  * This file is used by the interpreter and the JIT engine to locate
11  * assemblies.  Used to load AssemblyRef and later to resolve various
12  * kinds of `Refs'.
13  *
14  * TODO:
15  *   This should keep track of the assembly versions that we are loading.
16  *
17  */
18 #include <config.h>
19 #include <glib.h>
20 #include <gmodule.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <mono/metadata/metadata.h>
24 #include <mono/metadata/image.h>
25 #include <mono/metadata/tokentype.h>
26 #include <mono/metadata/cil-coff.h>
27 #include <mono/metadata/tabledefs.h>
28 #include "cli.h"
29
30 static guint32
31 typedef_from_name (MonoImage *image, const char *name, const char *nspace, guint32 *mlist)
32 {
33         MonoMetadata *m = &image->metadata;
34         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
35         guint32 i;
36         guint32 cols [MONO_TYPEDEF_SIZE];
37
38         for (i=0; i < t->rows; ++i) {
39                 mono_metadata_decode_row (t, i, cols, MONO_TYPEDEF_SIZE);
40                 if (strcmp (name, mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAME])) == 0 
41                                 && strcmp (nspace, mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAMESPACE])) == 0) {
42                         *mlist = cols [MONO_TYPEDEF_METHOD_LIST];
43                         return i + 1;
44                 }
45         }
46         g_assert_not_reached ();
47         return 0;
48 }
49
50 static void
51 methoddef_from_memberref (MonoImage *image, guint32 index, MonoImage **rimage, guint32 *rindex)
52 {
53         MonoMetadata *m = &image->metadata;
54         MonoTableInfo *tables = m->tables;
55         guint32 cols[6];
56         guint32 nindex, sig_len, msig_len, class, i;
57         const char *sig, *msig, *mname, *name, *nspace;
58         
59         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], index-1, cols, 3);
60         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
61         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
62         /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
63                 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
64         sig = mono_metadata_blob_heap (m, cols [MONO_MEMBERREF_SIGNATURE]);
65         sig_len = mono_metadata_decode_blob_size (sig, &sig);
66         mname = mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]);
67
68         switch (class) {
69         case MEMBERREF_PARENT_TYPEREF: {
70                 guint32 scopeindex, scopetable;
71
72                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPEREF], nindex-1, cols, MONO_TYPEREF_SIZE);
73                 scopeindex = cols [MONO_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
74                 scopetable = cols [MONO_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK;
75                 /*g_print ("typeref: 0x%x 0x%x %s.%s\n", scopetable, scopeindex,
76                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]),
77                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]));*/
78                 switch (scopetable) {
79                 case RESOLTION_SCOPE_ASSEMBLYREF:
80                         /*
81                          * To find the method we have the following info:
82                          * *) name and namespace of the class from the TYPEREF table
83                          * *) name and signature of the method from the MEMBERREF table
84                          */
85                         nspace = mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]);
86                         name = mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]);
87                         
88                         image = image->references [scopeindex-1]->image;
89                         m = &image->metadata;
90                         tables = &m->tables [MONO_TABLE_METHOD];
91                         typedef_from_name (image, name, nspace, &i);
92                         /* mostly dumb search for now */
93                         for (;i < tables->rows; ++i) {
94                                 mono_metadata_decode_row (tables, i, cols, MONO_METHOD_SIZE);
95                                 msig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
96                                 msig_len = mono_metadata_decode_blob_size (msig, &msig);
97                                 
98                                 if (strcmp (mname, mono_metadata_string_heap (m, cols [MONO_METHOD_NAME])) == 0 
99                                                 && sig_len == msig_len
100                                                 && strncmp (sig, msig, sig_len) == 0) {
101                                         *rimage = image;
102                                         *rindex = i + 1;
103                                         return;
104                                 }
105                         }
106                         g_assert_not_reached ();
107                         break;
108                 default:
109                         g_assert_not_reached ();
110                 }
111                 break;
112         }
113         default:
114                 g_assert_not_reached ();
115         }
116 }
117
118 static ffi_type *
119 ves_map_ffi_type (MonoType *type)
120 {
121         ffi_type *rettype;
122
123         if (!type)
124                 return &ffi_type_void;
125
126         switch (type->type) {
127         case MONO_TYPE_I1:
128                 rettype = &ffi_type_sint8;
129                 break;
130         case MONO_TYPE_BOOLEAN:
131         case MONO_TYPE_U1:
132                 rettype = &ffi_type_uint8;
133                 break;
134         case MONO_TYPE_I2:
135                 rettype = &ffi_type_sint16;
136                 break;
137         case MONO_TYPE_U2:
138         case MONO_TYPE_CHAR:
139                 rettype = &ffi_type_uint16;
140                 break;
141         case MONO_TYPE_I4:
142                 rettype = &ffi_type_sint32;
143                 break;
144         case MONO_TYPE_U4:
145                 rettype = &ffi_type_sint32;
146                 break;
147         case MONO_TYPE_R4:
148                 rettype = &ffi_type_float;
149                 break;
150         case MONO_TYPE_R8:
151                 rettype = &ffi_type_double;
152                 break;
153         case MONO_TYPE_STRING:
154                 rettype = &ffi_type_pointer;
155                 break;
156         default:
157                 g_warning ("not implemented");
158                 g_assert_not_reached ();
159         }
160
161         return rettype;
162 }
163
164 static void
165 fill_pinvoke_info (MonoImage *image, MonoMethodPInvoke *piinfo, int index)
166 {
167         MonoMethod *mh = &piinfo->method;
168         MonoTableInfo *tables = image->metadata.tables;
169         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
170         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
171         guint32 im_cols [4];
172         guint32 mr_cols [1];
173         const char *import = NULL;
174         const char *scope = NULL;
175         GModule *gmodule;
176         ffi_type **args, *rettype;
177         int i, acount;
178
179         for (i = 0; i < im->rows; i++) {
180                         
181                 mono_metadata_decode_row (im, i, im_cols, 4);
182
183                 if ((im_cols[1] >> 1) == index + 1) {
184
185                         import = mono_metadata_string_heap (&image->metadata, 
186                                                             im_cols [2]);
187
188                         mono_metadata_decode_row (mr, im_cols [3] - 1, mr_cols,
189                                                   1);
190                         
191                         scope = mono_metadata_string_heap (&image->metadata, 
192                                                            mr_cols [0]);
193                 }
194         }
195
196         g_assert (import && scope);
197
198         if (!strcmp (scope, "cygwin1.dll"))
199                 scope = "libc.so.6";
200
201         gmodule = g_module_open (scope, G_MODULE_BIND_LAZY);
202
203         g_assert (gmodule);
204
205         piinfo->cif = g_new (ffi_cif , 1);
206         piinfo->piflags = im_cols [0];
207         
208         g_module_symbol (gmodule, import, &piinfo->addr); 
209                         
210         g_assert (piinfo->addr);
211
212         acount = mh->signature->param_count;
213
214         args = g_new (ffi_type *, acount);
215
216         for (i = 0; i < acount; i++)
217                 args[i] = ves_map_ffi_type (mh->signature->params [i]->type);
218
219         rettype = ves_map_ffi_type (mh->signature->ret->type);
220
221         if (!ffi_prep_cif (piinfo->cif, FFI_DEFAULT_ABI, acount, rettype, 
222                            args) == FFI_OK) {
223                 g_warning ("prepare pinvoke failed");
224                 g_assert_not_reached ();
225         }
226 }
227
228 MonoMethod *
229 mono_get_method (MonoImage *image, guint32 token)
230 {
231         MonoMethod *result;
232         int table = mono_metadata_token_table (token);
233         int index = mono_metadata_token_index (token);
234         MonoTableInfo *tables = image->metadata.tables;
235         const char *loc;
236         const char *sig = NULL;
237         int size;
238         guint32 cols[6];
239
240         if (table == MONO_TABLE_METHOD && (result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token))))
241                         return result;
242         
243         if (table != MONO_TABLE_METHOD) {
244                 g_assert (table == MONO_TABLE_MEMBERREF);
245                 methoddef_from_memberref (image, index, &image, &token);
246                 return mono_get_method (image, MONO_TOKEN_METHOD_DEF | token);
247         }
248
249         
250         mono_metadata_decode_row (&tables [table], index - 1, cols, 6);
251
252         if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL)
253                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
254         else
255                 result = (MonoMethod *)g_new0 (MonoMethodManaged, 1);
256
257         result->image = image;
258         result->flags = cols [2];
259         result->iflags = cols [1];
260         result->name = mono_metadata_string_heap (&image->metadata, cols [3]);
261
262         if (!sig) /* already taken from the methodref */
263                 sig = mono_metadata_blob_heap (&image->metadata, cols [4]);
264         size = mono_metadata_decode_blob_size (sig, &sig);
265         result->signature = mono_metadata_parse_method_signature (&image->metadata, 0, sig, NULL);
266
267
268         if (result->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
269                 fill_pinvoke_info (image, (MonoMethodPInvoke *)result, index);
270         } else {
271                 /* if this is a methodref from another module/assembly, this fails */
272                 loc = mono_cli_rva_map ((MonoCLIImageInfo *)image->image_info, cols [0]);
273                 g_assert (loc);
274                 ((MonoMethodManaged *)result)->header = 
275                         mono_metadata_parse_mh (&image->metadata, loc);
276         }
277
278         g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
279
280         return result;
281 }
282
283 void
284 mono_free_method  (MonoMethod *method)
285 {
286         mono_metadata_free_method_signature (method->signature);
287         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
288                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
289                 g_free (piinfo->cif->arg_types);
290                 g_free (piinfo->cif);
291         } else {
292                 mono_metadata_free_mh (((MonoMethodManaged *)method)->header);
293         }
294
295         g_free (method);
296 }