Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / 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/metadata-internals.h>
32 #include <mono/metadata/loader.h>
33 #include <mono/metadata/class-internals.h>
34 #include <mono/metadata/debug-helpers.h>
35 #include <mono/metadata/reflection.h>
36 #include <mono/utils/mono-logger.h>
37
38 MonoDefaults mono_defaults;
39
40 /*
41  * This lock protects the hash tables inside MonoImage used by the metadata 
42  * loading functions in class.c and loader.c.
43  */
44 static CRITICAL_SECTION loader_mutex;
45
46 void
47 mono_loader_init ()
48 {
49         InitializeCriticalSection (&loader_mutex);
50 }
51
52 static MonoClassField*
53 field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
54                       MonoGenericContext *context)
55 {
56         MonoClass *klass;
57         MonoTableInfo *tables = image->tables;
58         guint32 cols[6];
59         guint32 nindex, class;
60         const char *fname;
61         const char *ptr;
62         guint32 idx = mono_metadata_token_index (token);
63
64         if (image->dynamic) {
65                 MonoClassField *result = mono_lookup_dynamic_token (image, token);
66                 *retklass = result->parent;
67                 return result;
68         }
69
70         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
71         nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
72         class = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
73
74         fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
75         
76         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
77         mono_metadata_decode_blob_size (ptr, &ptr);
78         /* we may want to check the signature here... */
79
80         switch (class) {
81         case MONO_MEMBERREF_PARENT_TYPEREF:
82                 klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
83                 if (!klass) {
84                         char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_REF | nindex, context);
85                         g_warning ("Missing field %s in class %s (typeref index %d)", fname, name, nindex);
86                         g_free (name);
87                         return NULL;
88                 }
89                 mono_class_init (klass);
90                 if (retklass)
91                         *retklass = klass;
92                 return mono_class_get_field_from_name (klass, fname);
93         case MONO_MEMBERREF_PARENT_TYPESPEC: {
94                 /*guint32 bcols [MONO_TYPESPEC_SIZE];
95                 guint32 len;
96                 MonoType *type;
97
98                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
99                                           bcols, MONO_TYPESPEC_SIZE);
100                 ptr = mono_metadata_blob_heap (image, bcols [MONO_TYPESPEC_SIGNATURE]);
101                 len = mono_metadata_decode_value (ptr, &ptr);   
102                 type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
103
104                 klass = mono_class_from_mono_type (type);
105                 mono_class_init (klass);
106                 g_print ("type in sig: %s\n", klass->name);*/
107                 klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, context);
108                 mono_class_init (klass);
109                 if (retklass)
110                         *retklass = klass;
111                 return mono_class_get_field_from_name (klass, fname);
112         }
113         default:
114                 g_warning ("field load from %x", class);
115                 return NULL;
116         }
117 }
118
119 MonoClassField*
120 mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass,
121                        MonoGenericContext *context)
122 {
123         MonoClass *k;
124         guint32 type;
125         MonoClassField *field;
126
127         if (image->dynamic) {
128                 MonoClassField *result = mono_lookup_dynamic_token (image, token);
129                 *retklass = result->parent;
130                 return result;
131         }
132
133         mono_loader_lock ();
134         if ((field = g_hash_table_lookup (image->field_cache, GUINT_TO_POINTER (token)))) {
135                 *retklass = field->parent;
136                 mono_loader_unlock ();
137                 return field;
138         }
139         mono_loader_unlock ();
140
141         if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
142                 field = field_from_memberref (image, token, retklass, context);
143         else {
144                 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
145                 if (!type)
146                         return NULL;
147                 k = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
148                 mono_class_init (k);
149                 if (!k)
150                         return NULL;
151                 if (retklass)
152                         *retklass = k;
153                 field = mono_class_get_field (k, token);
154         }
155
156         mono_loader_lock ();
157         if (!field->parent->generic_class)
158                 g_hash_table_insert (image->field_cache, GUINT_TO_POINTER (token), field);
159         mono_loader_unlock ();
160         return field;
161 }
162
163 static gboolean
164 mono_metadata_signature_vararg_match (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
165 {
166         int i;
167
168         if (sig1->hasthis != sig2->hasthis ||
169             sig1->sentinelpos != sig2->sentinelpos)
170                 return FALSE;
171
172         for (i = 0; i < sig1->sentinelpos; i++) { 
173                 MonoType *p1 = sig1->params[i];
174                 MonoType *p2 = sig2->params[i];
175                 
176                 /*if (p1->attrs != p2->attrs)
177                         return FALSE;
178                 */
179                 if (!mono_metadata_type_equal (p1, p2))
180                         return FALSE;
181         }
182
183         if (!mono_metadata_type_equal (sig1->ret, sig2->ret))
184                 return FALSE;
185         return TRUE;
186 }
187
188 static MonoMethod *
189 find_method_in_class (MonoClass *klass, const char *name, const char *qname,
190                       const char *fqname, MonoMethodSignature *sig)
191 {
192         MonoGenericContext *context = NULL;
193         int i;
194
195         if (klass->generic_container)
196                 context = &klass->generic_container->context;
197         else if (klass->generic_class)
198                 context = klass->generic_class->context;
199
200         mono_class_setup_methods (klass);
201         for (i = 0; i < klass->method.count; ++i) {
202                 MonoMethod *m = klass->methods [i];
203
204                 if (!((fqname && !strcmp (m->name, fqname)) ||
205                       (qname && !strcmp (m->name, qname)) || !strcmp (m->name, name)))
206                         continue;
207
208                 if (sig->call_convention == MONO_CALL_VARARG) {
209                         if (mono_metadata_signature_vararg_match (sig, mono_method_signature (m)))
210                                 return m;
211                 } else {
212                         MonoMethodSignature *msig = mono_method_signature_full (m, context);
213                         if (mono_metadata_signature_equal (sig, msig))
214                                 return m;
215                 }
216         }
217
218         return NULL;
219 }
220
221 static MonoMethod *
222 find_method (MonoClass *klass, MonoClass *ic, const char* name, MonoMethodSignature *sig)
223 {
224         int i;
225         char *qname, *fqname, *class_name;
226         gboolean is_interface;
227         MonoMethod *result = NULL;
228
229         is_interface = MONO_CLASS_IS_INTERFACE (klass);
230
231         if (ic) {
232                 class_name = mono_type_get_name_full (&ic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);
233
234                 qname = g_strconcat (class_name, ".", name, NULL); 
235                 if (ic->name_space && ic->name_space [0])
236                         fqname = g_strconcat (ic->name_space, ".", class_name, ".", name, NULL);
237                 else
238                         fqname = NULL;
239         } else
240                 class_name = qname = fqname = NULL;
241
242         while (klass) {
243                 result = find_method_in_class (klass, name, qname, fqname, sig);
244                 if (result)
245                         goto out;
246
247                 if (name [0] == '.' && (!strcmp (name, ".ctor") || !strcmp (name, ".cctor")))
248                         break;
249
250                 for (i = 0; i < klass->interface_count; i++) {
251                         MonoClass *ic = klass->interfaces [i];
252
253                         result = find_method_in_class (ic, name, qname, fqname, sig);
254                         if (result)
255                                 goto out;
256                 }
257
258                 klass = klass->parent;
259         }
260
261         if (is_interface)
262                 result = find_method_in_class (mono_defaults.object_class, name, qname, fqname, sig);
263
264  out:
265         g_free (class_name);
266         g_free (fqname);
267         g_free (qname);
268         return result;
269 }
270
271 /*
272  * token is the method_ref or method_def token used in a call IL instruction.
273  */
274 MonoMethodSignature*
275 mono_method_get_signature_full (MonoMethod *method, MonoImage *image, guint32 token, MonoGenericContext *context)
276 {
277         int table = mono_metadata_token_table (token);
278         int idx = mono_metadata_token_index (token);
279         guint32 cols [MONO_MEMBERREF_SIZE];
280         MonoMethodSignature *sig, *prev_sig;
281         const char *ptr;
282
283         /* !table is for wrappers: we should really assign their own token to them */
284         if (!table || table == MONO_TABLE_METHOD)
285                 return mono_method_signature (method);
286
287         if (table == MONO_TABLE_METHODSPEC) {
288                 g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
289                           !(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
290                           mono_method_signature (method));
291                 g_assert (method->is_inflated);
292
293                 return mono_method_signature (method);
294         }
295
296         if (method->klass->generic_class)
297                 return mono_method_signature (method);
298
299         if (image->dynamic)
300                 /* FIXME: This might be incorrect for vararg methods */
301                 return mono_method_signature (method);
302
303         mono_loader_lock ();
304         sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (token));
305         mono_loader_unlock ();
306         if (!sig) {
307                 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
308         
309                 ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
310                 mono_metadata_decode_blob_size (ptr, &ptr);
311                 sig = mono_metadata_parse_method_signature_full (image, context, 0, ptr, NULL);
312
313                 mono_loader_lock ();
314                 prev_sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (token));
315                 if (prev_sig) {
316                         /* Somebody got in before us */
317                         /* FIXME: Free sig */
318                         sig = prev_sig;
319                 }
320                 else
321                         g_hash_table_insert (image->memberref_signatures, GUINT_TO_POINTER (token), sig);
322                 mono_loader_unlock ();
323         }
324
325         sig = mono_class_inflate_generic_signature (image, sig, context);
326
327         return sig;
328 }
329
330 MonoMethodSignature*
331 mono_method_get_signature (MonoMethod *method, MonoImage *image, guint32 token)
332 {
333         return mono_method_get_signature_full (method, image, token, NULL);
334 }
335
336 static MonoMethod *
337 method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *context)
338 {
339         MonoClass *klass = NULL;
340         MonoMethod *method = NULL;
341         MonoTableInfo *tables = image->tables;
342         guint32 cols[6];
343         guint32 nindex, class;
344         MonoGenericClass *gclass = NULL;
345         MonoGenericContainer *container = NULL;
346         const char *mname;
347         MonoMethodSignature *sig;
348         const char *ptr;
349
350         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
351         nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
352         class = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
353         /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
354                 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
355
356         mname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
357
358         switch (class) {
359         case MONO_MEMBERREF_PARENT_TYPEREF:
360                 klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
361                 if (!klass) {
362                         char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_REF | nindex, context);
363                         g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
364                         g_free (name);
365                         return NULL;
366                 }
367                 break;
368         case MONO_MEMBERREF_PARENT_TYPESPEC:
369                 klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, context);
370                 if (!klass) {
371                         char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_SPEC | nindex, context);
372                         g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
373                         g_free (name);
374                         return NULL;
375                 }
376                 break;
377         case MONO_MEMBERREF_PARENT_TYPEDEF:
378                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex);
379                 if (!klass) {
380                         char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_DEF | nindex, context);
381                         g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
382                         g_free (name);
383                         return NULL;
384                 }
385                 break;
386         case MONO_MEMBERREF_PARENT_METHODDEF:
387                 return mono_get_method (image, MONO_TOKEN_METHOD_DEF | nindex, NULL);
388         default:
389                 g_error ("Memberref parent unknown: class: %d, index %d", class, nindex);
390                 g_assert_not_reached ();
391         }
392         g_assert (klass);
393
394         if (klass->generic_class) {
395                 gclass = klass->generic_class;
396                 klass = gclass->container_class;
397         }
398         if (klass->generic_container)
399                 container = klass->generic_container;
400         mono_class_init (klass);
401
402         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
403         mono_metadata_decode_blob_size (ptr, &ptr);
404         sig = mono_metadata_parse_method_signature_full (image, (MonoGenericContext *) container, 0, ptr, NULL);
405
406         switch (class) {
407         case MONO_MEMBERREF_PARENT_TYPEREF:
408                 method = find_method (klass, NULL, mname, sig);
409                 if (!method)
410                         g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, mono_class_get_name (klass));
411                 mono_metadata_free_method_signature (sig);
412                 break;
413         case MONO_MEMBERREF_PARENT_TYPESPEC: {
414                 MonoType *type;
415                 MonoMethod *result;
416
417                 type = &klass->byval_arg;
418
419                 if (type->type != MONO_TYPE_ARRAY && type->type != MONO_TYPE_SZARRAY) {
420                         method = find_method (klass, NULL, mname, sig);
421                         if (!method)
422                                 g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, mono_class_get_name (klass));
423                         else if (klass->generic_class && (klass != method->klass))
424                                 method = mono_class_inflate_generic_method (
425                                         method, klass->generic_class->context);
426                         mono_metadata_free_method_signature (sig);
427                         break;
428                 }
429
430                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
431                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_SPEC | nindex);
432                 result->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
433                 result->signature = sig;
434                 result->name = mname;
435
436                 if (!strcmp (mname, ".ctor")) {
437                         /* we special-case this in the runtime. */
438                         return result;
439                 }
440                 
441                 if (!strcmp (mname, "Set")) {
442                         g_assert (sig->hasthis);
443                         g_assert (type->data.array->rank + 1 == sig->param_count);
444                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
445                         return result;
446                 }
447
448                 if (!strcmp (mname, "Get")) {
449                         g_assert (sig->hasthis);
450                         g_assert (type->data.array->rank == sig->param_count);
451                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
452                         return result;
453                 }
454
455                 if (!strcmp (mname, "Address")) {
456                         g_assert (sig->hasthis);
457                         g_assert (type->data.array->rank == sig->param_count);
458                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
459                         return result;
460                 }
461
462                 g_assert_not_reached ();
463                 break;
464         }
465         case MONO_MEMBERREF_PARENT_TYPEDEF:
466                 method = find_method (klass, NULL, mname, sig);
467                 if (!method)
468                         g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, mono_class_get_name (klass));
469                 mono_metadata_free_method_signature (sig);
470                 break;
471         default:
472                 g_error ("Memberref parent unknown: class: %d, index %d", class, nindex);
473                 g_assert_not_reached ();
474         }
475
476         if (gclass)
477                 method = mono_class_inflate_generic_method (method, gclass->context);
478
479         return method;
480 }
481
482 static MonoMethod *
483 method_from_methodspec (MonoImage *image, MonoGenericContext *context, guint32 idx)
484 {
485         MonoMethod *method, *inflated;
486         MonoTableInfo *tables = image->tables;
487         MonoGenericContext *new_context = NULL;
488         MonoGenericMethod *gmethod;
489         MonoGenericContainer *container = NULL;
490         const char *ptr;
491         guint32 cols [MONO_METHODSPEC_SIZE];
492         guint32 token, param_count;
493
494         mono_metadata_decode_row (&tables [MONO_TABLE_METHODSPEC], idx - 1, cols, MONO_METHODSPEC_SIZE);
495         token = cols [MONO_METHODSPEC_METHOD];
496         if ((token & MONO_METHODDEFORREF_MASK) == MONO_METHODDEFORREF_METHODDEF)
497                 token = MONO_TOKEN_METHOD_DEF | (token >> MONO_METHODDEFORREF_BITS);
498         else
499                 token = MONO_TOKEN_MEMBER_REF | (token >> MONO_METHODDEFORREF_BITS);
500
501         method = mono_get_method (image, token, NULL);
502         method = mono_get_inflated_method (method);
503
504         ptr = mono_metadata_blob_heap (image, cols [MONO_METHODSPEC_SIGNATURE]);
505         
506         mono_metadata_decode_value (ptr, &ptr);
507         ptr++;
508         param_count = mono_metadata_decode_value (ptr, &ptr);
509
510         g_assert (param_count);
511         if (method->is_inflated)
512                 container = ((MonoMethodNormal *) ((MonoMethodInflated *) method)->declaring)->generic_container;
513         else
514                 container = ((MonoMethodNormal *) method)->generic_container;
515         g_assert (container && container->is_method);
516
517         if (context) {
518                 g_assert (context->container);
519                 container->parent = context->container;
520                 if (container->parent->is_method)
521                         container->parent = container->parent->parent;
522         }
523
524         gmethod = g_new0 (MonoGenericMethod, 1);
525         gmethod->generic_class = method->klass->generic_class;
526         gmethod->container = container;
527
528         if (context && context->gmethod)
529                 new_context = &context->gmethod->container->context;
530         else if (context && context->gclass)
531                 new_context = &context->gclass->container_class->generic_container->context;
532         else
533                 new_context = context ? &context->container->context : NULL;
534
535         gmethod->inst = mono_metadata_parse_generic_inst (
536                 image, new_context, param_count, ptr, &ptr);
537
538         if (context)
539                 gmethod->inst = mono_metadata_inflate_generic_inst (gmethod->inst, context);
540
541         if (!container->method_hash)
542                 container->method_hash = g_hash_table_new (
543                         (GHashFunc)mono_metadata_generic_method_hash, (GEqualFunc)mono_metadata_generic_method_equal);
544
545         inflated = g_hash_table_lookup (container->method_hash, gmethod);
546         if (inflated) {
547                 g_free (gmethod);
548                 return inflated;
549         }
550
551         if (!context) {
552                 new_context = g_new0 (MonoGenericContext, 1);
553                 new_context->container = container;
554                 new_context->gmethod = gmethod;
555
556                 context = new_context;
557         } else {
558                 new_context = g_new0 (MonoGenericContext, 1);
559                 new_context->container = container;
560                 new_context->gmethod = gmethod;
561                 new_context->gclass = context->gclass;
562
563                 context = new_context;
564         }
565
566         mono_stats.generics_metadata_size += sizeof (MonoGenericMethod) +
567                 sizeof (MonoGenericContext) + param_count * sizeof (MonoType);
568
569         inflated = mono_class_inflate_generic_method (method, context);
570         g_hash_table_insert (container->method_hash, gmethod, inflated);
571
572         if (new_context)
573                 context->gclass = inflated->klass->generic_class;
574         return inflated;
575 }
576
577 typedef struct MonoDllMap MonoDllMap;
578
579 struct MonoDllMap {
580         char *name;
581         char *target;
582         char *dll;
583         MonoDllMap *next;
584 };
585
586 static GHashTable *global_dll_map;
587
588 static int 
589 mono_dllmap_lookup_hash (GHashTable *dll_map, const char *dll, const char* func, const char **rdll, const char **rfunc) {
590         MonoDllMap *map, *tmp;
591
592         *rdll = dll;
593
594         if (!dll_map)
595                 return 0;
596
597         mono_loader_lock ();
598
599         map = g_hash_table_lookup (dll_map, dll);
600         if (!map) {
601                 mono_loader_unlock ();
602                 return 0;
603         }
604         *rdll = map->target? map->target: dll;
605                 
606         for (tmp = map->next; tmp; tmp = tmp->next) {
607                 if (strcmp (func, tmp->name) == 0) {
608                         *rfunc = tmp->name;
609                         if (tmp->dll)
610                                 *rdll = tmp->dll;
611                         mono_loader_unlock ();
612                         return 1;
613                 }
614         }
615         *rfunc = func;
616         mono_loader_unlock ();
617         return 1;
618 }
619
620 static int 
621 mono_dllmap_lookup (MonoImage *assembly, const char *dll, const char* func, const char **rdll, const char **rfunc)
622 {
623         int res;
624         if (assembly && assembly->dll_map) {
625                 res = mono_dllmap_lookup_hash (assembly->dll_map, dll, func, rdll, rfunc);
626                 if (res)
627                         return res;
628         }
629         return mono_dllmap_lookup_hash (global_dll_map, dll, func, rdll, rfunc);
630 }
631
632 void
633 mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc) {
634         MonoDllMap *map, *entry;
635         GHashTable *dll_map = NULL;
636
637         mono_loader_lock ();
638
639         if (!assembly) {
640                 if (!global_dll_map)
641                         global_dll_map = g_hash_table_new (g_str_hash, g_str_equal);
642                 dll_map = global_dll_map;
643         } else {
644                 if (!assembly->dll_map)
645                         assembly->dll_map = g_hash_table_new (g_str_hash, g_str_equal);
646                 dll_map = assembly->dll_map;
647         }
648
649         map = g_hash_table_lookup (dll_map, dll);
650         if (!map) {
651                 map = g_new0 (MonoDllMap, 1);
652                 map->dll = g_strdup (dll);
653                 if (tdll)
654                         map->target = g_strdup (tdll);
655                 g_hash_table_insert (dll_map, map->dll, map);
656         }
657         if (func) {
658                 entry = g_new0 (MonoDllMap, 1);
659                 entry->name = g_strdup (func);
660                 if (tfunc)
661                         entry->target = g_strdup (tfunc);
662                 if (tdll && map->target && strcmp (map->target, tdll))
663                         entry->dll = g_strdup (tdll);
664                 entry->next = map->next;
665                 map->next = entry;
666         }
667
668         mono_loader_unlock ();
669 }
670
671 gpointer
672 mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char **exc_arg)
673 {
674         MonoImage *image = method->klass->image;
675         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
676         MonoTableInfo *tables = image->tables;
677         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
678         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
679         guint32 im_cols [MONO_IMPLMAP_SIZE];
680         guint32 scope_token;
681         const char *import = NULL;
682         const char *orig_scope;
683         const char *new_scope;
684         char *full_name, *file_name;
685         int i;
686         GModule *gmodule = NULL;
687
688         g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
689
690         if (piinfo->addr)
691                 return piinfo->addr;
692
693         if (method->klass->image->dynamic) {
694                 MonoReflectionMethodAux *method_aux = 
695                         g_hash_table_lookup (
696                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
697                 if (!method_aux)
698                         return NULL;
699
700                 import = method_aux->dllentry;
701                 orig_scope = method_aux->dll;
702         }
703         else {
704                 if (!piinfo->implmap_idx)
705                         return NULL;
706
707                 mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
708
709                 piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
710                 import = mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]);
711                 scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME);
712                 orig_scope = mono_metadata_string_heap (image, scope_token);
713         }
714
715         mono_dllmap_lookup (image, orig_scope, import, &new_scope, &import);
716
717         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
718                         "DllImport attempting to load: '%s'.", new_scope);
719
720         if (exc_class) {
721                 *exc_class = NULL;
722                 *exc_arg = NULL;
723         }
724
725         /* we allow a special name to dlopen from the running process namespace */
726         if (strcmp (new_scope, "__Internal") == 0)
727                 gmodule = g_module_open (NULL, G_MODULE_BIND_LAZY);
728                 
729         /*
730          * Try loading the module using a variety of names
731          */
732         for (i = 0; i < 4; ++i) {
733                 switch (i) {
734                 case 0:
735                         /* Try the original name */
736                         file_name = g_strdup (new_scope);
737                         break;
738                 case 1:
739                         /* Try trimming the .dll extension */
740                         if (strstr (new_scope, ".dll") == (new_scope + strlen (new_scope) - 4)) {
741                                 file_name = g_strdup (new_scope);
742                                 file_name [strlen (new_scope) - 4] = '\0';
743                         }
744                         else
745                                 continue;
746                         break;
747                 case 2:
748                         if (strstr (new_scope, "lib") != new_scope) {
749                                 file_name = g_strdup_printf ("lib%s", new_scope);
750                         }
751                         else
752                                 continue;
753                         break;
754                 default:
755 #ifndef PLATFORM_WIN32
756                         if (!g_ascii_strcasecmp ("user32.dll", new_scope) ||
757                             !g_ascii_strcasecmp ("kernel32.dll", new_scope) ||
758                             !g_ascii_strcasecmp ("user32", new_scope) ||
759                             !g_ascii_strcasecmp ("kernel", new_scope)) {
760                                 file_name = g_strdup ("libMonoSupportW.so");
761                         } else
762 #endif
763                                     continue;
764 #ifndef PLATFORM_WIN32
765                         break;
766 #endif
767                 }
768
769                 if (!gmodule) {
770                         full_name = g_module_build_path (NULL, file_name);
771                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
772                                         "DllImport loading location: '%s'.", full_name);
773                         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
774                         if (!gmodule) {
775                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
776                                                 "DllImport error loading library: '%s'.",
777                                                 g_module_error ());
778                         }
779                         g_free (full_name);
780                 }
781
782                 if (!gmodule) {
783                         full_name = g_module_build_path (".", file_name);
784                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
785                                         "DllImport loading library: '%s'.", full_name);
786                         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
787                         if (!gmodule) {
788                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
789                                                 "DllImport error loading library '%s'.",
790                                                 g_module_error ());
791                         }
792                         g_free (full_name);
793                 }
794
795                 if (!gmodule) {
796                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
797                                         "DllImport loading: '%s'.", file_name);
798                         gmodule=g_module_open (file_name, G_MODULE_BIND_LAZY);
799                         if (!gmodule) {
800                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
801                                                 "DllImport error loading library '%s'.",
802                                                 g_module_error ());
803                         }
804                 }
805
806                 g_free (file_name);
807
808                 if (gmodule)
809                         break;
810         }
811
812         if (!gmodule) {
813                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_DLLIMPORT,
814                                 "DllImport unable to load library '%s'.",
815                                 g_module_error ());
816
817                 if (exc_class) {
818                         *exc_class = "DllNotFoundException";
819                         *exc_arg = new_scope;
820                 }
821                 return NULL;
822         }
823
824         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
825                                 "Searching for '%s'.", import);
826
827         if (piinfo->piflags & PINVOKE_ATTRIBUTE_NO_MANGLE) {
828                 g_module_symbol (gmodule, import, &piinfo->addr); 
829         } else {
830                 char *mangled_name = NULL, *mangled_name2 = NULL;
831                 int mangle_charset;
832                 int mangle_stdcall;
833                 int mangle_param_count;
834 #ifdef PLATFORM_WIN32
835                 int param_count;
836 #endif
837
838                 /*
839                  * Search using a variety of mangled names
840                  */
841                 for (mangle_charset = 0; mangle_charset <= 1; mangle_charset ++) {
842                         for (mangle_stdcall = 0; mangle_stdcall <= 1; mangle_stdcall ++) {
843                                 gboolean need_param_count = FALSE;
844 #ifdef PLATFORM_WIN32
845                                 if (mangle_stdcall > 0)
846                                         need_param_count = TRUE;
847 #endif
848                                 for (mangle_param_count = 0; mangle_param_count <= (need_param_count ? 256 : 0); mangle_param_count += 4) {
849
850                                         if (piinfo->addr)
851                                                 continue;
852
853                                         mangled_name = (char*)import;
854                                         switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
855                                         case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
856                                                 /* Try the mangled name first */
857                                                 if (mangle_charset == 0)
858                                                         mangled_name = g_strconcat (import, "W", NULL);
859                                                 break;
860                                         case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
861 #ifdef PLATFORM_WIN32
862                                                 if (mangle_charset == 0)
863                                                         mangled_name = g_strconcat (import, "W", NULL);
864 #endif
865                                                 break;
866                                         case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
867                                         default:
868                                                 /* Try the mangled name last */
869                                                 if (mangle_charset == 1)
870                                                         mangled_name = g_strconcat (import, "A", NULL);
871                                                 break;
872                                         }
873
874 #ifdef PLATFORM_WIN32
875                                         if (mangle_param_count == 0)
876                                                 param_count = mono_method_signature (method)->param_count * sizeof (gpointer);
877                                         else
878                                                 /* Try brute force, since it would be very hard to compute the stack usage correctly */
879                                                 param_count = mangle_param_count;
880
881                                         /* Try the stdcall mangled name */
882                                         /* 
883                                          * gcc under windows creates mangled names without the underscore, but MS.NET
884                                          * doesn't support it, so we doesn't support it either.
885                                          */
886                                         if (mangle_stdcall == 1)
887                                                 mangled_name2 = g_strdup_printf ("_%s@%d", mangled_name, param_count);
888                                         else
889                                                 mangled_name2 = mangled_name;
890 #else
891                                         mangled_name2 = mangled_name;
892 #endif
893
894                                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
895                                                                 "Probing '%s'.", mangled_name2);
896
897                                         g_module_symbol (gmodule, mangled_name2, &piinfo->addr);
898
899                                         if (piinfo->addr)
900                                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
901                                                                         "Found as '%s'.", mangled_name2);
902
903                                         if (mangled_name != mangled_name2)
904                                                 g_free (mangled_name2);
905                                         if (mangled_name != import)
906                                                 g_free (mangled_name);
907                                 }
908                         }
909                 }
910         }
911
912         if (!piinfo->addr) {
913                 if (exc_class) {
914                         *exc_class = "EntryPointNotFoundException";
915                         *exc_arg = import;
916                 }
917                 return NULL;
918         }
919         return piinfo->addr;
920 }
921
922 static MonoMethod *
923 mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
924                             MonoGenericContext *context)
925 {
926         MonoMethod *result;
927         int table = mono_metadata_token_table (token);
928         int idx = mono_metadata_token_index (token);
929         MonoTableInfo *tables = image->tables;
930         MonoGenericContainer *generic_container = NULL, *container = NULL;
931         const char *sig = NULL;
932         int size, i;
933         guint32 cols [MONO_TYPEDEF_SIZE];
934
935         if (image->dynamic)
936                 return mono_lookup_dynamic_token (image, token);
937
938         if (table != MONO_TABLE_METHOD) {
939                 MonoGenericContainer *generic_container = NULL;
940                 if (context) {
941                         g_assert (context->container);
942                         generic_container = context->container;
943                 }
944                 if (table == MONO_TABLE_METHODSPEC)
945                         return method_from_methodspec (image, context, idx);
946                 if (table != MONO_TABLE_MEMBERREF)
947                         g_print("got wrong token: 0x%08x\n", token);
948                 g_assert (table == MONO_TABLE_MEMBERREF);
949                 result = method_from_memberref (image, idx, context);
950
951                 return result;
952         }
953
954         mono_metadata_decode_row (&tables [table], idx - 1, cols, 6);
955
956         if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
957             (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
958                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
959         else 
960                 result = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
961         
962         result->slot = -1;
963         result->klass = klass;
964         result->flags = cols [2];
965         result->iflags = cols [1];
966         result->token = token;
967         result->name = mono_metadata_string_heap (image, cols [3]);
968
969         if (klass)
970                 container = klass->generic_container;
971
972         if (!(cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
973             (!(cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) || cols [1] & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
974                 generic_container = mono_metadata_load_generic_params (image, token, container);
975                 if (generic_container)
976                         container = generic_container;
977         }
978
979         if (!sig) /* already taken from the methodref */
980                 sig = mono_metadata_blob_heap (image, cols [4]);
981         size = mono_metadata_decode_blob_size (sig, &sig);
982         
983         /* there are generic params, or a container. FIXME: be lazy here for generics*/
984         if (* sig & 0x10 || container) {
985                 result->signature = mono_metadata_parse_method_signature_full (
986                         image, (MonoGenericContext *) container, idx, sig, NULL);
987
988                 if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
989                         result->signature->pinvoke = 1;
990         }
991
992         if (!result->klass) {
993                 guint32 type = mono_metadata_typedef_from_method (image, token);
994                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
995         }
996
997         if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
998                 if (result->klass == mono_defaults.string_class && !strcmp (result->name, ".ctor"))
999                         result->string_ctor = 1;
1000         } else if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (!(cols [1] & METHOD_IMPL_ATTRIBUTE_NATIVE))) {
1001                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)result;
1002                 MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
1003                 
1004                 piinfo->implmap_idx = mono_metadata_implmap_from_method (image, idx - 1);
1005                 piinfo->piflags = mono_metadata_decode_row_col (im, piinfo->implmap_idx - 1, MONO_IMPLMAP_FLAGS);
1006         } else {
1007                 if (result->signature && result->signature->generic_param_count) {
1008                         MonoMethodSignature *sig = result->signature;
1009
1010                         for (i = 0; i < sig->generic_param_count; i++) {
1011                                 generic_container->type_params [i].method = result;
1012
1013                                 mono_class_from_generic_parameter (
1014                                         &generic_container->type_params [i], image, TRUE);
1015                         }
1016
1017                         if (sig->ret->type == MONO_TYPE_MVAR) {
1018                                 int num = sig->ret->data.generic_param->num;
1019                                 sig->ret->data.generic_param = &generic_container->type_params [num];
1020                         }
1021
1022                         for (i = 0; i < sig->param_count; i++) {
1023                                 MonoType *t = sig->params [i];
1024                                 if (t->type == MONO_TYPE_MVAR) {
1025                                         int num = t->data.generic_param->num;
1026                                         sig->params [i]->data.generic_param = &generic_container->type_params [num];
1027                                 }
1028                         }
1029                 }
1030                 
1031                 /* FIXME: lazyness for generics too, but how? */
1032                 if (!result->klass->dummy && !(result->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
1033                     !(result->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) && container) {
1034                         gpointer loc = mono_image_rva_map (image, cols [0]);
1035                         g_assert (loc);
1036                         ((MonoMethodNormal *) result)->header = mono_metadata_parse_mh_full (
1037                                 image, (MonoGenericContext *) container, loc);
1038                 }
1039                 
1040                 ((MonoMethodNormal *) result)->generic_container = generic_container;
1041         }
1042
1043         return result;
1044 }
1045
1046 MonoMethod *
1047 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
1048 {
1049         return mono_get_method_full (image, token, klass, NULL);
1050 }
1051
1052 MonoMethod *
1053 mono_get_method_full (MonoImage *image, guint32 token, MonoClass *klass,
1054                       MonoGenericContext *context)
1055 {
1056         MonoMethod *result;
1057
1058         /* We do everything inside the lock to prevent creation races */
1059
1060         mono_loader_lock ();
1061
1062         if ((result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token)))) {
1063                 mono_loader_unlock ();
1064                 return result;
1065         }
1066
1067         result = mono_get_method_from_token (image, token, klass, context);
1068
1069         //printf ("GET: %s\n", mono_method_full_name (result, TRUE));
1070
1071         if (!(result && result->is_inflated))
1072                 g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
1073
1074         mono_loader_unlock ();
1075
1076         return result;
1077 }
1078
1079 MonoMethod *
1080 mono_get_method_constrained (MonoImage *image, guint32 token, MonoClass *constrained_class,
1081                              MonoGenericContext *context)
1082 {
1083         MonoMethod *method, *result;
1084         MonoClass *ic = NULL;
1085         MonoGenericClass *gclass = NULL;
1086
1087         mono_loader_lock ();
1088
1089         method = mono_get_method_from_token (image, token, NULL, context);
1090         if (!method) {
1091                 mono_loader_unlock ();
1092                 return NULL;
1093         }
1094
1095         mono_class_init (constrained_class);
1096         method = mono_get_inflated_method (method);
1097
1098         if ((constrained_class != method->klass) && (method->klass->interface_id != 0))
1099                 ic = method->klass;
1100
1101         if (constrained_class->generic_class)
1102                 gclass = constrained_class->generic_class;
1103
1104         result = find_method (constrained_class, ic, method->name, mono_method_signature (method));
1105         if (!result)
1106                 g_warning ("Missing method %s in assembly %s token %x", method->name,
1107                            image->name, token);
1108
1109         if (gclass)
1110                 result = mono_class_inflate_generic_method (result, gclass->context);
1111
1112         mono_loader_unlock ();
1113         return result;
1114 }
1115
1116 void
1117 mono_free_method  (MonoMethod *method)
1118 {
1119         if (method->signature) {
1120                 /* 
1121                  * FIXME: This causes crashes because the types inside signatures and
1122                  * locals are shared.
1123                  */
1124                 /* mono_metadata_free_method_signature (method->signature); */
1125                 g_free (method->signature);
1126         }
1127
1128         if (method->dynamic) {
1129                 MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
1130
1131                 g_free ((char*)method->name);
1132                 if (mw->method.header)
1133                         g_free ((char*)mw->method.header->code);
1134                 g_free (mw->method_data);
1135         }
1136
1137         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && ((MonoMethodNormal *)method)->header) {
1138                 /* FIXME: Ditto */
1139                 /* mono_metadata_free_mh (((MonoMethodNormal *)method)->header); */
1140                 g_free (((MonoMethodNormal*)method)->header);
1141         }
1142
1143         g_free (method);
1144 }
1145
1146 void
1147 mono_method_get_param_names (MonoMethod *method, const char **names)
1148 {
1149         int i, lastp;
1150         MonoClass *klass = method->klass;
1151         MonoTableInfo *methodt;
1152         MonoTableInfo *paramt;
1153         guint32 idx;
1154
1155         if (!mono_method_signature (method)->param_count)
1156                 return;
1157         for (i = 0; i < mono_method_signature (method)->param_count; ++i)
1158                 names [i] = "";
1159
1160         if (klass->generic_class) /* copy the names later */
1161                 return;
1162
1163         mono_class_init (klass);
1164
1165         if (klass->image->dynamic) {
1166                 MonoReflectionMethodAux *method_aux = 
1167                         g_hash_table_lookup (
1168                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1169                 if (method_aux && method_aux->param_names) {
1170                         for (i = 0; i < mono_method_signature (method)->param_count; ++i)
1171                                 if (method_aux->param_names [i + 1])
1172                                         names [i] = method_aux->param_names [i + 1];
1173                 }
1174                 return;
1175         }
1176
1177         methodt = &klass->image->tables [MONO_TABLE_METHOD];
1178         paramt = &klass->image->tables [MONO_TABLE_PARAM];
1179         idx = mono_method_get_index (method);
1180         if (idx > 0) {
1181                 guint32 cols [MONO_PARAM_SIZE];
1182                 guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
1183
1184                 if (idx < methodt->rows)
1185                         lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
1186                 else
1187                         lastp = paramt->rows + 1;
1188                 for (i = param_index; i < lastp; ++i) {
1189                         mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
1190                         if (cols [MONO_PARAM_SEQUENCE]) /* skip return param spec */
1191                                 names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass->image, cols [MONO_PARAM_NAME]);
1192                 }
1193                 return;
1194         }
1195 }
1196
1197 guint32
1198 mono_method_get_param_token (MonoMethod *method, int index)
1199 {
1200         MonoClass *klass = method->klass;
1201         MonoTableInfo *methodt;
1202         guint32 idx;
1203
1204         if (klass->generic_class)
1205                 g_assert_not_reached ();
1206
1207         mono_class_init (klass);
1208
1209         if (klass->image->dynamic) {
1210                 g_assert_not_reached ();
1211         }
1212
1213         methodt = &klass->image->tables [MONO_TABLE_METHOD];
1214         idx = mono_method_get_index (method);
1215         if (idx > 0) {
1216                 guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
1217
1218                 return mono_metadata_make_token (MONO_TABLE_PARAM, param_index + index);
1219         }
1220
1221         return 0;
1222 }
1223
1224 void
1225 mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs)
1226 {
1227         int i, lastp;
1228         MonoClass *klass = method->klass;
1229         MonoTableInfo *methodt;
1230         MonoTableInfo *paramt;
1231         guint32 idx;
1232
1233         for (i = 0; i < mono_method_signature (method)->param_count + 1; ++i)
1234                 mspecs [i] = NULL;
1235
1236         if (method->klass->image->dynamic) {
1237                 MonoReflectionMethodAux *method_aux = 
1238                         g_hash_table_lookup (
1239                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1240                 if (method_aux && method_aux->param_marshall) {
1241                         MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
1242                         for (i = 0; i < mono_method_signature (method)->param_count + 1; ++i)
1243                                 if (dyn_specs [i]) {
1244                                         mspecs [i] = g_new0 (MonoMarshalSpec, 1);
1245                                         memcpy (mspecs [i], dyn_specs [i], sizeof (MonoMarshalSpec));
1246                                 }
1247                 }
1248                 return;
1249         }
1250
1251         mono_class_init (klass);
1252
1253         methodt = &klass->image->tables [MONO_TABLE_METHOD];
1254         paramt = &klass->image->tables [MONO_TABLE_PARAM];
1255         idx = mono_method_get_index (method);
1256         if (idx > 0) {
1257                 guint32 cols [MONO_PARAM_SIZE];
1258                 guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
1259
1260                 if (idx < methodt->rows)
1261                         lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
1262                 else
1263                         lastp = paramt->rows + 1;
1264
1265                 for (i = param_index; i < lastp; ++i) {
1266                         mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
1267
1268                         if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) {
1269                                 const char *tp;
1270                                 tp = mono_metadata_get_marshal_info (klass->image, i - 1, FALSE);
1271                                 g_assert (tp);
1272                                 mspecs [cols [MONO_PARAM_SEQUENCE]]= mono_metadata_parse_marshal_spec (klass->image, tp);
1273                         }
1274                 }
1275
1276                 return;
1277         }
1278 }
1279
1280 gboolean
1281 mono_method_has_marshal_info (MonoMethod *method)
1282 {
1283         int i, lastp;
1284         MonoClass *klass = method->klass;
1285         MonoTableInfo *methodt;
1286         MonoTableInfo *paramt;
1287         guint32 idx;
1288
1289         if (method->klass->image->dynamic) {
1290                 MonoReflectionMethodAux *method_aux = 
1291                         g_hash_table_lookup (
1292                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1293                 MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
1294                 if (dyn_specs) {
1295                         for (i = 0; i < mono_method_signature (method)->param_count + 1; ++i)
1296                                 if (dyn_specs [i])
1297                                         return TRUE;
1298                 }
1299                 return FALSE;
1300         }
1301
1302         mono_class_init (klass);
1303
1304         methodt = &klass->image->tables [MONO_TABLE_METHOD];
1305         paramt = &klass->image->tables [MONO_TABLE_PARAM];
1306         idx = mono_method_get_index (method);
1307         if (idx > 0) {
1308                 guint32 cols [MONO_PARAM_SIZE];
1309                 guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
1310                 
1311                 if (idx + 1 < methodt->rows)
1312                         lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
1313                 else
1314                         lastp = paramt->rows + 1;
1315
1316                 for (i = param_index; i < lastp; ++i) {
1317                         mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
1318
1319                         if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL)
1320                                 return TRUE;
1321                 }
1322                 return FALSE;
1323         }
1324         return FALSE;
1325 }
1326
1327 gpointer
1328 mono_method_get_wrapper_data (MonoMethod *method, guint32 id)
1329 {
1330         void **data;
1331         g_assert (method != NULL);
1332         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
1333
1334         data = ((MonoMethodWrapper *)method)->method_data;
1335         g_assert (data != NULL);
1336         g_assert (id <= GPOINTER_TO_UINT (*data));
1337         return data [id];
1338 }
1339
1340 static void
1341 default_stack_walk (MonoStackWalk func, gboolean do_il_offset, gpointer user_data) {
1342         g_error ("stack walk not installed");
1343 }
1344
1345 static MonoStackWalkImpl stack_walk = default_stack_walk;
1346
1347 void
1348 mono_stack_walk (MonoStackWalk func, gpointer user_data)
1349 {
1350         stack_walk (func, TRUE, user_data);
1351 }
1352
1353 void
1354 mono_stack_walk_no_il (MonoStackWalk func, gpointer user_data)
1355 {
1356         stack_walk (func, FALSE, user_data);
1357 }
1358
1359 void
1360 mono_install_stack_walk (MonoStackWalkImpl func)
1361 {
1362         stack_walk = func;
1363 }
1364
1365 static gboolean
1366 last_managed (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
1367 {
1368         MonoMethod **dest = data;
1369         *dest = m;
1370         /*g_print ("In %s::%s [%d] [%d]\n", m->klass->name, m->name, no, ilo);*/
1371
1372         return managed;
1373 }
1374
1375 MonoMethod*
1376 mono_method_get_last_managed (void)
1377 {
1378         MonoMethod *m = NULL;
1379         stack_walk (last_managed, FALSE, &m);
1380         return m;
1381 }
1382
1383 void
1384 mono_loader_lock (void)
1385 {
1386         EnterCriticalSection (&loader_mutex);
1387 }
1388
1389 void
1390 mono_loader_unlock (void)
1391 {
1392         LeaveCriticalSection (&loader_mutex);
1393 }
1394
1395 MonoMethodSignature* 
1396 mono_method_signature (MonoMethod *m)
1397 {
1398         m = mono_get_inflated_method (m);
1399         return mono_method_signature_full (m, NULL);
1400 }
1401
1402 MonoMethodSignature* 
1403 mono_method_signature_full (MonoMethod *m, MonoGenericContext *context)
1404 {
1405         int idx;
1406         int size;
1407         MonoImage* img;
1408         const char *sig;
1409         
1410         if (m->signature)
1411                 return m->signature;
1412                 
1413         mono_loader_lock ();
1414         
1415         if (m->signature) {
1416                 mono_loader_unlock ();
1417                 return m->signature;
1418         }
1419         
1420         g_assert (mono_metadata_token_table (m->token) == MONO_TABLE_METHOD);
1421         idx = mono_metadata_token_index (m->token);
1422         img = m->klass->image;
1423         
1424         sig = mono_metadata_blob_heap (img, mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_SIGNATURE));
1425         size = mono_metadata_decode_blob_size (sig, &sig);
1426         
1427         m->signature = mono_metadata_parse_method_signature_full (img, context, idx, sig, NULL);
1428         
1429         if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
1430                 m->signature->pinvoke = 1;
1431         else if ((m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (!(m->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE))) {
1432                 MonoCallConvention conv = 0;
1433                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)m;
1434                 m->signature->pinvoke = 1;
1435                 
1436                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CALL_CONV_MASK) {
1437                 case 0: /* no call conv, so using default */
1438                 case PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI:
1439                         conv = MONO_CALL_DEFAULT;
1440                         break;
1441                 case PINVOKE_ATTRIBUTE_CALL_CONV_CDECL:
1442                         conv = MONO_CALL_C;
1443                         break;
1444                 case PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL:
1445                         conv = MONO_CALL_STDCALL;
1446                         break;
1447                 case PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL:
1448                         conv = MONO_CALL_THISCALL;
1449                         break;
1450                 case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL:
1451                         conv = MONO_CALL_FASTCALL;
1452                         break;
1453                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC:
1454                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST:
1455                 default:
1456                         g_warning ("unsupported calling convention : 0x%04x", piinfo->piflags);
1457                         g_assert_not_reached ();
1458                 }       
1459                 m->signature->call_convention = conv;
1460         }
1461         
1462         mono_loader_unlock ();
1463         return m->signature;
1464 }
1465
1466 const char*
1467 mono_method_get_name (MonoMethod *method)
1468 {
1469         return method->name;
1470 }
1471
1472 MonoClass*
1473 mono_method_get_class (MonoMethod *method)
1474 {
1475         return method->klass;
1476 }
1477
1478 guint32
1479 mono_method_get_token (MonoMethod *method)
1480 {
1481         return method->token;
1482 }
1483
1484 MonoMethodHeader* 
1485 mono_method_get_header (MonoMethod *method)
1486 {
1487         int idx;
1488         guint32 rva;
1489         MonoImage* img;
1490         gpointer loc;
1491         MonoMethodNormal* mn = (MonoMethodNormal*) method;
1492         
1493 #ifdef G_LIKELY
1494         if (G_LIKELY (mn->header))
1495 #else
1496         if (mn->header)
1497 #endif
1498                 return mn->header;
1499         
1500         if (method->klass->dummy || (method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
1501                 return NULL;
1502         
1503         mono_loader_lock ();
1504         
1505         if (mn->header) {
1506                 mono_loader_unlock ();
1507                 return mn->header;
1508         }
1509         
1510         g_assert (mono_metadata_token_table (method->token) == MONO_TABLE_METHOD);
1511         idx = mono_metadata_token_index (method->token);
1512         img = method->klass->image;
1513         rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
1514         loc = mono_image_rva_map (img, rva);
1515         
1516         g_assert (loc);
1517         
1518         mn->header = mono_metadata_parse_mh_full (img, (MonoGenericContext *) mn->generic_container, loc);
1519         
1520         mono_loader_unlock ();
1521         return mn->header;
1522 }
1523
1524 guint32
1525 mono_method_get_flags (MonoMethod *method, guint32 *iflags)
1526 {
1527         if (iflags)
1528                 *iflags = method->iflags;
1529         return method->flags;
1530 }
1531
1532 /*
1533  * Find the method index in the metadata methodDef table.
1534  */
1535 guint32
1536 mono_method_get_index (MonoMethod *method) {
1537         MonoClass *klass = method->klass;
1538         int i;
1539
1540         if (method->token)
1541                 return mono_metadata_token_index (method->token);
1542
1543         mono_class_setup_methods (klass);
1544         for (i = 0; i < klass->method.count; ++i) {
1545                 if (method == klass->methods [i])
1546                         return klass->method.first + 1 + i;
1547         }
1548         return 0;
1549 }
1550