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