Fri Nov 2 19:06:54 CET 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/assembly.h>
26 #include <mono/metadata/tokentype.h>
27 #include <mono/metadata/cil-coff.h>
28 #include <mono/metadata/tabledefs.h>
29 #include <mono/metadata/loader.h>
30 #include <mono/metadata/class.h>
31
32 static gboolean dummy_icall = TRUE;
33
34 MonoDefaults mono_defaults;
35
36 #ifdef __CYGWIN__
37 #define mono_map_dll(name) (name)
38 #else
39 static char *dll_map[] = {
40         "libc", "libc.so.6",
41         "libm", "libm.so.6",
42         "cygwin1.dll", "libc.so.6", 
43         NULL, NULL
44 };
45
46 static const char *
47 mono_map_dll (const char *name)
48 {
49         int i = 0;
50
51         while (dll_map [i]) {
52                 if (!strcmp (dll_map [i], name))
53                         return  dll_map [i + 1];
54                 i += 2;
55         }
56
57         return name;
58 }
59 #endif
60
61 void
62 mono_init (void)
63 {
64         static gboolean initialized = FALSE;
65         MonoAssembly *ass;
66         enum MonoImageOpenStatus status = MONO_IMAGE_OK;
67
68         if (initialized)
69                 return;
70
71         /* find the corlib */
72         ass = mono_assembly_open (CORLIB_NAME, NULL, &status);
73         g_assert (status == MONO_IMAGE_OK);
74         g_assert (ass != NULL);
75         mono_defaults.corlib = ass->image;
76
77         mono_defaults.object_class = mono_class_from_name (
78                 mono_defaults.corlib, "System", "Object");
79         g_assert (mono_defaults.object_class != 0);
80
81         mono_defaults.void_class = mono_class_from_name (
82                 mono_defaults.corlib, "System", "Void");
83         g_assert (mono_defaults.void_class != 0);
84
85         mono_defaults.boolean_class = mono_class_from_name (
86                 mono_defaults.corlib, "System", "Boolean");
87         g_assert (mono_defaults.boolean_class != 0);
88
89         mono_defaults.byte_class = mono_class_from_name (
90                 mono_defaults.corlib, "System", "Byte");
91         g_assert (mono_defaults.byte_class != 0);
92
93         mono_defaults.sbyte_class = mono_class_from_name (
94                 mono_defaults.corlib, "System", "SByte");
95         g_assert (mono_defaults.sbyte_class != 0);
96
97         mono_defaults.int16_class = mono_class_from_name (
98                 mono_defaults.corlib, "System", "Int16");
99         g_assert (mono_defaults.int16_class != 0);
100
101         mono_defaults.uint16_class = mono_class_from_name (
102                 mono_defaults.corlib, "System", "UInt16");
103         g_assert (mono_defaults.uint16_class != 0);
104
105         mono_defaults.int32_class = mono_class_from_name (
106                 mono_defaults.corlib, "System", "Int32");
107         g_assert (mono_defaults.int32_class != 0);
108
109         mono_defaults.uint32_class = mono_class_from_name (
110                 mono_defaults.corlib, "System", "UInt32");
111         g_assert (mono_defaults.uint32_class != 0);
112
113         mono_defaults.uint_class = mono_class_from_name (
114                 mono_defaults.corlib, "System", "UIntPtr");
115         g_assert (mono_defaults.uint_class != 0);
116
117         mono_defaults.int_class = mono_class_from_name (
118                 mono_defaults.corlib, "System", "IntPtr");
119         g_assert (mono_defaults.int_class != 0);
120
121         mono_defaults.int64_class = mono_class_from_name (
122                 mono_defaults.corlib, "System", "Int64");
123         g_assert (mono_defaults.int64_class != 0);
124
125         mono_defaults.uint64_class = mono_class_from_name (
126                 mono_defaults.corlib, "System", "UInt64");
127         g_assert (mono_defaults.uint64_class != 0);
128
129         mono_defaults.single_class = mono_class_from_name (
130                 mono_defaults.corlib, "System", "Single");
131         g_assert (mono_defaults.single_class != 0);
132
133         mono_defaults.double_class = mono_class_from_name (
134                 mono_defaults.corlib, "System", "Double");
135         g_assert (mono_defaults.double_class != 0);
136
137         mono_defaults.char_class = mono_class_from_name (
138                 mono_defaults.corlib, "System", "Char");
139         g_assert (mono_defaults.char_class != 0);
140
141         mono_defaults.string_class = mono_class_from_name (
142                 mono_defaults.corlib, "System", "String");
143         g_assert (mono_defaults.string_class != 0);
144
145         mono_defaults.enum_class = mono_class_from_name (
146                 mono_defaults.corlib, "System", "Enum");
147         g_assert (mono_defaults.enum_class != 0);
148
149         mono_defaults.array_class = mono_class_from_name (
150                 mono_defaults.corlib, "System", "Array");
151         g_assert (mono_defaults.array_class != 0);
152
153         mono_defaults.delegate_class = mono_class_from_name (
154                 mono_defaults.corlib, "System", "Delegate");
155         g_assert (mono_defaults.delegate_class != 0);
156
157         mono_defaults.typehandle_class = mono_class_from_name (
158                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
159         g_assert (mono_defaults.typehandle_class != 0);
160
161         mono_defaults.methodhandle_class = mono_class_from_name (
162                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
163         g_assert (mono_defaults.methodhandle_class != 0);
164
165         mono_defaults.fieldhandle_class = mono_class_from_name (
166                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
167         g_assert (mono_defaults.fieldhandle_class != 0);
168
169         mono_defaults.type_class = mono_class_from_name (
170                 mono_defaults.corlib, "System", "Type");
171         g_assert (mono_defaults.type_class != 0);
172
173 }
174
175 static GHashTable *icall_hash = NULL;
176
177 void
178 mono_add_internal_call (const char *name, gpointer method)
179 {
180         if (!icall_hash) {
181                 dummy_icall = FALSE;
182                 icall_hash = g_hash_table_new (g_str_hash , g_str_equal);
183         }
184
185         g_hash_table_insert (icall_hash, g_strdup (name), method);
186 }
187
188 static void
189 ves_icall_dummy ()
190 {
191         g_warning ("the mono runtime is not initialized");
192         g_assert_not_reached ();
193 }
194
195 gpointer
196 mono_lookup_internal_call (const char *name)
197 {
198         gpointer res;
199
200         if (dummy_icall)
201                 return ves_icall_dummy;
202
203         if (!icall_hash) {
204                 g_warning ("icall_hash not initialized");
205                 g_assert_not_reached ();
206         }
207
208         if (!(res = g_hash_table_lookup (icall_hash, name))) {
209                 g_warning ("cant resolve internal call to \"%s\"", name);
210                 return NULL;
211         }
212
213         return res;
214 }
215
216 MonoClassField*
217 mono_field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass)
218 {
219         MonoImage *mimage;
220         MonoClass *klass;
221         MonoTableInfo *tables = image->tables;
222         guint32 cols[6];
223         guint32 nindex, class, i;
224         const char *fname, *name, *nspace;
225         const char *ptr;
226         guint32 index = mono_metadata_token_index (token);
227
228         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], index-1, cols, MONO_MEMBERREF_SIZE);
229         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
230         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
231
232         fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
233         
234         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
235         mono_metadata_decode_blob_size (ptr, &ptr);
236         /* we may want to check the signature here... */
237
238         switch (class) {
239         case MEMBERREF_PARENT_TYPEREF: {
240                 guint32 scopeindex, scopetable;
241
242                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPEREF], nindex-1, cols, MONO_TYPEREF_SIZE);
243                 scopeindex = cols [MONO_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
244                 scopetable = cols [MONO_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK;
245                 /*g_print ("typeref: 0x%x 0x%x %s.%s\n", scopetable, scopeindex,
246                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]),
247                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]));*/
248                 switch (scopetable) {
249                 case RESOLTION_SCOPE_ASSEMBLYREF:
250                         /*
251                          * To find the field we have the following info:
252                          * *) name and namespace of the class from the TYPEREF table
253                          * *) name and signature of the field from the MEMBERREF table
254                          */
255                         nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
256                         name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
257
258                         /* this will triggered by references to mscorlib */
259                         if (image->references [scopeindex-1] == NULL)
260                                 g_error ("Reference to mscorlib? Probably need to implement %s.%s::%s in corlib", nspace, name, fname);
261
262                         mimage = image->references [scopeindex-1]->image;
263
264                         klass = mono_class_from_name (mimage, nspace, name);
265                         mono_class_metadata_init (klass);
266
267                         /* mostly dumb search for now */
268                         for (i = 0; i < klass->field.count; ++i) {
269                                 MonoClassField *f = &klass->fields [i];
270                                 if (!strcmp (fname, f->name)) {
271                                         if (retklass)
272                                                 *retklass = klass;
273                                         return f;
274                                 }
275                         }
276                         g_warning ("Missing field %s.%s::%s", nspace, name, fname);
277                         return NULL;
278                 default:
279                         return NULL;
280                 }
281                 break;
282         }
283         default:
284                 return NULL;
285         }
286 }
287
288 static MonoMethod *
289 method_from_memberref (MonoImage *image, guint32 index)
290 {
291         MonoImage *mimage;
292         MonoClass *klass;
293         MonoTableInfo *tables = image->tables;
294         guint32 cols[6];
295         guint32 nindex, class, i;
296         const char *mname, *name, *nspace;
297         MonoMethodSignature *sig;
298         const char *ptr;
299
300         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], index-1, cols, 3);
301         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
302         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
303         /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
304                 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
305
306         mname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
307         
308         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
309         mono_metadata_decode_blob_size (ptr, &ptr);
310         sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
311
312         switch (class) {
313         case MEMBERREF_PARENT_TYPEREF: {
314                 guint32 scopeindex, scopetable;
315
316                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPEREF], nindex-1, cols, MONO_TYPEREF_SIZE);
317                 scopeindex = cols [MONO_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
318                 scopetable = cols [MONO_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK;
319                 /*g_print ("typeref: 0x%x 0x%x %s.%s\n", scopetable, scopeindex,
320                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]),
321                         mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]));*/
322                 switch (scopetable) {
323                 case RESOLTION_SCOPE_ASSEMBLYREF:
324                         /*
325                          * To find the method we have the following info:
326                          * *) name and namespace of the class from the TYPEREF table
327                          * *) name and signature of the method from the MEMBERREF table
328                          */
329                         nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
330                         name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
331
332                         /* this will triggered by references to mscorlib */
333                         if (image->references [scopeindex-1] == NULL)
334                                 g_error ("Reference to mscorlib? Probably need to implement %s.%s::%s in corlib", nspace, name, mname);
335
336                         mimage = image->references [scopeindex-1]->image;
337
338                         klass = mono_class_from_name (mimage, nspace, name);
339                         mono_class_metadata_init (klass);
340
341                         /* 
342                          * FIXME: this is a workaround for the different signatures
343                          * in delegates constructors you get in user code (native int)
344                          * and in mscorlib (native unsigned int)
345                          */
346                         if (klass->parent && klass->parent->parent == mono_defaults.delegate_class) {
347                                 for (i = 0; i < klass->method.count; ++i) {
348                                         MonoMethod *m = klass->methods [i];
349                                         if (!strcmp (mname, m->name)) {
350                                                 if (!strcmp (mname, ".ctor")) {
351                                                         /* we assume signature is correct */
352                                                         mono_metadata_free_method_signature (sig);
353                                                         return m;
354                                                 }
355                                                 if (mono_metadata_signature_equal (sig, m->signature)) {
356                                                         mono_metadata_free_method_signature (sig);
357                                                         return m;
358                                                 }
359                                         }
360                                 }
361                         }
362                         /* mostly dumb search for now */
363                         for (i = 0; i < klass->method.count; ++i) {
364                                 MonoMethod *m = klass->methods [i];
365                                 if (!strcmp (mname, m->name)) {
366                                         if (mono_metadata_signature_equal (sig, m->signature)) {
367                                                 mono_metadata_free_method_signature (sig);
368                                                 return m;
369                                         }
370                                 }
371                         }
372                         g_warning ("Missing method %s.%s::%s", nspace, name, mname);
373                         mono_metadata_free_method_signature (sig);
374                         return NULL;
375                 default:
376                         mono_metadata_free_method_signature (sig);
377                         return NULL;
378                 }
379                 break;
380         }
381         case MEMBERREF_PARENT_TYPESPEC: {
382                 guint32 bcols [MONO_TYPESPEC_SIZE];
383                 guint32 len;
384                 MonoType *type;
385                 MonoMethod *result;
386
387                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
388                                           bcols, MONO_TYPESPEC_SIZE);
389                 ptr = mono_metadata_blob_heap (image, bcols [MONO_TYPESPEC_SIGNATURE]);
390                 len = mono_metadata_decode_value (ptr, &ptr);   
391                 type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
392
393                 if (type->type != MONO_TYPE_ARRAY)
394                         g_assert_not_reached ();                
395
396                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
397                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_SPEC | nindex);
398                 result->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
399                 result->signature = sig;
400                 result->name = mname;
401
402                 if (!strcmp (mname, ".ctor")) { 
403                         g_assert (sig->hasthis);
404                         if (type->data.array->rank == sig->param_count) {
405                                 result->addr = mono_lookup_internal_call ("__array_ctor");
406                         } else if ((type->data.array->rank * 2) == sig->param_count) {
407                                 result->addr = mono_lookup_internal_call ("__array_bound_ctor");
408                         } else 
409                                 g_assert_not_reached ();
410
411                         result->flags = METHOD_ATTRIBUTE_PINVOKE_IMPL;
412                         return result;                                          
413                 }
414
415                 if (!strcmp (mname, "Set")) {
416                         g_assert (sig->hasthis);
417                         g_assert (type->data.array->rank + 1 == sig->param_count);
418
419                         result->addr = mono_lookup_internal_call ("__array_Set");
420                         return result;
421                 }
422
423                 if (!strcmp (mname, "Get")) {
424                         g_assert (sig->hasthis);
425                         g_assert (type->data.array->rank == sig->param_count);
426
427                         result->addr = mono_lookup_internal_call ("__array_Get");
428                         return result;
429                 }
430
431                 g_assert_not_reached ();
432                 break;
433         }
434         default:
435                 g_assert_not_reached ();
436         }
437
438         return NULL;
439 }
440
441 static void
442 fill_pinvoke_info (MonoImage *image, MonoMethodPInvoke *piinfo, int index)
443 {
444         MonoMethod *mh = &piinfo->method;
445         MonoTableInfo *tables = image->tables;
446         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
447         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
448         guint32 im_cols [4];
449         guint32 mr_cols [1];
450         const char *import = NULL;
451         const char *scope = NULL;
452         char *full_name;
453         GModule *gmodule;
454         int i;
455
456         for (i = 0; i < im->rows; i++) {
457                         
458                 mono_metadata_decode_row (im, i, im_cols, 4);
459
460                 if ((im_cols[1] >> 1) == index + 1) {
461
462                         import = mono_metadata_string_heap (image, im_cols [2]);
463
464                         mono_metadata_decode_row (mr, im_cols [3] - 1, mr_cols,
465                                                   1);
466                         
467                         scope = mono_metadata_string_heap (image, mr_cols [0]);
468                 }
469         }
470
471         piinfo->piflags = im_cols [0];
472
473         g_assert (import && scope);
474
475         scope = mono_map_dll (scope);
476         full_name = g_module_build_path (NULL, scope);
477         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
478
479         mh->addr = NULL;
480         if (!gmodule) {
481                 if (!(gmodule=g_module_open (scope, G_MODULE_BIND_LAZY))) {
482                         g_warning ("Failed to load library %s (%s)", full_name, scope);
483                         g_free (full_name);
484                         return;
485                 }
486         }
487         g_free (full_name);
488
489         g_module_symbol (gmodule, import, &mh->addr); 
490
491         if (!mh->addr) {
492                 g_warning ("Failed to load function %s from %s", import, scope);
493                 return;
494         }
495
496         mh->flags |= METHOD_ATTRIBUTE_PINVOKE_IMPL;
497 }
498
499 MonoMethod *
500 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
501 {
502         MonoMethod *result;
503         int table = mono_metadata_token_table (token);
504         int index = mono_metadata_token_index (token);
505         MonoTableInfo *tables = image->tables;
506         const char *loc, *sig = NULL;
507         char *name;
508         int size;
509         guint32 cols [MONO_TYPEDEF_SIZE];
510
511         if ((result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token))))
512                         return result;
513
514         if (table != MONO_TABLE_METHOD) {
515                 g_assert (table == MONO_TABLE_MEMBERREF);
516                 result = method_from_memberref (image, index);
517                 g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
518                 return result;
519         }
520
521         mono_metadata_decode_row (&tables [table], index - 1, cols, 6);
522
523         if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
524             (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
525                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
526         else 
527                 result = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
528         
529         result->slot = -1;
530         result->klass = klass;
531         result->flags = cols [2];
532         result->iflags = cols [1];
533         result->name = mono_metadata_string_heap (image, cols [3]);
534
535         if (!sig) /* already taken from the methodref */
536                 sig = mono_metadata_blob_heap (image, cols [4]);
537         size = mono_metadata_decode_blob_size (sig, &sig);
538         result->signature = mono_metadata_parse_method_signature (image, 0, sig, NULL);
539
540         if (!result->klass) {
541                 guint32 type = mono_metadata_typedef_from_method (image, token);
542                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
543         }
544
545         if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
546                 name = g_strconcat (result->klass->name_space, ".", result->klass->name, "::", 
547                                     mono_metadata_string_heap (image, cols [MONO_METHOD_NAME]), NULL);
548                 result->addr = mono_lookup_internal_call (name);
549                 g_free (name);
550                 result->flags |= METHOD_ATTRIBUTE_PINVOKE_IMPL;
551         } else if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
552                 fill_pinvoke_info (image, (MonoMethodPInvoke *)result, index - 1);
553         } else {
554                 /* if this is a methodref from another module/assembly, this fails */
555                 loc = mono_cli_rva_map ((MonoCLIImageInfo *)image->image_info, cols [0]);
556
557                 if (!result->klass->dummy && !(result->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
558                                         !(result->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
559                         g_assert (loc);
560                         ((MonoMethodNormal *)result)->header = mono_metadata_parse_mh (image, loc);
561                 }
562         }
563
564         g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
565
566         return result;
567 }
568
569 void
570 mono_free_method  (MonoMethod *method)
571 {
572         mono_metadata_free_method_signature (method->signature);
573         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
574                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
575                 g_free (piinfo->code);
576         } else if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
577                 mono_metadata_free_mh (((MonoMethodNormal *)method)->header);
578         }
579
580         g_free (method);
581 }
582