2003-11-16 Zoltan Varga <vargaz@freemail.hu>
[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                 if (!ginst->is_open)
502                         ginst->is_open = mono_class_is_open_constructed_type (ginst->type_argv [i]);
503         }
504
505         return mono_class_inflate_generic_method (method, ginst);
506 }
507
508 typedef struct MonoDllMap MonoDllMap;
509
510 struct MonoDllMap {
511         char *name;
512         char *target;
513         char *dll;
514         MonoDllMap *next;
515 };
516
517 static GHashTable *dll_map;
518
519 int 
520 mono_dllmap_lookup (const char *dll, const char* func, const char **rdll, const char **rfunc) {
521         MonoDllMap *map, *tmp;
522
523         if (!dll_map)
524                 return 0;
525
526         mono_loader_lock ();
527
528         map = g_hash_table_lookup (dll_map, dll);
529         if (!map) {
530                 mono_loader_unlock ();
531                 return 0;
532         }
533         *rdll = map->target? map->target: dll;
534                 
535         for (tmp = map->next; tmp; tmp = tmp->next) {
536                 if (strcmp (func, tmp->name) == 0) {
537                         *rfunc = tmp->name;
538                         if (tmp->dll)
539                                 *rdll = tmp->dll;
540                         mono_loader_unlock ();
541                         return 1;
542                 }
543         }
544         *rfunc = func;
545         mono_loader_unlock ();
546         return 1;
547 }
548
549 void
550 mono_dllmap_insert (const char *dll, const char *func, const char *tdll, const char *tfunc) {
551         MonoDllMap *map, *entry;
552
553         mono_loader_lock ();
554
555         if (!dll_map)
556                 dll_map = g_hash_table_new (g_str_hash, g_str_equal);
557
558         map = g_hash_table_lookup (dll_map, dll);
559         if (!map) {
560                 map = g_new0 (MonoDllMap, 1);
561                 map->dll = g_strdup (dll);
562                 if (tdll)
563                         map->target = g_strdup (tdll);
564                 g_hash_table_insert (dll_map, map->dll, map);
565         }
566         if (func) {
567                 entry = g_new0 (MonoDllMap, 1);
568                 entry->name = g_strdup (func);
569                 if (tfunc)
570                         entry->target = g_strdup (tfunc);
571                 if (tdll && map->target && strcmp (map->target, tdll))
572                         entry->dll = g_strdup (tdll);
573                 entry->next = map->next;
574                 map->next = entry;
575         }
576
577         mono_loader_unlock ();
578 }
579
580 gpointer
581 mono_lookup_pinvoke_call (MonoMethod *method)
582 {
583         MonoImage *image = method->klass->image;
584         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
585         MonoTableInfo *tables = image->tables;
586         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
587         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
588         guint32 im_cols [MONO_IMPLMAP_SIZE];
589         guint32 scope_token;
590         const char *import = NULL;
591         const char *scope = NULL;
592         char *full_name;
593         GModule *gmodule;
594
595         g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
596
597         if (method->addr)
598                 return method->addr;
599         if (!piinfo->implmap_idx)
600                 return NULL;
601         
602         mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
603
604         piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
605         import = mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]);
606         scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME);
607         scope = mono_metadata_string_heap (image, scope_token);
608
609         mono_dllmap_lookup (scope, import, &scope, &import);
610
611         full_name = g_module_build_path (NULL, scope);
612         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
613
614         if (!gmodule) {
615                 g_free (full_name);
616                 full_name = g_module_build_path (".", scope);
617                 gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
618         }
619
620         if (!gmodule) {
621                 gchar *error = g_strdup (g_module_error ());
622                 if (!(gmodule=g_module_open (scope, G_MODULE_BIND_LAZY))) {
623                         g_warning ("Failed to load library %s (%s): %s", full_name, scope, error);
624                         g_free (error);
625                         g_free (full_name);
626                         return NULL;
627                 }
628                 g_free (error);
629         }
630         g_free (full_name);
631
632         if (piinfo->piflags & PINVOKE_ATTRIBUTE_NO_MANGLE) {
633                 g_module_symbol (gmodule, import, &method->addr); 
634         } else {
635                 char *mangled_name;
636
637                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
638                 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
639                         mangled_name = g_strconcat (import, "W", NULL);
640                         g_module_symbol (gmodule, mangled_name, &method->addr); 
641                         g_free (mangled_name);
642
643                         if (!method->addr)
644                                 g_module_symbol (gmodule, import, &method->addr); 
645                         break;
646                 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
647                         g_module_symbol (gmodule, import, &method->addr); 
648                         break;
649                 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
650                 default:
651                         mangled_name = g_strconcat (import, "A", NULL);
652                         g_module_symbol (gmodule, mangled_name, &method->addr); 
653                         g_free (mangled_name);
654
655                         if (!method->addr)
656                                 g_module_symbol (gmodule, import, &method->addr); 
657                                
658                         break;                                  
659                 }
660         }
661
662         if (!method->addr) {
663                 g_warning ("Failed to load function %s from %s", import, scope);
664                 return NULL;
665         }
666         return method->addr;
667 }
668
669 static MonoMethod *
670 mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass)
671 {
672         MonoMethod *result;
673         int table = mono_metadata_token_table (token);
674         int idx = mono_metadata_token_index (token);
675         MonoTableInfo *tables = image->tables;
676         const char *loc, *sig = NULL;
677         int size, i;
678         guint32 cols [MONO_TYPEDEF_SIZE];
679
680         if (image->assembly->dynamic)
681                 return mono_lookup_dynamic_token (image, token);
682
683         if (table != MONO_TABLE_METHOD) {
684                 if (table == MONO_TABLE_METHODSPEC)
685                         return method_from_methodspec (image, idx);
686                 if (table != MONO_TABLE_MEMBERREF)
687                         g_print("got wrong token: 0x%08x\n", token);
688                 g_assert (table == MONO_TABLE_MEMBERREF);
689                 result = method_from_memberref (image, idx);
690
691                 return result;
692         }
693
694         mono_metadata_decode_row (&tables [table], idx - 1, cols, 6);
695
696         if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
697             (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
698                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
699         else 
700                 result = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
701         
702         result->slot = -1;
703         result->klass = klass;
704         result->flags = cols [2];
705         result->iflags = cols [1];
706         result->token = token;
707         result->name = mono_metadata_string_heap (image, cols [3]);
708
709         if (!sig) /* already taken from the methodref */
710                 sig = mono_metadata_blob_heap (image, cols [4]);
711         size = mono_metadata_decode_blob_size (sig, &sig);
712         result->signature = mono_metadata_parse_method_signature (image, idx, sig, NULL);
713
714         if (!result->klass) {
715                 guint32 type = mono_metadata_typedef_from_method (image, token);
716                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
717         }
718
719         if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
720                 if (result->klass == mono_defaults.string_class && !strcmp (result->name, ".ctor"))
721                         result->string_ctor = 1;
722
723                 result->signature->pinvoke = 1;
724         } else if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
725                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)result;
726                 MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
727                 MonoCallConvention conv;
728
729                 result->signature->pinvoke = 1;
730                 piinfo->implmap_idx = mono_metadata_implmap_from_method (image, idx - 1);
731                 piinfo->piflags = mono_metadata_decode_row_col (im, piinfo->implmap_idx - 1, MONO_IMPLMAP_FLAGS);
732
733                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CALL_CONV_MASK) {
734                 case PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI:
735                         conv = MONO_CALL_DEFAULT;
736                         break;
737                 case PINVOKE_ATTRIBUTE_CALL_CONV_CDECL:
738                         conv = MONO_CALL_C;
739                         break;
740                 case PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL:
741                         conv = MONO_CALL_STDCALL;
742                         break;
743                 case PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL:
744                         conv = MONO_CALL_THISCALL;
745                         break;
746                 case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL:
747                         conv = MONO_CALL_FASTCALL;
748                         break;
749                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC:
750                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST:
751                 default:
752                         g_warning ("unsupported calling convention");
753                         g_assert_not_reached ();
754                 }       
755                 result->signature->call_convention = conv;
756         } else {
757                 /* if this is a methodref from another module/assembly, this fails */
758                 loc = mono_cli_rva_map ((MonoCLIImageInfo *)image->image_info, cols [0]);
759
760                 if (!result->klass->dummy && !(result->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
761                                         !(result->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
762                         MonoMethodNormal *mn = (MonoMethodNormal *) result;
763
764                         g_assert (loc);
765                         mn->header = mono_metadata_parse_mh (image, loc);
766
767                         if (result->signature->generic_param_count) {
768                                 mn->header->gen_params = mono_metadata_load_generic_params (image, token, NULL);
769
770                                 for (i = 0; i < result->signature->generic_param_count; i++)
771                                         mn->header->gen_params [i].method = result;
772                         }
773                 }
774         }
775
776         return result;
777 }
778
779 MonoMethod *
780 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
781 {
782         MonoMethod *result;
783
784         /* We do everything inside the lock to prevent creation races */
785
786         mono_loader_lock ();
787
788         if ((result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token)))) {
789                 mono_loader_unlock ();
790                 return result;
791         }
792
793         result = mono_get_method_from_token (image, token, klass);
794
795         g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
796
797         mono_loader_unlock ();
798
799         return result;
800 }
801
802 void
803 mono_free_method  (MonoMethod *method)
804 {
805         mono_metadata_free_method_signature (method->signature);
806         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
807                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
808                 g_free (piinfo->code);
809         } else if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
810                 mono_metadata_free_mh (((MonoMethodNormal *)method)->header);
811         }
812
813         g_free (method);
814 }
815
816 void
817 mono_method_get_param_names (MonoMethod *method, const char **names)
818 {
819         int i, lastp;
820         MonoClass *klass = method->klass;
821         MonoTableInfo *methodt;
822         MonoTableInfo *paramt;
823
824         if (!method->signature->param_count)
825                 return;
826         for (i = 0; i < method->signature->param_count; ++i)
827                 names [i] = "";
828
829         mono_class_init (klass);
830
831         if (klass->wastypebuilder || klass->generic_inst) /* copy the names later */
832                 return;
833
834         if (klass->image->assembly->dynamic) {
835                 MonoReflectionMethodAux *method_aux = 
836                         mono_g_hash_table_lookup (
837                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
838                 if (method_aux && method_aux->param_names) {
839                         for (i = 0; i < method->signature->param_count; ++i)
840                                 if (method_aux->param_names [i])
841                                         names [i] = method_aux->param_names [i];
842                 }
843                 return;
844         }
845
846         methodt = &klass->image->tables [MONO_TABLE_METHOD];
847         paramt = &klass->image->tables [MONO_TABLE_PARAM];
848         for (i = 0; i < klass->method.count; ++i) {
849                 if (method == klass->methods [i]) {
850                         guint32 idx = klass->method.first + i;
851                         guint32 cols [MONO_PARAM_SIZE];
852                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
853
854                         if (idx + 1 < methodt->rows)
855                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
856                         else
857                                 lastp = paramt->rows + 1;
858                         for (i = param_index; i < lastp; ++i) {
859                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
860                                 if (cols [MONO_PARAM_SEQUENCE]) /* skip return param spec */
861                                         names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass->image, cols [MONO_PARAM_NAME]);
862                         }
863                         return;
864                 }
865         }
866 }
867
868 void
869 mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs)
870 {
871         int i, lastp;
872         MonoClass *klass = method->klass;
873         MonoTableInfo *methodt;
874         MonoTableInfo *paramt;
875
876         for (i = 0; i < method->signature->param_count + 1; ++i)
877                 mspecs [i] = NULL;
878
879         if (method->klass->image->assembly->dynamic) {
880                 MonoReflectionMethodAux *method_aux = 
881                         mono_g_hash_table_lookup (
882                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
883                 if (method_aux && method_aux->param_marshall) {
884                         MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
885                         for (i = 0; i < method->signature->param_count + 1; ++i)
886                                 if (dyn_specs [i]) {
887                                         mspecs [i] = g_new0 (MonoMarshalSpec, 1);
888                                         memcpy (mspecs [i], dyn_specs [i], sizeof (MonoMarshalSpec));
889                                 }
890                 }
891                 return;
892         }
893
894         mono_class_init (klass);
895
896         methodt = &klass->image->tables [MONO_TABLE_METHOD];
897         paramt = &klass->image->tables [MONO_TABLE_PARAM];
898
899         for (i = 0; i < klass->method.count; ++i) {
900                 if (method == klass->methods [i]) {
901                         guint32 idx = klass->method.first + i;
902                         guint32 cols [MONO_PARAM_SIZE];
903                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
904
905                         if (idx + 1 < methodt->rows)
906                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
907                         else
908                                 lastp = paramt->rows + 1;
909
910                         for (i = param_index; i < lastp; ++i) {
911                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
912
913                                 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) {
914                                         const char *tp;
915                                         tp = mono_metadata_get_marshal_info (klass->image, i - 1, FALSE);
916                                         g_assert (tp);
917                                         mspecs [cols [MONO_PARAM_SEQUENCE]]= mono_metadata_parse_marshal_spec (klass->image, tp);
918                                 }
919                         }
920
921                         return;
922                 }
923         }
924 }
925
926 gboolean
927 mono_method_has_marshal_info (MonoMethod *method)
928 {
929         int i, lastp;
930         MonoClass *klass = method->klass;
931         MonoTableInfo *methodt;
932         MonoTableInfo *paramt;
933
934         if (method->klass->image->assembly->dynamic) {
935                 MonoReflectionMethodAux *method_aux = 
936                         mono_g_hash_table_lookup (
937                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
938                 MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
939                 if (dyn_specs) {
940                         for (i = 0; i < method->signature->param_count + 1; ++i)
941                                 if (dyn_specs [i])
942                                         return TRUE;
943                 }
944                 return FALSE;
945         }
946
947         mono_class_init (klass);
948
949         methodt = &klass->image->tables [MONO_TABLE_METHOD];
950         paramt = &klass->image->tables [MONO_TABLE_PARAM];
951
952         for (i = 0; i < klass->method.count; ++i) {
953                 if (method == klass->methods [i]) {
954                         guint32 idx = klass->method.first + i;
955                         guint32 cols [MONO_PARAM_SIZE];
956                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
957
958                         if (idx + 1 < methodt->rows)
959                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
960                         else
961                                 lastp = paramt->rows + 1;
962
963                         for (i = param_index; i < lastp; ++i) {
964                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
965
966                                 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL)
967                                         return TRUE;
968                         }
969                         return FALSE;
970                 }
971         }
972         return FALSE;
973 }
974
975 gpointer
976 mono_method_get_wrapper_data (MonoMethod *method, guint32 id)
977 {
978         GList *l;
979         g_assert (method != NULL);
980         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
981
982         if (!(l = g_list_nth (((MonoMethodWrapper *)method)->data, id - 1)))
983                 g_assert_not_reached ();
984
985         return l->data;
986 }
987
988 static void
989 default_stack_walk (MonoStackWalk func, gpointer user_data) {
990         g_error ("stack walk not installed");
991 }
992
993 static MonoStackWalkImpl stack_walk = default_stack_walk;
994
995 void
996 mono_stack_walk (MonoStackWalk func, gpointer user_data)
997 {
998         stack_walk (func, user_data);
999 }
1000
1001 void
1002 mono_install_stack_walk (MonoStackWalkImpl func)
1003 {
1004         stack_walk = func;
1005 }
1006
1007 static gboolean
1008 last_managed (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
1009 {
1010         MonoMethod **dest = data;
1011         *dest = m;
1012         /*g_print ("In %s::%s [%d] [%d]\n", m->klass->name, m->name, no, ilo);*/
1013
1014         return managed;
1015 }
1016
1017 MonoMethod*
1018 mono_method_get_last_managed (void)
1019 {
1020         MonoMethod *m = NULL;
1021         stack_walk (last_managed, &m);
1022         return m;
1023 }
1024
1025
1026