2003-10-31 Martin Baulig <martin@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  *   Patrik Torstensson (patrik.torstensson@labs2.com)
8  *
9  * (C) 2001 Ximian, Inc.
10  *
11  * This file is used by the interpreter and the JIT engine to locate
12  * assemblies.  Used to load AssemblyRef and later to resolve various
13  * kinds of `Refs'.
14  *
15  * TODO:
16  *   This should keep track of the assembly versions that we are loading.
17  *
18  */
19 #include <config.h>
20 #include <glib.h>
21 #include <gmodule.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <mono/metadata/metadata.h>
26 #include <mono/metadata/image.h>
27 #include <mono/metadata/assembly.h>
28 #include <mono/metadata/tokentype.h>
29 #include <mono/metadata/cil-coff.h>
30 #include <mono/metadata/tabledefs.h>
31 #include <mono/metadata/loader.h>
32 #include <mono/metadata/class.h>
33 #include <mono/metadata/debug-helpers.h>
34 #include <mono/metadata/reflection.h>
35
36 static gboolean dummy_icall = TRUE;
37
38 MonoDefaults mono_defaults;
39
40 CRITICAL_SECTION loader_mutex;
41
42 static GHashTable *icall_hash = NULL;
43
44 void
45 mono_loader_init ()
46 {
47         InitializeCriticalSection (&loader_mutex);
48 }
49
50 void
51 mono_add_internal_call (const char *name, gconstpointer method)
52 {
53         mono_loader_lock ();
54
55         if (!icall_hash) {
56                 dummy_icall = FALSE;
57                 icall_hash = g_hash_table_new (g_str_hash , g_str_equal);
58         }
59
60         g_hash_table_insert (icall_hash, g_strdup (name), (gpointer) method);
61
62         mono_loader_unlock ();
63 }
64
65 static void
66 ves_icall_dummy (void)
67 {
68         g_warning ("the mono runtime is not initialized");
69         g_assert_not_reached ();
70 }
71
72 gpointer
73 mono_lookup_internal_call (MonoMethod *method)
74 {
75         char *name;
76         char *tmpsig;
77         gpointer res;
78
79         if (dummy_icall)
80                 return ves_icall_dummy;
81
82         if (!method) {
83                 g_warning ("can't resolve internal call, method is null");
84         }
85
86         if (!icall_hash) {
87                 g_warning ("icall_hash not initialized");
88                 g_assert_not_reached ();
89         }
90
91         mono_loader_lock ();
92
93         if (*method->klass->name_space)
94                 name = g_strconcat (method->klass->name_space, ".", method->klass->name, "::", method->name, NULL);
95         else
96                 name = g_strconcat (method->klass->name, "::", method->name, NULL);
97         if (!(res = g_hash_table_lookup (icall_hash, name))) {
98                 /* trying to resolve with full signature */
99                 g_free (name);
100         
101                 tmpsig = mono_signature_get_desc(method->signature, TRUE);
102                 if (*method->klass->name_space)
103                         name = g_strconcat (method->klass->name_space, ".", method->klass->name, "::", method->name, "(", tmpsig, ")", NULL);
104                 else
105                         name = g_strconcat (method->klass->name, "::", method->name, "(", tmpsig, ")", NULL);
106                 if (!(res = g_hash_table_lookup (icall_hash, name))) {
107                         g_warning ("cant resolve internal call to \"%s\" (tested without signature also)", name);
108                         g_print ("\nYour mono runtime and corlib are out of sync.\n");
109                         g_print ("Corlib is: %s\n", method->klass->image->name);
110                         g_print ("\nWhen you update one from cvs you need to update, compile and install\nthe other too.\n");
111                         g_print ("Do not report this as a bug unless you're sure you have updated correctly:\nyou probably have a broken mono install.\n");
112                         g_print ("If you see other errors or faults after this message they are probably related\n");
113                         g_print ("and you need to fix your mono install first.\n");
114
115                         g_free (name);
116                         g_free (tmpsig);
117
118                         mono_loader_unlock ();
119
120                         return NULL;
121                 }
122
123                 g_free(tmpsig);
124         }
125
126         mono_loader_unlock ();
127
128         g_free (name);
129
130         return res;
131 }
132
133 MonoClassField*
134 mono_field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass)
135 {
136         MonoClass *klass;
137         MonoTableInfo *tables = image->tables;
138         guint32 cols[6];
139         guint32 nindex, class;
140         const char *fname;
141         const char *ptr;
142         guint32 idx = mono_metadata_token_index (token);
143
144         if (image->assembly->dynamic) {
145                 MonoClassField *result = mono_lookup_dynamic_token (image, token);
146                 *retklass = result->parent;
147                 return result;
148         }
149
150         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
151         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
152         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
153
154         fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
155         
156         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
157         mono_metadata_decode_blob_size (ptr, &ptr);
158         /* we may want to check the signature here... */
159
160         switch (class) {
161         case MEMBERREF_PARENT_TYPEREF:
162                 klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
163                 if (!klass) {
164                         g_warning ("Missing field %s in typeref index %d", fname, nindex);
165                         return NULL;
166                 }
167                 mono_class_init (klass);
168                 if (retklass)
169                         *retklass = klass;
170                 return mono_class_get_field_from_name (klass, fname);
171         case MEMBERREF_PARENT_TYPESPEC: {
172                 /*guint32 bcols [MONO_TYPESPEC_SIZE];
173                 guint32 len;
174                 MonoType *type;
175
176                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
177                                           bcols, MONO_TYPESPEC_SIZE);
178                 ptr = mono_metadata_blob_heap (image, bcols [MONO_TYPESPEC_SIGNATURE]);
179                 len = mono_metadata_decode_value (ptr, &ptr);   
180                 type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
181
182                 klass = mono_class_from_mono_type (type);
183                 mono_class_init (klass);
184                 g_print ("type in sig: %s\n", klass->name);*/
185                 klass = mono_class_get (image, MONO_TOKEN_TYPE_SPEC | nindex);
186                 mono_class_init (klass);
187                 if (retklass)
188                         *retklass = klass;
189                 return mono_class_get_field_from_name (klass, fname);
190         }
191         default:
192                 g_warning ("field load from %x", class);
193                 return NULL;
194         }
195 }
196
197 MonoClassField*
198 mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass)
199 {
200         MonoClass *k;
201         guint32 type;
202
203         if (image->assembly->dynamic) {
204                 MonoClassField *result = mono_lookup_dynamic_token (image, token);
205                 *retklass = result->parent;
206                 return result;
207         }
208
209         if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
210                 return mono_field_from_memberref (image, token, retklass);
211
212         type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
213         if (!type)
214                 return NULL;
215         k = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
216         mono_class_init (k);
217         if (!k)
218                 return NULL;
219         if (retklass)
220                 *retklass = k;
221         return mono_class_get_field (k, token);
222 }
223
224 static gboolean
225 mono_metadata_signature_vararg_match (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
226 {
227         int i;
228
229         if (sig1->hasthis != sig2->hasthis ||
230             sig1->sentinelpos != sig2->sentinelpos)
231                 return FALSE;
232
233         for (i = 0; i < sig1->sentinelpos; i++) { 
234                 MonoType *p1 = sig1->params[i];
235                 MonoType *p2 = sig2->params[i];
236                 
237                 //if (p1->attrs != p2->attrs)
238                 //      return FALSE;
239                 
240                 if (!mono_metadata_type_equal (p1, p2))
241                         return FALSE;
242         }
243
244         if (!mono_metadata_type_equal (sig1->ret, sig2->ret))
245                 return FALSE;
246         return TRUE;
247 }
248
249 static MonoMethod *
250 find_method (MonoClass *klass, const char* name, MonoMethodSignature *sig)
251 {
252         int i;
253         MonoClass *sclass = klass;
254         
255         if (sig->call_convention == MONO_CALL_VARARG) {
256                 while (klass) {
257                         /* mostly dumb search for now */
258                         for (i = 0; i < klass->method.count; ++i) {
259                                 MonoMethod *m = klass->methods [i];
260                                 if (!strcmp (name, m->name)) {
261                                         if (mono_metadata_signature_vararg_match (sig, m->signature))
262                                                 return m;
263                                 }
264                         }
265                         if (name [0] == '.' && (strcmp (name, ".ctor") == 0 || strcmp (name, ".cctor") == 0))
266                                 break;
267                         klass = klass->parent;
268                 }
269                 return NULL;
270         }
271         while (klass) {
272                 /* mostly dumb search for now */
273                 for (i = 0; i < klass->method.count; ++i) {
274                         MonoMethod *m = klass->methods [i];
275                         if (!strcmp (name, m->name)) {
276                                 if (mono_metadata_signature_equal (sig, m->signature))
277                                         return m;
278                         }
279                 }
280                 if (name [0] == '.' && (strcmp (name, ".ctor") == 0 || strcmp (name, ".cctor") == 0))
281                         break;
282                 klass = klass->parent;
283         }
284         if (sclass->generic_inst) {
285                 MonoClass *gclass = mono_class_from_mono_type (sclass->generic_inst->data.generic_inst->generic_type);
286                 MonoMethod *res = find_method (gclass, name, sig);
287                 if (!res)
288                         return NULL;
289                 for (i = 0; i < res->klass->method.count; ++i) {
290                         if (res == res->klass->methods [i]) {
291                                 return sclass->methods [i];
292                         }
293                 }
294         }
295         return NULL;
296
297 }
298
299 /*
300  * token is the method_ref or method_def token used in a call IL instruction.
301  */
302 MonoMethodSignature*
303 mono_method_get_signature (MonoMethod *method, MonoImage *image, guint32 token)
304 {
305         int table = mono_metadata_token_table (token);
306         int idx = mono_metadata_token_index (token);
307         guint32 cols [MONO_MEMBERREF_SIZE];
308         MonoMethodSignature *sig;
309         const char *ptr;
310
311         /* !table is for wrappers: we should really assign their own token to them */
312         if (!table || table == MONO_TABLE_METHOD)
313                 return method->signature;
314
315         if (table == MONO_TABLE_METHODSPEC) {
316                 MonoMethodNormal *mn;
317
318                 g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
319                           !(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
320                           method->signature);
321                 mn = (MonoMethodNormal *) method;
322                 g_assert (mn->header->geninst);
323
324                 return method->signature;
325         }
326
327         if (method->klass->generic_inst)
328                 return method->signature;
329
330         if (image->assembly->dynamic)
331                 /* FIXME: This might be incorrect for vararg methods */
332                 return method->signature;
333
334         mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
335         
336         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
337         mono_metadata_decode_blob_size (ptr, &ptr);
338         sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
339
340         return sig;
341 }
342
343 static MonoMethod *
344 method_from_memberref (MonoImage *image, guint32 idx)
345 {
346         MonoClass *klass;
347         MonoMethod *method;
348         MonoTableInfo *tables = image->tables;
349         guint32 cols[6];
350         guint32 nindex, class;
351         const char *mname;
352         MonoMethodSignature *sig;
353         const char *ptr;
354
355         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
356         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
357         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
358         /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
359                 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
360
361         mname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
362         
363         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
364         mono_metadata_decode_blob_size (ptr, &ptr);
365         sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
366
367         switch (class) {
368         case MEMBERREF_PARENT_TYPEREF:
369                 klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
370                 if (!klass) {
371                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
372                         mono_metadata_free_method_signature (sig);
373                         return NULL;
374                 }
375                 mono_class_init (klass);
376                 method = find_method (klass, mname, sig);
377                 if (!method)
378                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
379                 mono_metadata_free_method_signature (sig);
380                 return method;
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 && type->type != MONO_TYPE_SZARRAY) {
394                         klass = mono_class_from_mono_type (type);
395                         mono_class_init (klass);
396                         method = find_method (klass, mname, sig);
397                         if (!method)
398                                 g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
399                         else if (klass->generic_inst)
400                                 method = mono_class_inflate_generic_method (method, klass->generic_inst->data.generic_inst);
401                         mono_metadata_free_method_signature (sig);
402                         return method;
403                 }
404
405                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
406                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_SPEC | nindex);
407                 result->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
408                 result->signature = sig;
409                 result->name = mname;
410
411                 if (!strcmp (mname, ".ctor")) {
412                         /* we special-case this in the runtime. */
413                         result->addr = NULL;
414                         return result;
415                 }
416                 
417                 if (!strcmp (mname, "Set")) {
418                         g_assert (sig->hasthis);
419                         g_assert (type->data.array->rank + 1 == sig->param_count);
420                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
421                         result->addr = NULL;
422                         return result;
423                 }
424
425                 if (!strcmp (mname, "Get")) {
426                         g_assert (sig->hasthis);
427                         g_assert (type->data.array->rank == sig->param_count);
428                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
429                         result->addr = NULL;
430                         return result;
431                 }
432
433                 if (!strcmp (mname, "Address")) {
434                         g_assert (sig->hasthis);
435                         g_assert (type->data.array->rank == sig->param_count);
436                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
437                         result->addr = NULL;
438                         return result;
439                 }
440
441                 g_assert_not_reached ();
442                 break;
443         }
444         case MEMBERREF_PARENT_TYPEDEF:
445                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex);
446                 if (!klass) {
447                         g_warning ("Missing method %s in assembly %s typedef index %d", mname, image->name, nindex);
448                         mono_metadata_free_method_signature (sig);
449                         return NULL;
450                 }
451                 mono_class_init (klass);
452                 method = find_method (klass, mname, sig);
453                 if (!method)
454                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
455                 mono_metadata_free_method_signature (sig);
456                 return method;
457         case MEMBERREF_PARENT_METHODDEF:
458                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | nindex, NULL);
459                 return method;
460         default:
461                 g_error ("Memberref parent unknown: class: %d, index %d", class, nindex);
462                 g_assert_not_reached ();
463         }
464
465         return NULL;
466 }
467
468 static MonoMethod *
469 method_from_methodspec (MonoImage *image, guint32 idx)
470 {
471         MonoMethod *method;
472         MonoTableInfo *tables = image->tables;
473         MonoGenericInst *ginst;
474         const char *ptr;
475         guint32 cols [MONO_METHODSPEC_SIZE];
476         guint32 token, param_count, i;
477
478         mono_metadata_decode_row (&tables [MONO_TABLE_METHODSPEC], idx - 1, cols, MONO_METHODSPEC_SIZE);
479         token = cols [MONO_METHODSPEC_METHOD];
480         if ((token & METHODDEFORREF_MASK) == METHODDEFORREF_METHODDEF)
481                 token = MONO_TOKEN_METHOD_DEF | (token >> METHODDEFORREF_BITS);
482         else
483                 token = MONO_TOKEN_MEMBER_REF | (token >> METHODDEFORREF_BITS);
484
485         method = mono_get_method (image, token, NULL);
486
487         ptr = mono_metadata_blob_heap (image, cols [MONO_METHODSPEC_SIGNATURE]);
488         
489         mono_metadata_decode_value (ptr, &ptr);
490         ptr++;
491         param_count = mono_metadata_decode_value (ptr, &ptr);
492
493         ginst = g_new0 (MonoGenericInst, 1);
494         ginst->generic_method = method;
495         ginst->type_argc = param_count;
496         ginst->type_argv = g_new0 (MonoType *, param_count);
497         
498         for (i = 0; i < param_count; i++)
499                 ginst->type_argv [i] = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
500
501         return mono_class_inflate_generic_method (method, ginst);
502 }
503
504 typedef struct MonoDllMap MonoDllMap;
505
506 struct MonoDllMap {
507         char *name;
508         char *target;
509         char *dll;
510         MonoDllMap *next;
511 };
512
513 static GHashTable *dll_map;
514
515 int 
516 mono_dllmap_lookup (const char *dll, const char* func, const char **rdll, const char **rfunc) {
517         MonoDllMap *map, *tmp;
518
519         if (!dll_map)
520                 return 0;
521
522         mono_loader_lock ();
523
524         map = g_hash_table_lookup (dll_map, dll);
525         if (!map) {
526                 mono_loader_unlock ();
527                 return 0;
528         }
529         *rdll = map->target? map->target: dll;
530                 
531         for (tmp = map->next; tmp; tmp = tmp->next) {
532                 if (strcmp (func, tmp->name) == 0) {
533                         *rfunc = tmp->name;
534                         if (tmp->dll)
535                                 *rdll = tmp->dll;
536                         mono_loader_unlock ();
537                         return 1;
538                 }
539         }
540         *rfunc = func;
541         mono_loader_unlock ();
542         return 1;
543 }
544
545 void
546 mono_dllmap_insert (const char *dll, const char *func, const char *tdll, const char *tfunc) {
547         MonoDllMap *map, *entry;
548
549         mono_loader_lock ();
550
551         if (!dll_map)
552                 dll_map = g_hash_table_new (g_str_hash, g_str_equal);
553
554         map = g_hash_table_lookup (dll_map, dll);
555         if (!map) {
556                 map = g_new0 (MonoDllMap, 1);
557                 map->dll = g_strdup (dll);
558                 if (tdll)
559                         map->target = g_strdup (tdll);
560                 g_hash_table_insert (dll_map, map->dll, map);
561         }
562         if (func) {
563                 entry = g_new0 (MonoDllMap, 1);
564                 entry->name = g_strdup (func);
565                 if (tfunc)
566                         entry->target = g_strdup (tfunc);
567                 if (tdll && map->target && strcmp (map->target, tdll))
568                         entry->dll = g_strdup (tdll);
569                 entry->next = map->next;
570                 map->next = entry;
571         }
572
573         mono_loader_unlock ();
574 }
575
576 gpointer
577 mono_lookup_pinvoke_call (MonoMethod *method)
578 {
579         MonoImage *image = method->klass->image;
580         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
581         MonoTableInfo *tables = image->tables;
582         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
583         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
584         guint32 im_cols [MONO_IMPLMAP_SIZE];
585         guint32 scope_token;
586         const char *import = NULL;
587         const char *scope = NULL;
588         char *full_name;
589         GModule *gmodule;
590
591         g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
592
593         if (method->addr)
594                 return method->addr;
595         if (!piinfo->implmap_idx)
596                 return NULL;
597         
598         mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
599
600         piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
601         import = mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]);
602         scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME);
603         scope = mono_metadata_string_heap (image, scope_token);
604
605         mono_dllmap_lookup (scope, import, &scope, &import);
606
607         full_name = g_module_build_path (NULL, scope);
608         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
609
610         if (!gmodule) {
611                 g_free (full_name);
612                 full_name = g_module_build_path (".", scope);
613                 gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
614         }
615
616         if (!gmodule) {
617                 gchar *error = g_strdup (g_module_error ());
618                 if (!(gmodule=g_module_open (scope, G_MODULE_BIND_LAZY))) {
619                         g_warning ("Failed to load library %s (%s): %s", full_name, scope, error);
620                         g_free (error);
621                         g_free (full_name);
622                         return NULL;
623                 }
624                 g_free (error);
625         }
626         g_free (full_name);
627
628         if (piinfo->piflags & PINVOKE_ATTRIBUTE_NO_MANGLE) {
629                 g_module_symbol (gmodule, import, &method->addr); 
630         } else {
631                 char *mangled_name;
632
633                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
634                 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
635                         mangled_name = g_strconcat (import, "W", NULL);
636                         g_module_symbol (gmodule, mangled_name, &method->addr); 
637                         g_free (mangled_name);
638
639                         if (!method->addr)
640                                 g_module_symbol (gmodule, import, &method->addr); 
641                         break;
642                 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
643                         g_module_symbol (gmodule, import, &method->addr); 
644                         break;
645                 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
646                 default:
647                         mangled_name = g_strconcat (import, "A", NULL);
648                         g_module_symbol (gmodule, mangled_name, &method->addr); 
649                         g_free (mangled_name);
650
651                         if (!method->addr)
652                                 g_module_symbol (gmodule, import, &method->addr); 
653                                
654                         break;                                  
655                 }
656         }
657
658         if (!method->addr) {
659                 g_warning ("Failed to load function %s from %s", import, scope);
660                 return NULL;
661         }
662         return method->addr;
663 }
664
665 static MonoMethod *
666 mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass)
667 {
668         MonoMethod *result;
669         int table = mono_metadata_token_table (token);
670         int idx = mono_metadata_token_index (token);
671         MonoTableInfo *tables = image->tables;
672         const char *loc, *sig = NULL;
673         int size, i;
674         guint32 cols [MONO_TYPEDEF_SIZE];
675
676         if (image->assembly->dynamic)
677                 return mono_lookup_dynamic_token (image, token);
678
679         if (table != MONO_TABLE_METHOD) {
680                 if (table == MONO_TABLE_METHODSPEC)
681                         return method_from_methodspec (image, idx);
682                 if (table != MONO_TABLE_MEMBERREF)
683                         g_print("got wrong token: 0x%08x\n", token);
684                 g_assert (table == MONO_TABLE_MEMBERREF);
685                 result = method_from_memberref (image, idx);
686
687                 return result;
688         }
689
690         mono_metadata_decode_row (&tables [table], idx - 1, cols, 6);
691
692         if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
693             (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
694                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
695         else 
696                 result = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
697         
698         result->slot = -1;
699         result->klass = klass;
700         result->flags = cols [2];
701         result->iflags = cols [1];
702         result->token = token;
703         result->name = mono_metadata_string_heap (image, cols [3]);
704
705         if (!sig) /* already taken from the methodref */
706                 sig = mono_metadata_blob_heap (image, cols [4]);
707         size = mono_metadata_decode_blob_size (sig, &sig);
708         result->signature = mono_metadata_parse_method_signature (image, idx, sig, NULL);
709
710         if (!result->klass) {
711                 guint32 type = mono_metadata_typedef_from_method (image, token);
712                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
713         }
714
715         if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
716                 if (result->klass == mono_defaults.string_class && !strcmp (result->name, ".ctor"))
717                         result->string_ctor = 1;
718
719                 result->signature->pinvoke = 1;
720         } else if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
721                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)result;
722                 MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
723                 MonoCallConvention conv;
724
725                 result->signature->pinvoke = 1;
726                 piinfo->implmap_idx = mono_metadata_implmap_from_method (image, idx - 1);
727                 piinfo->piflags = mono_metadata_decode_row_col (im, piinfo->implmap_idx - 1, MONO_IMPLMAP_FLAGS);
728
729                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CALL_CONV_MASK) {
730                 case PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI:
731                         conv = MONO_CALL_DEFAULT;
732                         break;
733                 case PINVOKE_ATTRIBUTE_CALL_CONV_CDECL:
734                         conv = MONO_CALL_C;
735                         break;
736                 case PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL:
737                         conv = MONO_CALL_STDCALL;
738                         break;
739                 case PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL:
740                         conv = MONO_CALL_THISCALL;
741                         break;
742                 case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL:
743                         conv = MONO_CALL_FASTCALL;
744                         break;
745                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC:
746                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST:
747                 default:
748                         g_warning ("unsupported calling convention");
749                         g_assert_not_reached ();
750                 }       
751                 result->signature->call_convention = conv;
752         } else {
753                 /* if this is a methodref from another module/assembly, this fails */
754                 loc = mono_cli_rva_map ((MonoCLIImageInfo *)image->image_info, cols [0]);
755
756                 if (!result->klass->dummy && !(result->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
757                                         !(result->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
758                         MonoMethodNormal *mn = (MonoMethodNormal *) result;
759
760                         g_assert (loc);
761                         mn->header = mono_metadata_parse_mh (image, loc);
762
763                         if (result->signature->generic_param_count) {
764                                 mn->header->gen_params = mono_metadata_load_generic_params (image, token, NULL);
765
766                                 for (i = 0; i < result->signature->generic_param_count; i++)
767                                         mn->header->gen_params [i].method = result;
768                         }
769                 }
770         }
771
772         return result;
773 }
774
775 MonoMethod *
776 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
777 {
778         MonoMethod *result;
779
780         /* We do everything inside the lock to prevent creation races */
781
782         mono_loader_lock ();
783
784         if ((result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token)))) {
785                 mono_loader_unlock ();
786                 return result;
787         }
788
789         result = mono_get_method_from_token (image, token, klass);
790
791         g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
792
793         mono_loader_unlock ();
794
795         return result;
796 }
797
798 void
799 mono_free_method  (MonoMethod *method)
800 {
801         mono_metadata_free_method_signature (method->signature);
802         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
803                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
804                 g_free (piinfo->code);
805         } else if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
806                 mono_metadata_free_mh (((MonoMethodNormal *)method)->header);
807         }
808
809         g_free (method);
810 }
811
812 void
813 mono_method_get_param_names (MonoMethod *method, const char **names)
814 {
815         int i, lastp;
816         MonoClass *klass = method->klass;
817         MonoTableInfo *methodt;
818         MonoTableInfo *paramt;
819
820         if (!method->signature->param_count)
821                 return;
822         for (i = 0; i < method->signature->param_count; ++i)
823                 names [i] = "";
824
825         mono_class_init (klass);
826
827         if (klass->wastypebuilder || klass->generic_inst) /* copy the names later */
828                 return;
829
830         if (klass->image->assembly->dynamic) {
831                 MonoReflectionMethodAux *method_aux = 
832                         mono_g_hash_table_lookup (
833                                 ((MonoDynamicAssembly*)method->klass->image->assembly->dynamic)->method_aux_hash, method);
834                 if (method_aux && method_aux->param_names) {
835                         for (i = 0; i < method->signature->param_count; ++i)
836                                 if (method_aux->param_names [i])
837                                         names [i] = method_aux->param_names [i];
838                 }
839                 return;
840         }
841
842         methodt = &klass->image->tables [MONO_TABLE_METHOD];
843         paramt = &klass->image->tables [MONO_TABLE_PARAM];
844         for (i = 0; i < klass->method.count; ++i) {
845                 if (method == klass->methods [i]) {
846                         guint32 idx = klass->method.first + i;
847                         guint32 cols [MONO_PARAM_SIZE];
848                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
849
850                         if (idx + 1 < methodt->rows)
851                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
852                         else
853                                 lastp = paramt->rows + 1;
854                         for (i = param_index; i < lastp; ++i) {
855                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
856                                 if (cols [MONO_PARAM_SEQUENCE]) /* skip return param spec */
857                                         names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass->image, cols [MONO_PARAM_NAME]);
858                         }
859                         return;
860                 }
861         }
862 }
863
864 void
865 mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs)
866 {
867         int i, lastp;
868         MonoClass *klass = method->klass;
869         MonoTableInfo *methodt;
870         MonoTableInfo *paramt;
871
872         for (i = 0; i < method->signature->param_count + 1; ++i)
873                 mspecs [i] = NULL;
874
875         if (method->klass->image->assembly->dynamic) {
876                 MonoReflectionMethodAux *method_aux = 
877                         mono_g_hash_table_lookup (
878                                 ((MonoDynamicAssembly*)method->klass->image->assembly->dynamic)->method_aux_hash, method);
879                 if (method_aux && method_aux->param_marshall) {
880                         MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
881                         for (i = 0; i < method->signature->param_count + 1; ++i)
882                                 if (dyn_specs [i]) {
883                                         mspecs [i] = g_new0 (MonoMarshalSpec, 1);
884                                         memcpy (mspecs [i], dyn_specs [i], sizeof (MonoMarshalSpec));
885                                 }
886                 }
887                 return;
888         }
889
890         mono_class_init (klass);
891
892         methodt = &klass->image->tables [MONO_TABLE_METHOD];
893         paramt = &klass->image->tables [MONO_TABLE_PARAM];
894
895         for (i = 0; i < klass->method.count; ++i) {
896                 if (method == klass->methods [i]) {
897                         guint32 idx = klass->method.first + i;
898                         guint32 cols [MONO_PARAM_SIZE];
899                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
900
901                         if (idx + 1 < methodt->rows)
902                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
903                         else
904                                 lastp = paramt->rows + 1;
905
906                         for (i = param_index; i < lastp; ++i) {
907                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
908
909                                 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) {
910                                         const char *tp;
911                                         tp = mono_metadata_get_marshal_info (klass->image, i - 1, FALSE);
912                                         g_assert (tp);
913                                         mspecs [cols [MONO_PARAM_SEQUENCE]]= mono_metadata_parse_marshal_spec (klass->image, tp);
914                                 }
915                         }
916
917                         return;
918                 }
919         }
920 }
921
922 gboolean
923 mono_method_has_marshal_info (MonoMethod *method)
924 {
925         int i, lastp;
926         MonoClass *klass = method->klass;
927         MonoTableInfo *methodt;
928         MonoTableInfo *paramt;
929
930         if (method->klass->image->assembly->dynamic) {
931                 MonoReflectionMethodAux *method_aux = 
932                         mono_g_hash_table_lookup (
933                                 ((MonoDynamicAssembly*)method->klass->image->assembly->dynamic)->method_aux_hash, method);
934                 MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
935                 if (dyn_specs) {
936                         for (i = 0; i < method->signature->param_count + 1; ++i)
937                                 if (dyn_specs [i])
938                                         return TRUE;
939                 }
940                 return FALSE;
941         }
942
943         mono_class_init (klass);
944
945         methodt = &klass->image->tables [MONO_TABLE_METHOD];
946         paramt = &klass->image->tables [MONO_TABLE_PARAM];
947
948         for (i = 0; i < klass->method.count; ++i) {
949                 if (method == klass->methods [i]) {
950                         guint32 idx = klass->method.first + i;
951                         guint32 cols [MONO_PARAM_SIZE];
952                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
953
954                         if (idx + 1 < methodt->rows)
955                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
956                         else
957                                 lastp = paramt->rows + 1;
958
959                         for (i = param_index; i < lastp; ++i) {
960                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
961
962                                 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL)
963                                         return TRUE;
964                         }
965                         return FALSE;
966                 }
967         }
968         return FALSE;
969 }
970
971 gpointer
972 mono_method_get_wrapper_data (MonoMethod *method, guint32 id)
973 {
974         GList *l;
975         g_assert (method != NULL);
976         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
977
978         if (!(l = g_list_nth (((MonoMethodWrapper *)method)->data, id - 1)))
979                 g_assert_not_reached ();
980
981         return l->data;
982 }
983
984 static void
985 default_stack_walk (MonoStackWalk func, gpointer user_data) {
986         g_error ("stack walk not installed");
987 }
988
989 static MonoStackWalkImpl stack_walk = default_stack_walk;
990
991 void
992 mono_stack_walk (MonoStackWalk func, gpointer user_data)
993 {
994         stack_walk (func, user_data);
995 }
996
997 void
998 mono_install_stack_walk (MonoStackWalkImpl func)
999 {
1000         stack_walk = func;
1001 }
1002
1003 static gboolean
1004 last_managed (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
1005 {
1006         MonoMethod **dest = data;
1007         *dest = m;
1008         /*g_print ("In %s::%s [%d] [%d]\n", m->klass->name, m->name, no, ilo);*/
1009
1010         return managed;
1011 }
1012
1013 MonoMethod*
1014 mono_method_get_last_managed (void)
1015 {
1016         MonoMethod *m = NULL;
1017         stack_walk (last_managed, &m);
1018         return m;
1019 }
1020
1021
1022