2001-08-20 Dietmar Maurer <dietmar@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/assembly.h>
26 #include <mono/metadata/tokentype.h>
27 #include <mono/metadata/cil-coff.h>
28 #include <mono/metadata/tabledefs.h>
29 #include "cli.h"
30
31 MonoDefaults mono_defaults;
32
33 static char *dll_map[] = {
34         "libc", "libc.so.6",
35         "libm", "libm.so.6",
36         "cygwin1.dll", "libc.so.6", 
37         NULL, NULL
38 };
39
40 static const char *
41 mono_map_dll (const char *name)
42 {
43         int i = 0;
44
45         while (dll_map [i]) {
46                 if (!strcmp (dll_map [i], name))
47                         return  dll_map [i + 1];
48                 i += 2;
49         }
50
51         return name;
52 }
53
54 guint32
55 mono_typedef_from_name (MonoImage *image, const char *name, 
56                         const char *nspace, guint32 *mlist)
57 {
58         MonoMetadata *m = &image->metadata;
59         MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
60         guint32 i;
61         guint32 cols [MONO_TYPEDEF_SIZE];
62
63         for (i=0; i < t->rows; ++i) {
64                 mono_metadata_decode_row (t, i, cols, MONO_TYPEDEF_SIZE);
65                 if (strcmp (name, mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAME])) == 0 
66                                 && strcmp (nspace, mono_metadata_string_heap (m, cols [MONO_TYPEDEF_NAMESPACE])) == 0) {
67                         if (mlist)
68                                 *mlist = cols [MONO_TYPEDEF_METHOD_LIST];
69                         return MONO_TOKEN_TYPE_DEF | (i + 1);
70                 }
71         }
72         g_assert_not_reached ();
73         return 0;
74 }
75
76 void
77 mono_init ()
78 {
79         static gboolean initialized = FALSE;
80         MonoAssembly *ass;
81         enum MonoImageOpenStatus status = MONO_IMAGE_OK;
82
83         if (initialized)
84                 return;
85
86         /* find the corlib */
87         ass = mono_assembly_open (CORLIB_NAME, NULL, &status);
88         g_assert (status == MONO_IMAGE_OK);
89         g_assert (ass != NULL);
90         mono_defaults.corlib = ass->image;
91
92         mono_defaults.array_token = mono_typedef_from_name (
93                 mono_defaults.corlib, "Array", "System", NULL);
94         g_assert (mono_defaults.array_token != 0);
95
96         mono_defaults.char_token = mono_typedef_from_name (
97                 mono_defaults.corlib, "Char", "System", NULL);
98         g_assert (mono_defaults.char_token != 0);
99
100         mono_defaults.string_token = mono_typedef_from_name (
101                 mono_defaults.corlib, "String", "System", NULL);
102         
103         g_assert (mono_defaults.string_token != 0);
104
105 }
106
107 static MonoMethod *
108 method_from_memberref (MonoImage *image, guint32 index)
109 {
110         MonoImage *mimage;
111         MonoMetadata *m = &image->metadata;
112         MonoTableInfo *tables = m->tables;
113         guint32 cols[6];
114         guint32 nindex, class, i;
115         const char *mname, *name, *nspace;
116         MonoMethodSignature *sig, *msig;
117         const char *ptr;
118
119         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], index-1, cols, 3);
120         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
121         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
122         /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
123                 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
124
125         mname = mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]);
126         
127         ptr = mono_metadata_blob_heap (m, cols [MONO_MEMBERREF_SIGNATURE]);
128         mono_metadata_decode_blob_size (ptr, &ptr);
129         sig = mono_metadata_parse_method_signature (m, 0, ptr, NULL);
130
131         switch (class) {
132         case MEMBERREF_PARENT_TYPEREF: {
133                 guint32 scopeindex, scopetable;
134
135                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPEREF], nindex-1, cols, MONO_TYPEREF_SIZE);
136                 scopeindex = cols [MONO_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
137                 scopetable = cols [MONO_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK;
138                 /*g_print ("typeref: 0x%x 0x%x %s.%s\n", scopetable, scopeindex,
139                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]),
140                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]));*/
141                 switch (scopetable) {
142                 case RESOLTION_SCOPE_ASSEMBLYREF:
143                         /*
144                          * To find the method we have the following info:
145                          * *) name and namespace of the class from the TYPEREF table
146                          * *) name and signature of the method from the MEMBERREF table
147                          */
148                         nspace = mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]);
149                         name = mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]);
150
151                         /* this will triggered by references to mscorlib */
152                         g_assert (image->references [scopeindex-1] != NULL);
153
154                         mimage = image->references [scopeindex-1]->image;
155
156                         m = &mimage->metadata;
157                         tables = &m->tables [MONO_TABLE_METHOD];
158                         mono_typedef_from_name (mimage, name, nspace, &i);
159                         /* mostly dumb search for now */
160                         for (i--; i < tables->rows; ++i) {
161
162                                 mono_metadata_decode_row (tables, i, cols, MONO_METHOD_SIZE);
163
164                                 if (!strcmp (mname, mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]))) {
165                                         
166                                         ptr = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
167                                         mono_metadata_decode_blob_size (ptr, &ptr);
168                                         msig = mono_metadata_parse_method_signature (m, 1, ptr, NULL);
169
170                                         if (mono_metadata_signature_equal (&image->metadata, sig, 
171                                                                            &mimage->metadata, msig)) {
172                                                 mono_metadata_free_method_signature (sig);
173                                                 mono_metadata_free_method_signature (msig);
174                                                 return mono_get_method (mimage, MONO_TOKEN_METHOD_DEF | (i + 1));
175                                         }
176                                 }
177                         }
178                         g_warning ("cant find method %s.%s::%s",nspace, name, mname);
179                         g_assert_not_reached ();
180                         break;
181                 default:
182                         g_assert_not_reached ();
183                 }
184                 break;
185         }
186         case MEMBERREF_PARENT_TYPESPEC: {
187                 guint32 bcols [MONO_TYPESPEC_SIZE];
188                 guint32 len;
189                 MonoType *type;
190                 MonoMethod *result;
191
192                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
193                                           bcols, MONO_TYPESPEC_SIZE);
194                 ptr = mono_metadata_blob_heap (m, bcols [MONO_TYPESPEC_SIGNATURE]);
195                 len = mono_metadata_decode_value (ptr, &ptr);   
196                 type = mono_metadata_parse_type (m, ptr, &ptr);
197
198                 if (type->type != MONO_TYPE_ARRAY)
199                         g_assert_not_reached ();                
200
201                 result = (MonoMethod *)g_new0 (MonoMethod, 1);
202                 result->image = image;
203                 result->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
204                 result->signature = sig;
205                 
206                 if (!strcmp (mname, ".ctor")) { 
207                         g_assert (sig->hasthis);
208                         if (type->data.array->rank == sig->param_count) {
209                                 result->addr = mono_lookup_internal_call ("__array_ctor");
210                                 return result;
211                         } else if ((type->data.array->rank * 2) == sig->param_count) {
212                                 result->addr = mono_lookup_internal_call ("__array_bound_ctor");
213                                 return result;                  
214                         } else 
215                                 g_assert_not_reached ();
216                 }
217
218                 if (!strcmp (mname, "Set")) {
219                         g_assert (sig->hasthis);
220                         g_assert (type->data.array->rank + 1 == sig->param_count);
221
222                         result->addr = mono_lookup_internal_call ("__array_Set");
223                         return result;
224                 }
225
226                 if (!strcmp (mname, "Get")) {
227                         g_assert (sig->hasthis);
228                         g_assert (type->data.array->rank == sig->param_count);
229
230                         result->addr = mono_lookup_internal_call ("__array_Get");
231                         return result;
232                 }
233
234                 g_assert_not_reached ();
235                 break;
236         }
237         default:
238                 g_assert_not_reached ();
239         }
240
241         return NULL;
242 }
243
244 static ffi_type *
245 ves_map_ffi_type (MonoType *type)
246 {
247         ffi_type *rettype;
248
249         switch (type->type) {
250         case MONO_TYPE_I1:
251                 rettype = &ffi_type_sint8;
252                 break;
253         case MONO_TYPE_BOOLEAN:
254         case MONO_TYPE_U1:
255                 rettype = &ffi_type_uint8;
256                 break;
257         case MONO_TYPE_I2:
258                 rettype = &ffi_type_sint16;
259                 break;
260         case MONO_TYPE_U2:
261         case MONO_TYPE_CHAR:
262                 rettype = &ffi_type_uint16;
263                 break;
264         case MONO_TYPE_I4:
265                 rettype = &ffi_type_sint32;
266                 break;
267         case MONO_TYPE_U4:
268                 rettype = &ffi_type_sint32;
269                 break;
270         case MONO_TYPE_R4:
271                 rettype = &ffi_type_float;
272                 break;
273         case MONO_TYPE_R8:
274                 rettype = &ffi_type_double;
275                 break;
276         case MONO_TYPE_STRING:
277                 rettype = &ffi_type_pointer;
278                 break;
279         case MONO_TYPE_VOID:
280                 rettype = &ffi_type_void;
281                 break;
282         default:
283                 g_warning ("not implemented");
284                 g_assert_not_reached ();
285         }
286
287         return rettype;
288 }
289
290 static void
291 fill_pinvoke_info (MonoImage *image, MonoMethodPInvoke *piinfo, int index)
292 {
293         MonoMethod *mh = &piinfo->method;
294         MonoTableInfo *tables = image->metadata.tables;
295         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
296         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
297         guint32 im_cols [4];
298         guint32 mr_cols [1];
299         const char *import = NULL;
300         const char *scope = NULL;
301         char *full_name;
302         GModule *gmodule;
303         ffi_type **args, *rettype;
304         int i, acount;
305
306         for (i = 0; i < im->rows; i++) {
307                         
308                 mono_metadata_decode_row (im, i, im_cols, 4);
309
310                 if ((im_cols[1] >> 1) == index + 1) {
311
312                         import = mono_metadata_string_heap (&image->metadata, 
313                                                             im_cols [2]);
314
315                         mono_metadata_decode_row (mr, im_cols [3] - 1, mr_cols,
316                                                   1);
317                         
318                         scope = mono_metadata_string_heap (&image->metadata, 
319                                                            mr_cols [0]);
320                 }
321         }
322
323         g_assert (import && scope);
324
325         scope = mono_map_dll (scope);
326         full_name = g_module_build_path (NULL, scope);
327         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
328         g_free (full_name);
329
330         g_assert (gmodule);
331
332         piinfo->cif = g_new (ffi_cif , 1);
333         piinfo->piflags = im_cols [0];
334
335         g_module_symbol (gmodule, import, &mh->addr); 
336
337         g_assert (mh->addr);
338
339         acount = mh->signature->param_count;
340
341         args = g_new (ffi_type *, acount);
342
343         for (i = 0; i < acount; i++)
344                 args[i] = ves_map_ffi_type (mh->signature->params [i]->type);
345
346         rettype = ves_map_ffi_type (mh->signature->ret->type);
347         
348         if (!ffi_prep_cif (piinfo->cif, FFI_DEFAULT_ABI, acount, rettype, 
349                            args) == FFI_OK) {
350                 g_warning ("prepare pinvoke failed");
351                 g_assert_not_reached ();
352         }
353 }
354
355 MonoMethod *
356 mono_get_method (MonoImage *image, guint32 token)
357 {
358         MonoMethod *result;
359         MonoMetadata *m = &image->metadata;
360         int table = mono_metadata_token_table (token);
361         int index = mono_metadata_token_index (token);
362         MonoTableInfo *tables = m->tables;
363         const char *loc, *sig = NULL;
364         char *name;
365         int size;
366         guint32 cols[MONO_TYPEDEF_SIZE];
367
368         if (table == MONO_TABLE_METHOD && (result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token))))
369                         return result;
370
371         if (table != MONO_TABLE_METHOD) {
372                 g_assert (table == MONO_TABLE_MEMBERREF);
373                 return method_from_memberref (image, index);
374         }
375
376         mono_metadata_decode_row (&tables [table], index - 1, cols, 6);
377
378         if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
379                 MonoTableInfo *t = &m->tables [MONO_TABLE_TYPEDEF];
380                 MonoAssembly *corlib;
381                 guint32 tdef;
382                 guint32 tdcols [MONO_TYPEDEF_SIZE];
383
384                 tdef = mono_metadata_typedef_from_method (m, index - 1) - 1;
385
386                 mono_metadata_decode_row (t, tdef, tdcols, MONO_TYPEDEF_SIZE);
387
388                 name = g_strconcat (mono_metadata_string_heap (m, tdcols [MONO_TYPEDEF_NAMESPACE]), ".",
389                                     mono_metadata_string_heap (m, tdcols [MONO_TYPEDEF_NAME]), "::", 
390                                     mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]), NULL);
391
392                 corlib = mono_assembly_open (CORLIB_NAME, NULL, NULL);
393
394                 /* all internal calls must be inside corlib */
395                 g_assert (corlib->image == image);
396
397                 result = (MonoMethod *)g_new0 (MonoMethod, 1);
398
399                 result->addr = mono_lookup_internal_call (name);
400
401                 g_free (name);
402
403                 g_assert (result->addr != NULL);
404
405         } else if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
406
407                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
408         } else {
409
410                 result = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
411         }
412
413         result->image = image;
414         result->flags = cols [2];
415         result->iflags = cols [1];
416         result->name = mono_metadata_string_heap (m, cols [3]);
417
418         if (!sig) /* already taken from the methodref */
419                 sig = mono_metadata_blob_heap (m, cols [4]);
420         size = mono_metadata_decode_blob_size (sig, &sig);
421         result->signature = mono_metadata_parse_method_signature (m, 0, sig, NULL);
422
423         if (result->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
424                 fill_pinvoke_info (image, (MonoMethodPInvoke *)result, 
425                                    index - 1);
426         } else if (!(result->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
427                 /* if this is a methodref from another module/assembly, this fails */
428                 loc = mono_cli_rva_map ((MonoCLIImageInfo *)image->image_info, cols [0]);
429                 g_assert (loc);
430                 ((MonoMethodNormal *)result)->header = 
431                         mono_metadata_parse_mh (m, loc);
432         }
433
434         g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
435
436         return result;
437 }
438
439 void
440 mono_free_method  (MonoMethod *method)
441 {
442         mono_metadata_free_method_signature (method->signature);
443         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
444                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
445                 g_free (piinfo->cif->arg_types);
446                 g_free (piinfo->cif);
447         } else if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
448                 mono_metadata_free_mh (((MonoMethodNormal *)method)->header);
449         }
450
451         g_free (method);
452 }
453