2003-08-27 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                 return mono_class_get_field_from_name (klass, fname);
188         }
189         default:
190                 g_warning ("field load from %x", class);
191                 return NULL;
192         }
193 }
194
195 MonoClassField*
196 mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass)
197 {
198         MonoClass *k;
199         guint32 type;
200
201         if (image->assembly->dynamic) {
202                 MonoClassField *result = mono_lookup_dynamic_token (image, token);
203                 *retklass = result->parent;
204                 return result;
205         }
206
207         if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
208                 return mono_field_from_memberref (image, token, retklass);
209
210         type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
211         if (!type)
212                 return NULL;
213         k = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
214         mono_class_init (k);
215         if (!k)
216                 return NULL;
217         if (retklass)
218                 *retklass = k;
219         return mono_class_get_field (k, token);
220 }
221
222 static gboolean
223 mono_metadata_signature_vararg_match (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
224 {
225         int i;
226
227         if (sig1->hasthis != sig2->hasthis ||
228             sig1->sentinelpos != sig2->sentinelpos)
229                 return FALSE;
230
231         for (i = 0; i < sig1->sentinelpos; i++) { 
232                 MonoType *p1 = sig1->params[i];
233                 MonoType *p2 = sig2->params[i];
234                 
235                 //if (p1->attrs != p2->attrs)
236                 //      return FALSE;
237                 
238                 if (!mono_metadata_type_equal (p1, p2))
239                         return FALSE;
240         }
241
242         if (!mono_metadata_type_equal (sig1->ret, sig2->ret))
243                 return FALSE;
244         return TRUE;
245 }
246
247 static MonoMethod *
248 find_method (MonoClass *klass, const char* name, MonoMethodSignature *sig)
249 {
250         int i;
251         MonoClass *sclass = klass;
252         
253         if (sig->call_convention == MONO_CALL_VARARG) {
254                 while (klass) {
255                         /* mostly dumb search for now */
256                         for (i = 0; i < klass->method.count; ++i) {
257                                 MonoMethod *m = klass->methods [i];
258                                 if (!strcmp (name, m->name)) {
259                                         if (mono_metadata_signature_vararg_match (sig, m->signature))
260                                                 return m;
261                                 }
262                         }
263                         if (name [0] == '.' && (strcmp (name, ".ctor") == 0 || strcmp (name, ".cctor") == 0))
264                                 break;
265                         klass = klass->parent;
266                 }
267                 return NULL;
268         }
269         while (klass) {
270                 /* mostly dumb search for now */
271                 for (i = 0; i < klass->method.count; ++i) {
272                         MonoMethod *m = klass->methods [i];
273                         if (!strcmp (name, m->name)) {
274                                 if (mono_metadata_signature_equal (sig, m->signature))
275                                         return m;
276                         }
277                 }
278                 if (name [0] == '.' && (strcmp (name, ".ctor") == 0 || strcmp (name, ".cctor") == 0))
279                         break;
280                 klass = klass->parent;
281         }
282         if (sclass->generic_inst) {
283                 MonoClass *gclass = mono_class_from_mono_type (sclass->generic_inst->data.generic_inst->generic_type);
284                 MonoMethod *res = find_method (gclass, name, sig);
285                 if (!res)
286                         return NULL;
287                 for (i = 0; i < res->klass->method.count; ++i) {
288                         if (res == res->klass->methods [i]) {
289                                 return sclass->methods [i];
290                         }
291                 }
292         }
293         return NULL;
294
295 }
296
297 /*
298  * token is the method_ref or method_def token used in a call IL instruction.
299  */
300 MonoMethodSignature*
301 mono_method_get_signature (MonoMethod *method, MonoImage *image, guint32 token)
302 {
303         int table = mono_metadata_token_table (token);
304         int idx = mono_metadata_token_index (token);
305         guint32 cols [MONO_MEMBERREF_SIZE];
306         MonoMethodSignature *sig;
307         const char *ptr;
308
309         /* !table is for wrappers: we should really assign their own token to them */
310         if (!table || table == MONO_TABLE_METHOD)
311                 return method->signature;
312
313         if (method->klass->generic_inst)
314                 return method->signature;
315
316         if (image->assembly->dynamic)
317                 /* FIXME: This might be incorrect for vararg methods */
318                 return method->signature;
319
320         mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
321         
322         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
323         mono_metadata_decode_blob_size (ptr, &ptr);
324         sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
325
326         return sig;
327 }
328
329 static MonoMethod *
330 method_from_memberref (MonoImage *image, guint32 idx)
331 {
332         MonoClass *klass;
333         MonoMethod *method;
334         MonoTableInfo *tables = image->tables;
335         guint32 cols[6];
336         guint32 nindex, class;
337         const char *mname;
338         MonoMethodSignature *sig;
339         const char *ptr;
340
341         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
342         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
343         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
344         /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
345                 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
346
347         mname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
348         
349         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
350         mono_metadata_decode_blob_size (ptr, &ptr);
351         sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
352
353         switch (class) {
354         case MEMBERREF_PARENT_TYPEREF:
355                 klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
356                 if (!klass) {
357                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
358                         mono_metadata_free_method_signature (sig);
359                         return NULL;
360                 }
361                 mono_class_init (klass);
362                 method = find_method (klass, mname, sig);
363                 if (!method)
364                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
365                 mono_metadata_free_method_signature (sig);
366                 return method;
367         case MEMBERREF_PARENT_TYPESPEC: {
368                 guint32 bcols [MONO_TYPESPEC_SIZE];
369                 guint32 len;
370                 MonoType *type;
371                 MonoMethod *result;
372
373                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
374                                           bcols, MONO_TYPESPEC_SIZE);
375                 ptr = mono_metadata_blob_heap (image, bcols [MONO_TYPESPEC_SIGNATURE]);
376                 len = mono_metadata_decode_value (ptr, &ptr);   
377                 type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
378
379                 if (type->type != MONO_TYPE_ARRAY && type->type != MONO_TYPE_SZARRAY) {
380                         klass = mono_class_from_mono_type (type);
381                         mono_class_init (klass);
382                         method = find_method (klass, mname, sig);
383                         if (!method)
384                                 g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
385                         mono_metadata_free_method_signature (sig);
386                         return method;
387                 }
388
389                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
390                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_SPEC | nindex);
391                 result->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
392                 result->signature = sig;
393                 result->name = mname;
394
395                 if (!strcmp (mname, ".ctor")) {
396                         /* we special-case this in the runtime. */
397                         result->addr = NULL;
398                         return result;
399                 }
400                 
401                 if (!strcmp (mname, "Set")) {
402                         g_assert (sig->hasthis);
403                         g_assert (type->data.array->rank + 1 == sig->param_count);
404                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
405                         result->addr = NULL;
406                         return result;
407                 }
408
409                 if (!strcmp (mname, "Get")) {
410                         g_assert (sig->hasthis);
411                         g_assert (type->data.array->rank == sig->param_count);
412                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
413                         result->addr = NULL;
414                         return result;
415                 }
416
417                 if (!strcmp (mname, "Address")) {
418                         g_assert (sig->hasthis);
419                         g_assert (type->data.array->rank == sig->param_count);
420                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
421                         result->addr = NULL;
422                         return result;
423                 }
424
425                 g_assert_not_reached ();
426                 break;
427         }
428         case MEMBERREF_PARENT_TYPEDEF:
429                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex);
430                 if (!klass) {
431                         g_warning ("Missing method %s in assembly %s typedef index %d", mname, image->name, nindex);
432                         mono_metadata_free_method_signature (sig);
433                         return NULL;
434                 }
435                 mono_class_init (klass);
436                 method = find_method (klass, mname, sig);
437                 if (!method)
438                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
439                 mono_metadata_free_method_signature (sig);
440                 return method;
441         case MEMBERREF_PARENT_METHODDEF:
442                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | nindex, NULL);
443                 return method;
444         default:
445                 g_error ("Memberref parent unknown: class: %d, index %d", class, nindex);
446                 g_assert_not_reached ();
447         }
448
449         return NULL;
450 }
451
452 typedef struct MonoDllMap MonoDllMap;
453
454 struct MonoDllMap {
455         char *name;
456         char *target;
457         char *dll;
458         MonoDllMap *next;
459 };
460
461 static GHashTable *dll_map;
462
463 int 
464 mono_dllmap_lookup (const char *dll, const char* func, const char **rdll, const char **rfunc) {
465         MonoDllMap *map, *tmp;
466
467         if (!dll_map)
468                 return 0;
469
470         mono_loader_lock ();
471
472         map = g_hash_table_lookup (dll_map, dll);
473         if (!map) {
474                 mono_loader_unlock ();
475                 return 0;
476         }
477         *rdll = map->target? map->target: dll;
478                 
479         for (tmp = map->next; tmp; tmp = tmp->next) {
480                 if (strcmp (func, tmp->name) == 0) {
481                         *rfunc = tmp->name;
482                         if (tmp->dll)
483                                 *rdll = tmp->dll;
484                         mono_loader_unlock ();
485                         return 1;
486                 }
487         }
488         *rfunc = func;
489         mono_loader_unlock ();
490         return 1;
491 }
492
493 void
494 mono_dllmap_insert (const char *dll, const char *func, const char *tdll, const char *tfunc) {
495         MonoDllMap *map, *entry;
496
497         mono_loader_lock ();
498
499         if (!dll_map)
500                 dll_map = g_hash_table_new (g_str_hash, g_str_equal);
501
502         map = g_hash_table_lookup (dll_map, dll);
503         if (!map) {
504                 map = g_new0 (MonoDllMap, 1);
505                 map->dll = g_strdup (dll);
506                 if (tdll)
507                         map->target = g_strdup (tdll);
508                 g_hash_table_insert (dll_map, map->dll, map);
509         }
510         if (func) {
511                 entry = g_new0 (MonoDllMap, 1);
512                 entry->name = g_strdup (func);
513                 if (tfunc)
514                         entry->target = g_strdup (tfunc);
515                 if (tdll && map->target && strcmp (map->target, tdll))
516                         entry->dll = g_strdup (tdll);
517                 entry->next = map->next;
518                 map->next = entry;
519         }
520
521         mono_loader_unlock ();
522 }
523
524 gpointer
525 mono_lookup_pinvoke_call (MonoMethod *method)
526 {
527         MonoImage *image = method->klass->image;
528         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
529         MonoTableInfo *tables = image->tables;
530         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
531         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
532         guint32 im_cols [MONO_IMPLMAP_SIZE];
533         guint32 scope_token;
534         const char *import = NULL;
535         const char *scope = NULL;
536         char *full_name;
537         GModule *gmodule;
538
539         g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
540
541         if (method->addr)
542                 return method->addr;
543         if (!piinfo->implmap_idx)
544                 return NULL;
545         
546         mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
547
548         piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
549         import = mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]);
550         scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME);
551         scope = mono_metadata_string_heap (image, scope_token);
552
553         mono_dllmap_lookup (scope, import, &scope, &import);
554
555         full_name = g_module_build_path (NULL, scope);
556         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
557
558         if (!gmodule) {
559                 g_free (full_name);
560                 full_name = g_module_build_path (".", scope);
561                 gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
562         }
563
564         if (!gmodule) {
565                 gchar *error = g_strdup (g_module_error ());
566                 if (!(gmodule=g_module_open (scope, G_MODULE_BIND_LAZY))) {
567                         g_warning ("Failed to load library %s (%s): %s", full_name, scope, error);
568                         g_free (error);
569                         g_free (full_name);
570                         return NULL;
571                 }
572                 g_free (error);
573         }
574         g_free (full_name);
575
576         if (piinfo->piflags & PINVOKE_ATTRIBUTE_NO_MANGLE) {
577                 g_module_symbol (gmodule, import, &method->addr); 
578         } else {
579                 char *mangled_name;
580
581                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
582                 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
583                         mangled_name = g_strconcat (import, "W", NULL);
584                         g_module_symbol (gmodule, mangled_name, &method->addr); 
585                         g_free (mangled_name);
586
587                         if (!method->addr)
588                                 g_module_symbol (gmodule, import, &method->addr); 
589                         break;
590                 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
591                         g_module_symbol (gmodule, import, &method->addr); 
592                         break;
593                 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
594                 default:
595                         mangled_name = g_strconcat (import, "A", NULL);
596                         g_module_symbol (gmodule, mangled_name, &method->addr); 
597                         g_free (mangled_name);
598
599                         if (!method->addr)
600                                 g_module_symbol (gmodule, import, &method->addr); 
601                                
602                         break;                                  
603                 }
604         }
605
606         if (!method->addr) {
607                 g_warning ("Failed to load function %s from %s", import, scope);
608                 return NULL;
609         }
610         return method->addr;
611 }
612
613 static MonoMethod *
614 mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass)
615 {
616         MonoMethod *result;
617         int table = mono_metadata_token_table (token);
618         int idx = mono_metadata_token_index (token);
619         MonoTableInfo *tables = image->tables;
620         const char *loc, *sig = NULL;
621         int size;
622         guint32 cols [MONO_TYPEDEF_SIZE];
623
624         if (image->assembly->dynamic)
625                 return mono_lookup_dynamic_token (image, token);
626
627         if (table != MONO_TABLE_METHOD) {
628                 if (table == MONO_TABLE_METHODSPEC) {
629                         /* just a temporary hack */
630                         mono_metadata_decode_row (&tables [table], idx - 1, cols, MONO_METHODSPEC_SIZE);
631                         token = cols [MONO_METHODSPEC_METHOD];
632                         if ((token & METHODDEFORREF_MASK) == METHODDEFORREF_METHODDEF)
633                                 token = MONO_TOKEN_METHOD_DEF | (token >> METHODDEFORREF_BITS);
634                         else
635                                 token = MONO_TOKEN_MEMBER_REF | (token >> METHODDEFORREF_BITS);
636                         return mono_get_method (image, token, klass);
637                 }
638                 if (table != MONO_TABLE_MEMBERREF)
639                         g_print("got wrong token: 0x%08x\n", token);
640                 g_assert (table == MONO_TABLE_MEMBERREF);
641                 result = method_from_memberref (image, idx);
642
643                 return result;
644         }
645
646         mono_metadata_decode_row (&tables [table], idx - 1, cols, 6);
647
648         if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
649             (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
650                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
651         else 
652                 result = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
653         
654         result->slot = -1;
655         result->klass = klass;
656         result->flags = cols [2];
657         result->iflags = cols [1];
658         result->token = token;
659         result->name = mono_metadata_string_heap (image, cols [3]);
660
661         if (!sig) /* already taken from the methodref */
662                 sig = mono_metadata_blob_heap (image, cols [4]);
663         size = mono_metadata_decode_blob_size (sig, &sig);
664         result->signature = mono_metadata_parse_method_signature (image, idx, sig, NULL);
665
666         if (!result->klass) {
667                 guint32 type = mono_metadata_typedef_from_method (image, token);
668                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
669         }
670
671         if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
672                 if (result->klass == mono_defaults.string_class && !strcmp (result->name, ".ctor"))
673                         result->string_ctor = 1;
674
675                 result->addr = mono_lookup_internal_call (result);
676                 result->signature->pinvoke = 1;
677         } else if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
678                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)result;
679                 MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
680                 MonoCallConvention conv;
681
682                 result->signature->pinvoke = 1;
683                 piinfo->implmap_idx = mono_metadata_implmap_from_method (image, idx - 1);
684                 piinfo->piflags = mono_metadata_decode_row_col (im, piinfo->implmap_idx - 1, MONO_IMPLMAP_FLAGS);
685
686                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CALL_CONV_MASK) {
687                 case PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI:
688                         conv = MONO_CALL_DEFAULT;
689                         break;
690                 case PINVOKE_ATTRIBUTE_CALL_CONV_CDECL:
691                         conv = MONO_CALL_C;
692                         break;
693                 case PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL:
694                         conv = MONO_CALL_STDCALL;
695                         break;
696                 case PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL:
697                         conv = MONO_CALL_THISCALL;
698                         break;
699                 case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL:
700                         conv = MONO_CALL_FASTCALL;
701                         break;
702                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC:
703                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST:
704                 default:
705                         g_warning ("unsupported calling convention");
706                         g_assert_not_reached ();
707                 }       
708                 result->signature->call_convention = conv;
709         } else {
710                 /* if this is a methodref from another module/assembly, this fails */
711                 loc = mono_cli_rva_map ((MonoCLIImageInfo *)image->image_info, cols [0]);
712
713                 if (!result->klass->dummy && !(result->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
714                                         !(result->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
715                         g_assert (loc);
716                         ((MonoMethodNormal *)result)->header = mono_metadata_parse_mh (image, loc);
717                 }
718         }
719
720         return result;
721 }
722
723 MonoMethod *
724 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
725 {
726         MonoMethod *result;
727
728         /* We do everything inside the lock to prevent creation races */
729
730         mono_loader_lock ();
731
732         if ((result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token)))) {
733                 mono_loader_unlock ();
734                 return result;
735         }
736
737         result = mono_get_method_from_token (image, token, klass);
738
739         g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
740
741         mono_loader_unlock ();
742
743         return result;
744 }
745
746 void
747 mono_free_method  (MonoMethod *method)
748 {
749         mono_metadata_free_method_signature (method->signature);
750         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
751                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
752                 g_free (piinfo->code);
753         } else if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
754                 mono_metadata_free_mh (((MonoMethodNormal *)method)->header);
755         }
756
757         g_free (method);
758 }
759
760 void
761 mono_method_get_param_names (MonoMethod *method, const char **names)
762 {
763         int i, lastp;
764         MonoClass *klass = method->klass;
765         MonoTableInfo *methodt;
766         MonoTableInfo *paramt;
767
768         if (!method->signature->param_count)
769                 return;
770         for (i = 0; i < method->signature->param_count; ++i)
771                 names [i] = "";
772
773         mono_class_init (klass);
774
775         if (klass->wastypebuilder) /* copy the names later */
776                 return;
777
778         methodt = &klass->image->tables [MONO_TABLE_METHOD];
779         paramt = &klass->image->tables [MONO_TABLE_PARAM];
780         for (i = 0; i < klass->method.count; ++i) {
781                 if (method == klass->methods [i]) {
782                         guint32 idx = klass->method.first + i;
783                         guint32 cols [MONO_PARAM_SIZE];
784                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
785
786                         if (idx + 1 < methodt->rows)
787                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
788                         else
789                                 lastp = paramt->rows + 1;
790                         for (i = param_index; i < lastp; ++i) {
791                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
792                                 if (cols [MONO_PARAM_SEQUENCE]) /* skip return param spec */
793                                         names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass->image, cols [MONO_PARAM_NAME]);
794                         }
795                         return;
796                 }
797         }
798 }
799
800 void
801 mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs)
802 {
803         int i, lastp;
804         MonoClass *klass = method->klass;
805         MonoTableInfo *methodt;
806         MonoTableInfo *paramt;
807
808         for (i = 0; i < method->signature->param_count + 1; ++i)
809                 mspecs [i] = NULL;
810
811         if (method->klass->image->assembly->dynamic) {
812                 MonoMarshalSpec **dyn_specs = mono_g_hash_table_lookup (
813                         ((MonoDynamicAssembly*)method->klass->image->assembly->dynamic)->param_marshalling,
814                         method);
815                 if (dyn_specs) {
816                         for (i = 0; i < method->signature->param_count + 1; ++i)
817                                 if (dyn_specs [i]) {
818                                         mspecs [i] = g_new0 (MonoMarshalSpec, 1);
819                                         memcpy (mspecs [i], dyn_specs [i], sizeof (MonoMarshalSpec));
820                                 }
821                 }
822                 return;
823         }
824
825         mono_class_init (klass);
826
827         methodt = &klass->image->tables [MONO_TABLE_METHOD];
828         paramt = &klass->image->tables [MONO_TABLE_PARAM];
829
830         for (i = 0; i < klass->method.count; ++i) {
831                 if (method == klass->methods [i]) {
832                         guint32 idx = klass->method.first + i;
833                         guint32 cols [MONO_PARAM_SIZE];
834                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
835
836                         if (idx + 1 < methodt->rows)
837                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
838                         else
839                                 lastp = paramt->rows + 1;
840
841                         for (i = param_index; i < lastp; ++i) {
842                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
843
844                                 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) {
845                                         const char *tp;
846                                         tp = mono_metadata_get_marshal_info (klass->image, i - 1, FALSE);
847                                         g_assert (tp);
848                                         mspecs [cols [MONO_PARAM_SEQUENCE]]= mono_metadata_parse_marshal_spec (klass->image, tp);
849                                 }
850                         }
851
852                         return;
853                 }
854         }
855 }
856
857 gboolean
858 mono_method_has_marshal_info (MonoMethod *method)
859 {
860         int i, lastp;
861         MonoClass *klass = method->klass;
862         MonoTableInfo *methodt;
863         MonoTableInfo *paramt;
864
865         if (method->klass->image->assembly->dynamic) {
866                 MonoMarshalSpec **dyn_specs = mono_g_hash_table_lookup (
867                         ((MonoDynamicAssembly*)method->klass->image->assembly->dynamic)->param_marshalling,
868                         method);
869                 if (dyn_specs) {
870                         for (i = 0; i < method->signature->param_count + 1; ++i)
871                                 if (dyn_specs [i])
872                                         return TRUE;
873                 }
874                 return FALSE;
875         }
876
877         mono_class_init (klass);
878
879         methodt = &klass->image->tables [MONO_TABLE_METHOD];
880         paramt = &klass->image->tables [MONO_TABLE_PARAM];
881
882         for (i = 0; i < klass->method.count; ++i) {
883                 if (method == klass->methods [i]) {
884                         guint32 idx = klass->method.first + i;
885                         guint32 cols [MONO_PARAM_SIZE];
886                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
887
888                         if (idx + 1 < methodt->rows)
889                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
890                         else
891                                 lastp = paramt->rows + 1;
892
893                         for (i = param_index; i < lastp; ++i) {
894                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
895
896                                 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL)
897                                         return TRUE;
898                         }
899                         return FALSE;
900                 }
901         }
902         return FALSE;
903 }
904
905 gpointer
906 mono_method_get_wrapper_data (MonoMethod *method, guint32 id)
907 {
908         GList *l;
909         g_assert (method != NULL);
910         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
911
912         if (!(l = g_list_nth (((MonoMethodWrapper *)method)->data, id - 1)))
913                 g_assert_not_reached ();
914
915         return l->data;
916 }
917
918 static void
919 default_stack_walk (MonoStackWalk func, gpointer user_data) {
920         g_error ("stack walk not installed");
921 }
922
923 static MonoStackWalkImpl stack_walk = default_stack_walk;
924
925 void
926 mono_stack_walk (MonoStackWalk func, gpointer user_data)
927 {
928         stack_walk (func, user_data);
929 }
930
931 void
932 mono_install_stack_walk (MonoStackWalkImpl func)
933 {
934         stack_walk = func;
935 }
936
937 static gboolean
938 last_managed (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
939 {
940         MonoMethod **dest = data;
941         *dest = m;
942         /*g_print ("In %s::%s [%d] [%d]\n", m->klass->name, m->name, no, ilo);*/
943
944         return managed;
945 }
946
947 MonoMethod*
948 mono_method_get_last_managed (void)
949 {
950         MonoMethod *m = NULL;
951         stack_walk (last_managed, &m);
952         return m;
953 }
954
955
956