Wed Aug 22 17:26:02 CEST 2007 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / loader.c
1 /*
2  * loader.c: Image Loader 
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Miguel de Icaza (miguel@ximian.com)
7  *   Patrik Torstensson (patrik.torstensson@labs2.com)
8  *
9  * (C) 2001 Ximian, Inc.
10  * Copyright (C) 2002-2006 Novell, Inc.
11  *
12  * This file is used by the interpreter and the JIT engine to locate
13  * assemblies.  Used to load AssemblyRef and later to resolve various
14  * kinds of `Refs'.
15  *
16  * TODO:
17  *   This should keep track of the assembly versions that we are loading.
18  *
19  */
20 #include <config.h>
21 #include <glib.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/metadata/profiler.h>
37 #include <mono/utils/mono-logger.h>
38 #include <mono/utils/mono-dl.h>
39 #include <mono/metadata/exception.h>
40
41 MonoDefaults mono_defaults;
42
43 /*
44  * This lock protects the hash tables inside MonoImage used by the metadata 
45  * loading functions in class.c and loader.c.
46  */
47 static CRITICAL_SECTION loader_mutex;
48
49
50 /*
51  * This TLS variable contains the last type load error encountered by the loader.
52  */
53 guint32 loader_error_thread_id;
54
55 void
56 mono_loader_init ()
57 {
58         InitializeCriticalSection (&loader_mutex);
59
60         loader_error_thread_id = TlsAlloc ();
61 }
62
63 void
64 mono_loader_cleanup (void)
65 {
66         TlsFree (loader_error_thread_id);
67
68         /*DeleteCriticalSection (&loader_mutex);*/
69 }
70
71 /*
72  * Handling of type load errors should be done as follows:
73  *
74  *   If something could not be loaded, the loader should call one of the
75  * mono_loader_set_error_XXX functions ()
76  * with the appropriate arguments, then return NULL to report the failure. The error 
77  * should be propagated until it reaches code which can throw managed exceptions. At that
78  * point, an exception should be thrown based on the information returned by
79  * mono_loader_get_error (). Then the error should be cleared by calling 
80  * mono_loader_clear_error ().
81  */
82
83 static void
84 set_loader_error (MonoLoaderError *error)
85 {
86         TlsSetValue (loader_error_thread_id, error);
87 }
88
89 /**
90  * mono_loader_set_error_assembly_load:
91  *
92  * Set the loader error for this thread. 
93  */
94 void
95 mono_loader_set_error_assembly_load (const char *assembly_name, gboolean ref_only)
96 {
97         MonoLoaderError *error;
98
99         if (mono_loader_get_last_error ()) 
100                 return;
101
102         error = g_new0 (MonoLoaderError, 1);
103         error->exception_type = MONO_EXCEPTION_FILE_NOT_FOUND;
104         error->assembly_name = g_strdup (assembly_name);
105         error->ref_only = ref_only;
106
107         /* 
108          * This is not strictly needed, but some (most) of the loader code still
109          * can't deal with load errors, and this message is more helpful than an
110          * assert.
111          */
112         if (ref_only)
113                 g_warning ("Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.", assembly_name);
114         else
115                 g_warning ("Could not load file or assembly '%s' or one of its dependencies.", assembly_name);
116
117         set_loader_error (error);
118 }
119
120 /**
121  * mono_loader_set_error_type_load:
122  *
123  * Set the loader error for this thread. 
124  */
125 void
126 mono_loader_set_error_type_load (const char *class_name, const char *assembly_name)
127 {
128         MonoLoaderError *error;
129
130         if (mono_loader_get_last_error ()) 
131                 return;
132
133         error = g_new0 (MonoLoaderError, 1);
134         error->exception_type = MONO_EXCEPTION_TYPE_LOAD;
135         error->class_name = g_strdup (class_name);
136         error->assembly_name = g_strdup (assembly_name);
137
138         /* 
139          * This is not strictly needed, but some (most) of the loader code still
140          * can't deal with load errors, and this message is more helpful than an
141          * assert.
142          */
143         g_warning ("The class %s could not be loaded, used in %s", class_name, assembly_name);
144
145         set_loader_error (error);
146 }
147
148 /*
149  * mono_loader_set_error_method_load:
150  *
151  *   Set the loader error for this thread. MEMBER_NAME should point to a string
152  * inside metadata.
153  */
154 void
155 mono_loader_set_error_method_load (const char *class_name, const char *member_name)
156 {
157         MonoLoaderError *error;
158
159         /* FIXME: Store the signature as well */
160         if (mono_loader_get_last_error ())
161                 return;
162
163         error = g_new0 (MonoLoaderError, 1);
164         error->exception_type = MONO_EXCEPTION_MISSING_METHOD;
165         error->class_name = g_strdup (class_name);
166         error->member_name = member_name;
167
168         set_loader_error (error);
169 }
170
171 /*
172  * mono_loader_set_error_field_load:
173  *
174  * Set the loader error for this thread. MEMBER_NAME should point to a string
175  * inside metadata.
176  */
177 void
178 mono_loader_set_error_field_load (MonoClass *klass, const char *member_name)
179 {
180         MonoLoaderError *error;
181
182         /* FIXME: Store the signature as well */
183         if (mono_loader_get_last_error ())
184                 return;
185
186         error = g_new0 (MonoLoaderError, 1);
187         error->exception_type = MONO_EXCEPTION_MISSING_FIELD;
188         error->klass = klass;
189         error->member_name = member_name;
190
191         set_loader_error (error);
192 }
193
194 /*
195  * mono_loader_get_last_error:
196  *
197  *   Returns information about the last type load exception encountered by the loader, or
198  * NULL. After use, the exception should be cleared by calling mono_loader_clear_error.
199  */
200 MonoLoaderError*
201 mono_loader_get_last_error (void)
202 {
203         return (MonoLoaderError*)TlsGetValue (loader_error_thread_id);
204 }
205
206 /**
207  * mono_loader_clear_error:
208  *
209  * Disposes any loader error messages on this thread
210  */
211 void
212 mono_loader_clear_error (void)
213 {
214         MonoLoaderError *ex = (MonoLoaderError*)TlsGetValue (loader_error_thread_id);
215
216         if (ex) {
217                 g_free (ex->class_name);
218                 g_free (ex->assembly_name);
219                 g_free (ex);
220         
221                 TlsSetValue (loader_error_thread_id, NULL);
222         }
223 }
224
225 /**
226  * mono_loader_error_prepare_exception:
227  * @error: The MonoLoaderError to turn into an exception
228  *
229  * This turns a MonoLoaderError into an exception that can be thrown
230  * and resets the Mono Loader Error state during this process.
231  *
232  */
233 MonoException *
234 mono_loader_error_prepare_exception (MonoLoaderError *error)
235 {
236         MonoException *ex = NULL;
237
238         switch (error->exception_type) {
239         case MONO_EXCEPTION_TYPE_LOAD: {
240                 char *cname = g_strdup (error->class_name);
241                 char *aname = g_strdup (error->assembly_name);
242                 MonoString *class_name;
243                 
244                 mono_loader_clear_error ();
245                 
246                 class_name = mono_string_new (mono_domain_get (), cname);
247
248                 ex = mono_get_exception_type_load (class_name, aname);
249                 g_free (cname);
250                 g_free (aname);
251                 break;
252         }
253         case MONO_EXCEPTION_MISSING_METHOD: {
254                 char *cname = g_strdup (error->class_name);
255                 char *aname = g_strdup (error->member_name);
256                 
257                 mono_loader_clear_error ();
258                 ex = mono_get_exception_missing_method (cname, aname);
259                 g_free (cname);
260                 g_free (aname);
261                 break;
262         }
263                 
264         case MONO_EXCEPTION_MISSING_FIELD: {
265                 char *cnspace = g_strdup (*error->klass->name_space ? error->klass->name_space : "");
266                 char *cname = g_strdup (error->klass->name);
267                 char *cmembername = g_strdup (error->member_name);
268                 char *class_name;
269
270                 mono_loader_clear_error ();
271                 class_name = g_strdup_printf ("%s%s%s", cnspace, cnspace ? "." : "", cname);
272                 
273                 ex = mono_get_exception_missing_field (class_name, cmembername);
274                 g_free (class_name);
275                 g_free (cname);
276                 g_free (cmembername);
277                 g_free (cnspace);
278                 break;
279         }
280         
281         case MONO_EXCEPTION_FILE_NOT_FOUND: {
282                 char *msg;
283                 char *filename;
284
285                 if (error->ref_only)
286                         msg = g_strdup_printf ("Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.", error->assembly_name);
287                 else
288                         msg = g_strdup_printf ("Could not load file or assembly '%s' or one of its dependencies.", error->assembly_name);
289                 filename = g_strdup (error->assembly_name);
290                 /* Has to call this before calling anything which might call mono_class_init () */
291                 mono_loader_clear_error ();
292                 ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), filename));
293                 g_free (msg);
294                 g_free (filename);
295                 break;
296         }
297         
298         default:
299                 g_assert_not_reached ();
300         }
301
302         return ex;
303 }
304
305 static MonoClassField*
306 field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
307                       MonoGenericContext *context)
308 {
309         MonoClass *klass;
310         MonoClassField *field;
311         MonoTableInfo *tables = image->tables;
312         guint32 cols[6];
313         guint32 nindex, class;
314         const char *fname;
315         const char *ptr;
316         guint32 idx = mono_metadata_token_index (token);
317
318         if (image->dynamic) {
319                 MonoClassField *result = mono_lookup_dynamic_token (image, token);
320                 *retklass = result->parent;
321                 return result;
322         }
323
324         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
325         nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
326         class = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
327
328         fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
329
330         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
331         mono_metadata_decode_blob_size (ptr, &ptr);
332         /* we may want to check the signature here... */
333
334         switch (class) {
335         case MONO_MEMBERREF_PARENT_TYPEDEF:
336                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex);
337                 if (!klass) {
338                         char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_REF | nindex);
339                         g_warning ("Missing field %s in class %s (typeref index %d)", fname, name, nindex);
340                         g_free (name);
341                         return NULL;
342                 }
343                 mono_class_init (klass);
344                 if (retklass)
345                         *retklass = klass;
346                 field = mono_class_get_field_from_name (klass, fname);
347                 break;
348         case MONO_MEMBERREF_PARENT_TYPEREF:
349                 klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
350                 if (!klass) {
351                         char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_REF | nindex);
352                         g_warning ("Missing field %s in class %s (typeref index %d)", fname, name, nindex);
353                         g_free (name);
354                         return NULL;
355                 }
356                 mono_class_init (klass);
357                 if (retklass)
358                         *retklass = klass;
359                 field = mono_class_get_field_from_name (klass, fname);
360                 break;
361         case MONO_MEMBERREF_PARENT_TYPESPEC: {
362                 /*guint32 bcols [MONO_TYPESPEC_SIZE];
363                 guint32 len;
364                 MonoType *type;
365
366                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
367                                           bcols, MONO_TYPESPEC_SIZE);
368                 ptr = mono_metadata_blob_heap (image, bcols [MONO_TYPESPEC_SIGNATURE]);
369                 len = mono_metadata_decode_value (ptr, &ptr);   
370                 type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
371
372                 klass = mono_class_from_mono_type (type);
373                 mono_class_init (klass);
374                 g_print ("type in sig: %s\n", klass->name);*/
375                 klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, context);
376                 mono_class_init (klass);
377                 if (retklass)
378                         *retklass = klass;
379                 field = mono_class_get_field_from_name (klass, fname);
380                 break;
381         }
382         default:
383                 g_warning ("field load from %x", class);
384                 return NULL;
385         }
386
387         if (!field)
388                 mono_loader_set_error_field_load (klass, fname);
389
390         return field;
391 }
392
393 MonoClassField*
394 mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass,
395                        MonoGenericContext *context)
396 {
397         MonoClass *k;
398         guint32 type;
399         MonoClassField *field;
400
401         if (image->dynamic) {
402                 MonoClassField *result = mono_lookup_dynamic_token (image, token);
403                 *retklass = result->parent;
404                 return result;
405         }
406
407         mono_loader_lock ();
408         if ((field = g_hash_table_lookup (image->field_cache, GUINT_TO_POINTER (token)))) {
409                 *retklass = field->parent;
410                 mono_loader_unlock ();
411                 return field;
412         }
413         mono_loader_unlock ();
414
415         if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
416                 field = field_from_memberref (image, token, retklass, context);
417         else {
418                 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
419                 if (!type)
420                         return NULL;
421                 k = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
422                 if (!k)
423                         return NULL;
424                 mono_class_init (k);
425                 if (retklass)
426                         *retklass = k;
427                 field = mono_class_get_field (k, token);
428         }
429
430         mono_loader_lock ();
431         if (field && !field->parent->generic_class)
432                 g_hash_table_insert (image->field_cache, GUINT_TO_POINTER (token), field);
433         mono_loader_unlock ();
434         return field;
435 }
436
437 static gboolean
438 mono_metadata_signature_vararg_match (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
439 {
440         int i;
441
442         if (sig1->hasthis != sig2->hasthis ||
443             sig1->sentinelpos != sig2->sentinelpos)
444                 return FALSE;
445
446         for (i = 0; i < sig1->sentinelpos; i++) { 
447                 MonoType *p1 = sig1->params[i];
448                 MonoType *p2 = sig2->params[i];
449
450                 /*if (p1->attrs != p2->attrs)
451                         return FALSE;
452                 */
453                 if (!mono_metadata_type_equal (p1, p2))
454                         return FALSE;
455         }
456
457         if (!mono_metadata_type_equal (sig1->ret, sig2->ret))
458                 return FALSE;
459         return TRUE;
460 }
461
462 static MonoMethod *
463 find_method_in_class (MonoClass *in_class, const char *name, const char *qname, const char *fqname,
464                       MonoMethodSignature *sig, MonoClass *from_class)
465 {
466         int i;
467
468         mono_class_setup_methods (in_class);
469         for (i = 0; i < in_class->method.count; ++i) {
470                 MonoMethod *m = in_class->methods [i];
471
472                 if (!((fqname && !strcmp (m->name, fqname)) ||
473                       (qname && !strcmp (m->name, qname)) ||
474                       (name && !strcmp (m->name, name))))
475                         continue;
476
477                 if (sig->call_convention == MONO_CALL_VARARG) {
478                         if (mono_metadata_signature_vararg_match (sig, mono_method_signature (m)))
479                                 break;
480                 } else {
481                         if (mono_metadata_signature_equal (sig, mono_method_signature (m)))
482                                 break;
483                 }
484         }
485
486         if (i < in_class->method.count) {
487                 mono_class_setup_methods (from_class);
488                 g_assert (from_class->method.count == in_class->method.count);
489                 return from_class->methods [i];
490         }
491         return NULL;
492 }
493
494 static MonoMethod *
495 find_method (MonoClass *in_class, MonoClass *ic, const char* name, MonoMethodSignature *sig, MonoClass *from_class)
496 {
497         int i;
498         char *qname, *fqname, *class_name;
499         gboolean is_interface;
500         MonoMethod *result = NULL;
501
502         is_interface = MONO_CLASS_IS_INTERFACE (in_class);
503
504         if (ic) {
505                 class_name = mono_type_get_name_full (&ic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);
506
507                 qname = g_strconcat (class_name, ".", name, NULL); 
508                 if (ic->name_space && ic->name_space [0])
509                         fqname = g_strconcat (ic->name_space, ".", class_name, ".", name, NULL);
510                 else
511                         fqname = NULL;
512         } else
513                 class_name = qname = fqname = NULL;
514
515         while (in_class) {
516                 g_assert (from_class);
517                 result = find_method_in_class (in_class, name, qname, fqname, sig, from_class);
518                 if (result)
519                         goto out;
520
521                 if (name [0] == '.' && (!strcmp (name, ".ctor") || !strcmp (name, ".cctor")))
522                         break;
523
524                 g_assert (from_class->interface_count == in_class->interface_count);
525                 for (i = 0; i < in_class->interface_count; i++) {
526                         MonoClass *ic = in_class->interfaces [i];
527                         MonoClass *from_ic = from_class->interfaces [i];
528                         char *ic_qname, *ic_fqname, *ic_class_name;
529                         
530                         ic_class_name = mono_type_get_name_full (&ic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);
531                         ic_qname = g_strconcat (ic_class_name, ".", name, NULL); 
532                         if (ic->name_space && ic->name_space [0])
533                                 ic_fqname = g_strconcat (ic->name_space, ".", ic_class_name, ".", name, NULL);
534                         else
535                                 ic_fqname = NULL;
536
537                         result = find_method_in_class (ic, NULL, ic_qname, ic_fqname, sig, from_ic);
538                         g_free (ic_class_name);
539                         g_free (ic_fqname);
540                         g_free (ic_qname);
541                         if (result)
542                                 goto out;
543                 }
544
545                 in_class = in_class->parent;
546                 from_class = from_class->parent;
547         }
548         g_assert (!in_class == !from_class);
549
550         if (is_interface)
551                 result = find_method_in_class (mono_defaults.object_class, name, qname, fqname, sig, mono_defaults.object_class);
552
553  out:
554         g_free (class_name);
555         g_free (fqname);
556         g_free (qname);
557         return result;
558 }
559
560 static MonoMethodSignature*
561 inflate_generic_signature (MonoImage *image, MonoMethodSignature *sig, MonoGenericContext *context)
562 {
563         MonoMethodSignature *res;
564         gboolean is_open;
565         int i;
566
567         if (!context)
568                 return sig;
569
570         res = mono_metadata_signature_alloc (image, sig->param_count);
571         res->ret = mono_class_inflate_generic_type (sig->ret, context);
572         is_open = mono_class_is_open_constructed_type (res->ret);
573         for (i = 0; i < sig->param_count; ++i) {
574                 res->params [i] = mono_class_inflate_generic_type (sig->params [i], context);
575                 if (!is_open)
576                         is_open = mono_class_is_open_constructed_type (res->params [i]);
577         }
578         res->hasthis = sig->hasthis;
579         res->explicit_this = sig->explicit_this;
580         res->call_convention = sig->call_convention;
581         res->pinvoke = sig->pinvoke;
582         res->generic_param_count = sig->generic_param_count;
583         res->sentinelpos = sig->sentinelpos;
584         res->has_type_parameters = is_open;
585         res->is_inflated = 1;
586         return res;
587 }
588
589 static MonoMethodHeader*
590 inflate_generic_header (MonoMethodHeader *header, MonoGenericContext *context)
591 {
592         MonoMethodHeader *res;
593         int i;
594         res = g_malloc0 (sizeof (MonoMethodHeader) + sizeof (gpointer) * header->num_locals);
595         res->code = header->code;
596         res->code_size = header->code_size;
597         res->max_stack = header->max_stack;
598         res->num_clauses = header->num_clauses;
599         res->init_locals = header->init_locals;
600         res->num_locals = header->num_locals;
601         res->clauses = header->clauses;
602         for (i = 0; i < header->num_locals; ++i)
603                 res->locals [i] = mono_class_inflate_generic_type (header->locals [i], context);
604         if (res->num_clauses) {
605                 res->clauses = g_memdup (header->clauses, sizeof (MonoExceptionClause) * res->num_clauses);
606                 for (i = 0; i < header->num_clauses; ++i) {
607                         MonoExceptionClause *clause = &res->clauses [i];
608                         MonoType *t;
609                         if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE)
610                                 continue;
611                         t = mono_class_inflate_generic_type (&clause->data.catch_class->byval_arg, context);
612                         clause->data.catch_class = mono_class_from_mono_type (t);
613                 }
614         }
615         return res;
616 }
617
618 /*
619  * token is the method_ref or method_def token used in a call IL instruction.
620  */
621 MonoMethodSignature*
622 mono_method_get_signature_full (MonoMethod *method, MonoImage *image, guint32 token, MonoGenericContext *context)
623 {
624         int table = mono_metadata_token_table (token);
625         int idx = mono_metadata_token_index (token);
626         guint32 cols [MONO_MEMBERREF_SIZE];
627         MonoMethodSignature *sig, *prev_sig;
628         const char *ptr;
629
630         /* !table is for wrappers: we should really assign their own token to them */
631         if (!table || table == MONO_TABLE_METHOD)
632                 return mono_method_signature (method);
633
634         if (table == MONO_TABLE_METHODSPEC) {
635                 g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
636                           !(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
637                           mono_method_signature (method));
638                 g_assert (method->is_inflated);
639
640                 return mono_method_signature (method);
641         }
642
643         if (method->klass->generic_class)
644                 return mono_method_signature (method);
645
646         if (image->dynamic)
647                 /* FIXME: This might be incorrect for vararg methods */
648                 return mono_method_signature (method);
649
650         mono_loader_lock ();
651         sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (token));
652         mono_loader_unlock ();
653         if (!sig) {
654                 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
655
656                 ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
657                 mono_metadata_decode_blob_size (ptr, &ptr);
658                 sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
659
660                 mono_loader_lock ();
661                 prev_sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (token));
662                 if (prev_sig) {
663                         /* Somebody got in before us */
664                         /* FIXME: Free sig */
665                         sig = prev_sig;
666                 }
667                 else
668                         g_hash_table_insert (image->memberref_signatures, GUINT_TO_POINTER (token), sig);
669                 mono_loader_unlock ();
670         }
671
672         sig = inflate_generic_signature (image, sig, context);
673
674         return sig;
675 }
676
677 MonoMethodSignature*
678 mono_method_get_signature (MonoMethod *method, MonoImage *image, guint32 token)
679 {
680         return mono_method_get_signature_full (method, image, token, NULL);
681 }
682
683 /* this is only for the typespec array methods */
684 static MonoMethod*
685 search_in_array_class (MonoClass *klass, const char *name, MonoMethodSignature *sig)
686 {
687         int i;
688         for (i = 0; i < klass->method.count; ++i) {
689                 MonoMethod *method = klass->methods [i];
690                 if (strcmp (method->name, name) == 0 && sig->param_count == method->signature->param_count)
691                         return method;
692         }
693         return NULL;
694 }
695
696 static MonoMethod *
697 method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typespec_context,
698                        gboolean *used_context)
699 {
700         MonoClass *klass = NULL;
701         MonoMethod *method = NULL;
702         MonoTableInfo *tables = image->tables;
703         guint32 cols[6];
704         guint32 nindex, class;
705         const char *mname;
706         MonoMethodSignature *sig;
707         const char *ptr;
708
709         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
710         nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
711         class = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
712         /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
713                 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
714
715         mname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
716
717         /*
718          * Whether we actually used the `typespec_context' or not.
719          * This is used to tell our caller whether or not it's safe to insert the returned
720          * method into a cache.
721          */
722         if (used_context)
723                 *used_context = class == MONO_MEMBERREF_PARENT_TYPESPEC;
724
725         switch (class) {
726         case MONO_MEMBERREF_PARENT_TYPEREF:
727                 klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
728                 if (!klass) {
729                         char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_REF | nindex);
730                         g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
731                         mono_loader_set_error_method_load (name, mname);
732                         g_free (name);
733                         return NULL;
734                 }
735                 break;
736         case MONO_MEMBERREF_PARENT_TYPESPEC:
737                 /*
738                  * Parse the TYPESPEC in the parent's context.
739                  */
740                 klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, typespec_context);
741                 if (!klass) {
742                         char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_SPEC | nindex);
743                         g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
744                         mono_loader_set_error_method_load (name, mname);
745                         g_free (name);
746                         return NULL;
747                 }
748                 break;
749         case MONO_MEMBERREF_PARENT_TYPEDEF:
750                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex);
751                 if (!klass) {
752                         char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_DEF | nindex);
753                         g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
754                         mono_loader_set_error_method_load (name, mname);
755                         g_free (name);
756                         return NULL;
757                 }
758                 break;
759         case MONO_MEMBERREF_PARENT_METHODDEF:
760                 return mono_get_method (image, MONO_TOKEN_METHOD_DEF | nindex, NULL);
761                 
762         default:
763                 {
764                         /* This message leaks */
765                         char *message = g_strdup_printf ("Memberref parent unknown: class: %d, index %d", class, nindex);
766                         mono_loader_set_error_method_load ("", message);
767                         return NULL;
768                 }
769
770         }
771         g_assert (klass);
772         mono_class_init (klass);
773
774         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
775         mono_metadata_decode_blob_size (ptr, &ptr);
776
777         sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
778         if (sig == NULL)
779                 return NULL;
780
781         switch (class) {
782         case MONO_MEMBERREF_PARENT_TYPEREF:
783         case MONO_MEMBERREF_PARENT_TYPEDEF:
784                 method = find_method (klass, NULL, mname, sig, klass);
785                 break;
786
787         case MONO_MEMBERREF_PARENT_TYPESPEC: {
788                 MonoType *type;
789                 MonoMethod *result;
790
791                 type = &klass->byval_arg;
792
793                 if (type->type != MONO_TYPE_ARRAY && type->type != MONO_TYPE_SZARRAY) {
794                         MonoClass *in_class = klass->generic_class ? klass->generic_class->container_class : klass;
795                         method = find_method (in_class, NULL, mname, sig, klass);
796                         break;
797                 }
798
799                 /* we're an array and we created these methods already in klass in mono_class_init () */
800                 result = search_in_array_class (klass, mname, sig);
801                 if (result)
802                         return result;
803
804                 g_assert_not_reached ();
805                 break;
806         }
807         default:
808                 g_error ("Memberref parent unknown: class: %d, index %d", class, nindex);
809                 g_assert_not_reached ();
810         }
811
812         if (!method) {
813                 char *msig = mono_signature_get_desc (sig, FALSE);
814                 char * class_name = mono_type_get_name (&klass->byval_arg);
815                 GString *s = g_string_new (mname);
816                 if (sig->generic_param_count)
817                         g_string_append_printf (s, "<[%d]>", sig->generic_param_count);
818                 g_string_append_printf (s, "(%s)", msig);
819                 g_free (msig);
820                 msig = g_string_free (s, FALSE);
821
822                 g_warning (
823                         "Missing method %s::%s in assembly %s, referenced in assembly %s",
824                         class_name, msig, klass->image->name, image->name);
825                 mono_loader_set_error_method_load (class_name, mname);
826                 g_free (msig);
827                 g_free (class_name);
828         }
829         mono_metadata_free_method_signature (sig);
830
831         return method;
832 }
833
834 static MonoMethod *
835 method_from_methodspec (MonoImage *image, MonoGenericContext *context, guint32 idx)
836 {
837         MonoMethod *method, *inflated;
838         MonoClass *klass;
839         MonoTableInfo *tables = image->tables;
840         MonoGenericContext new_context;
841         MonoGenericInst *inst;
842         const char *ptr;
843         guint32 cols [MONO_METHODSPEC_SIZE];
844         guint32 token, nindex, param_count;
845
846         mono_metadata_decode_row (&tables [MONO_TABLE_METHODSPEC], idx - 1, cols, MONO_METHODSPEC_SIZE);
847         token = cols [MONO_METHODSPEC_METHOD];
848         nindex = token >> MONO_METHODDEFORREF_BITS;
849
850         ptr = mono_metadata_blob_heap (image, cols [MONO_METHODSPEC_SIGNATURE]);
851
852         mono_metadata_decode_value (ptr, &ptr);
853         ptr++;
854         param_count = mono_metadata_decode_value (ptr, &ptr);
855         g_assert (param_count);
856
857         /*
858          * Be careful with the two contexts here:
859          *
860          * ----------------------------------------
861          * class Foo<S> {
862          *   static void Hello<T> (S s, T t) { }
863          *
864          *   static void Test<U> (U u) {
865          *     Foo<U>.Hello<string> (u, "World");
866          *   }
867          * }
868          * ----------------------------------------
869          *
870          * Let's assume we're currently JITing Foo<int>.Test<long>
871          * (ie. `S' is instantiated as `int' and `U' is instantiated as `long').
872          *
873          * The call to Hello() is encoded with a MethodSpec with a TypeSpec as parent
874          * (MONO_MEMBERREF_PARENT_TYPESPEC).
875          *
876          * The TypeSpec is encoded as `Foo<!!0>', so we need to parse it in the current
877          * context (S=int, U=long) to get the correct `Foo<long>'.
878          * 
879          * After that, we parse the memberref signature in the new context
880          * (S=int, T=uninstantiated) and get the open generic method `Foo<long>.Hello<T>'.
881          *
882          */
883         if ((token & MONO_METHODDEFORREF_MASK) == MONO_METHODDEFORREF_METHODDEF)
884                 method = mono_get_method_full (image, MONO_TOKEN_METHOD_DEF | nindex, NULL, context);
885         else
886                 method = method_from_memberref (image, nindex, context, NULL);
887
888         klass = method->klass;
889
890         /* FIXME: Is this invalid metadata?  Should we throw an exception instead?  */
891         g_assert (!klass->generic_container);
892
893         if (klass->generic_class) {
894                 g_assert (method->is_inflated);
895                 method = ((MonoMethodInflated *) method)->declaring;
896         }
897
898         new_context.class_inst = klass->generic_class ? klass->generic_class->context.class_inst : NULL;
899
900         /*
901          * When parsing the methodspec signature, we're in the old context again:
902          *
903          * ----------------------------------------
904          * class Foo {
905          *   static void Hello<T> (T t) { }
906          *
907          *   static void Test<U> (U u) {
908          *     Foo.Hello<U> (u);
909          *   }
910          * }
911          * ----------------------------------------
912          *
913          * Let's assume we're currently JITing "Foo.Test<float>".
914          *
915          * In this case, we already parsed the memberref as "Foo.Hello<T>" and the methodspec
916          * signature is "<!!0>".  This means that we must instantiate the method type parameter
917          * `T' from the new method with the method type parameter `U' from the current context;
918          * ie. instantiate the method as `Foo.Hello<float>.
919          */
920
921         inst = mono_metadata_parse_generic_inst (image, NULL, param_count, ptr, &ptr);
922
923         if (context && inst->is_open)
924                 inst = mono_metadata_inflate_generic_inst (inst, context);
925
926         new_context.method_inst = inst;
927
928         inflated = mono_class_inflate_generic_method_full (method, klass, &new_context);
929
930         return inflated;
931 }
932
933 struct _MonoDllMap {
934         char *dll;
935         char *target;
936         char *func;
937         char *target_func;
938         MonoDllMap *next;
939 };
940
941 static MonoDllMap *global_dll_map;
942
943 static int 
944 mono_dllmap_lookup_list (MonoDllMap *dll_map, const char *dll, const char* func, const char **rdll, const char **rfunc) {
945         int found = 0;
946
947         *rdll = dll;
948
949         if (!dll_map)
950                 return 0;
951
952         mono_loader_lock ();
953
954         /* 
955          * we use the first entry we find that matches, since entries from
956          * the config file are prepended to the list and we document that the
957          * later entries win.
958          */
959         for (; dll_map; dll_map = dll_map->next) {
960                 if (dll_map->dll [0] == 'i' && dll_map->dll [1] == ':') {
961                         if (g_ascii_strcasecmp (dll_map->dll + 2, dll))
962                                 continue;
963                 } else if (strcmp (dll_map->dll, dll)) {
964                         continue;
965                 }
966                 if (!found && dll_map->target) {
967                         *rdll = dll_map->target;
968                         found = 1;
969                         /* we don't quit here, because we could find a full
970                          * entry that matches also function and that has priority.
971                          */
972                 }
973                 if (dll_map->func && strcmp (dll_map->func, func) == 0) {
974                         *rfunc = dll_map->target_func;
975                         break;
976                 }
977         }
978
979         mono_loader_unlock ();
980         return found;
981 }
982
983 static int 
984 mono_dllmap_lookup (MonoImage *assembly, const char *dll, const char* func, const char **rdll, const char **rfunc)
985 {
986         int res;
987         if (assembly && assembly->dll_map) {
988                 res = mono_dllmap_lookup_list (assembly->dll_map, dll, func, rdll, rfunc);
989                 if (res)
990                         return res;
991         }
992         return mono_dllmap_lookup_list (global_dll_map, dll, func, rdll, rfunc);
993 }
994
995 void
996 mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc) {
997         MonoDllMap *entry;
998
999         mono_loader_lock ();
1000
1001         if (!assembly) {
1002                 entry = g_malloc0 (sizeof (MonoDllMap));
1003                 entry->dll = dll? g_strdup (dll): NULL;
1004                 entry->target = tdll? g_strdup (tdll): NULL;
1005                 entry->func = func? g_strdup (func): NULL;
1006                 entry->target_func = tfunc? g_strdup (tfunc): NULL;
1007                 entry->next = global_dll_map;
1008                 global_dll_map = entry;
1009         } else {
1010                 MonoMemPool *mpool = assembly->mempool;
1011                 entry = mono_mempool_alloc0 (mpool, sizeof (MonoDllMap));
1012                 entry->dll = dll? mono_mempool_strdup (mpool, dll): NULL;
1013                 entry->target = tdll? mono_mempool_strdup (mpool, tdll): NULL;
1014                 entry->func = func? mono_mempool_strdup (mpool, func): NULL;
1015                 entry->target_func = tfunc? mono_mempool_strdup (mpool, tfunc): NULL;
1016                 entry->next = assembly->dll_map;
1017                 assembly->dll_map = entry;
1018         }
1019
1020         mono_loader_unlock ();
1021 }
1022
1023 static GHashTable *global_module_map;
1024
1025 static MonoDl*
1026 cached_module_load (const char *name, int flags, char **err)
1027 {
1028         MonoDl *res;
1029         mono_loader_lock ();
1030         if (!global_module_map)
1031                 global_module_map = g_hash_table_new (g_str_hash, g_str_equal);
1032         res = g_hash_table_lookup (global_module_map, name);
1033         if (res) {
1034                 *err = NULL;
1035                 mono_loader_unlock ();
1036                 return res;
1037         }
1038         res = mono_dl_open (name, flags, err);
1039         if (res)
1040                 g_hash_table_insert (global_module_map, g_strdup (name), res);
1041         mono_loader_unlock ();
1042         return res;
1043 }
1044
1045 gpointer
1046 mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char **exc_arg)
1047 {
1048         MonoImage *image = method->klass->image;
1049         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
1050         MonoTableInfo *tables = image->tables;
1051         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
1052         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
1053         guint32 im_cols [MONO_IMPLMAP_SIZE];
1054         guint32 scope_token;
1055         const char *import = NULL;
1056         const char *orig_scope;
1057         const char *new_scope;
1058         char *error_msg;
1059         char *full_name, *file_name;
1060         int i;
1061         MonoDl *module = NULL;
1062
1063         g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
1064
1065         if (piinfo->addr)
1066                 return piinfo->addr;
1067
1068         if (method->klass->image->dynamic) {
1069                 MonoReflectionMethodAux *method_aux = 
1070                         g_hash_table_lookup (
1071                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1072                 if (!method_aux)
1073                         return NULL;
1074
1075                 import = method_aux->dllentry;
1076                 orig_scope = method_aux->dll;
1077         }
1078         else {
1079                 if (!piinfo->implmap_idx)
1080                         return NULL;
1081
1082                 mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
1083
1084                 piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
1085                 import = mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]);
1086                 scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME);
1087                 orig_scope = mono_metadata_string_heap (image, scope_token);
1088         }
1089
1090         mono_dllmap_lookup (image, orig_scope, import, &new_scope, &import);
1091
1092         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1093                         "DllImport attempting to load: '%s'.", new_scope);
1094
1095         if (exc_class) {
1096                 *exc_class = NULL;
1097                 *exc_arg = NULL;
1098         }
1099
1100         /* we allow a special name to dlopen from the running process namespace */
1101         if (strcmp (new_scope, "__Internal") == 0)
1102                 module = mono_dl_open (NULL, MONO_DL_LAZY, &error_msg);
1103
1104         /*
1105          * Try loading the module using a variety of names
1106          */
1107         for (i = 0; i < 4; ++i) {
1108                 switch (i) {
1109                 case 0:
1110                         /* Try the original name */
1111                         file_name = g_strdup (new_scope);
1112                         break;
1113                 case 1:
1114                         /* Try trimming the .dll extension */
1115                         if (strstr (new_scope, ".dll") == (new_scope + strlen (new_scope) - 4)) {
1116                                 file_name = g_strdup (new_scope);
1117                                 file_name [strlen (new_scope) - 4] = '\0';
1118                         }
1119                         else
1120                                 continue;
1121                         break;
1122                 case 2:
1123                         if (strstr (new_scope, "lib") != new_scope) {
1124                                 file_name = g_strdup_printf ("lib%s", new_scope);
1125                         }
1126                         else
1127                                 continue;
1128                         break;
1129                 default:
1130 #ifndef PLATFORM_WIN32
1131                         if (!g_ascii_strcasecmp ("user32.dll", new_scope) ||
1132                             !g_ascii_strcasecmp ("kernel32.dll", new_scope) ||
1133                             !g_ascii_strcasecmp ("user32", new_scope) ||
1134                             !g_ascii_strcasecmp ("kernel", new_scope)) {
1135                                 file_name = g_strdup ("libMonoSupportW.so");
1136                         } else
1137 #endif
1138                                     continue;
1139 #ifndef PLATFORM_WIN32
1140                         break;
1141 #endif
1142                 }
1143
1144                 if (!module) {
1145                         void *iter = NULL;
1146                         while ((full_name = mono_dl_build_path (NULL, file_name, &iter))) {
1147                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1148                                                 "DllImport loading location: '%s'.", full_name);
1149                                 module = cached_module_load (full_name, MONO_DL_LAZY, &error_msg);
1150                                 if (!module) {
1151                                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1152                                                         "DllImport error loading library: '%s'.",
1153                                                         error_msg);
1154                                         g_free (error_msg);
1155                                 }
1156                                 g_free (full_name);
1157                                 if (module)
1158                                         break;
1159                         }
1160                 }
1161
1162                 if (!module) {
1163                         void *iter = NULL;
1164                         while ((full_name = mono_dl_build_path (".", file_name, &iter))) {
1165                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1166                                         "DllImport loading library: '%s'.", full_name);
1167                                 module = cached_module_load (full_name, MONO_DL_LAZY, &error_msg);
1168                                 if (!module) {
1169                                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1170                                                 "DllImport error loading library '%s'.",
1171                                                 error_msg);
1172                                         g_free (error_msg);
1173                                 }
1174                                 g_free (full_name);
1175                                 if (module)
1176                                         break;
1177                         }
1178                 }
1179
1180                 if (!module) {
1181                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1182                                         "DllImport loading: '%s'.", file_name);
1183                         module = cached_module_load (file_name, MONO_DL_LAZY, &error_msg);
1184                         if (!module) {
1185                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1186                                                 "DllImport error loading library '%s'.",
1187                                                 error_msg);
1188                         }
1189                 }
1190
1191                 g_free (file_name);
1192
1193                 if (module)
1194                         break;
1195         }
1196
1197         if (!module) {
1198                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_DLLIMPORT,
1199                                 "DllImport unable to load library '%s'.",
1200                                 error_msg);
1201                 g_free (error_msg);
1202
1203                 if (exc_class) {
1204                         *exc_class = "DllNotFoundException";
1205                         *exc_arg = new_scope;
1206                 }
1207                 return NULL;
1208         }
1209
1210         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1211                                 "Searching for '%s'.", import);
1212
1213         if (piinfo->piflags & PINVOKE_ATTRIBUTE_NO_MANGLE) {
1214                 error_msg = mono_dl_symbol (module, import, &piinfo->addr); 
1215         } else {
1216                 char *mangled_name = NULL, *mangled_name2 = NULL;
1217                 int mangle_charset;
1218                 int mangle_stdcall;
1219                 int mangle_param_count;
1220 #ifdef PLATFORM_WIN32
1221                 int param_count;
1222 #endif
1223
1224                 /*
1225                  * Search using a variety of mangled names
1226                  */
1227                 for (mangle_charset = 0; mangle_charset <= 1; mangle_charset ++) {
1228                         for (mangle_stdcall = 0; mangle_stdcall <= 1; mangle_stdcall ++) {
1229                                 gboolean need_param_count = FALSE;
1230 #ifdef PLATFORM_WIN32
1231                                 if (mangle_stdcall > 0)
1232                                         need_param_count = TRUE;
1233 #endif
1234                                 for (mangle_param_count = 0; mangle_param_count <= (need_param_count ? 256 : 0); mangle_param_count += 4) {
1235
1236                                         if (piinfo->addr)
1237                                                 continue;
1238
1239                                         mangled_name = (char*)import;
1240                                         switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
1241                                         case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
1242                                                 /* Try the mangled name first */
1243                                                 if (mangle_charset == 0)
1244                                                         mangled_name = g_strconcat (import, "W", NULL);
1245                                                 break;
1246                                         case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
1247 #ifdef PLATFORM_WIN32
1248                                                 if (mangle_charset == 0)
1249                                                         mangled_name = g_strconcat (import, "W", NULL);
1250 #else
1251                                                 /* Try the mangled name last */
1252                                                 if (mangle_charset == 1)
1253                                                         mangled_name = g_strconcat (import, "A", NULL);
1254 #endif
1255                                                 break;
1256                                         case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
1257                                         default:
1258                                                 /* Try the mangled name last */
1259                                                 if (mangle_charset == 1)
1260                                                         mangled_name = g_strconcat (import, "A", NULL);
1261                                                 break;
1262                                         }
1263
1264 #ifdef PLATFORM_WIN32
1265                                         if (mangle_param_count == 0)
1266                                                 param_count = mono_method_signature (method)->param_count * sizeof (gpointer);
1267                                         else
1268                                                 /* Try brute force, since it would be very hard to compute the stack usage correctly */
1269                                                 param_count = mangle_param_count;
1270
1271                                         /* Try the stdcall mangled name */
1272                                         /* 
1273                                          * gcc under windows creates mangled names without the underscore, but MS.NET
1274                                          * doesn't support it, so we doesn't support it either.
1275                                          */
1276                                         if (mangle_stdcall == 1)
1277                                                 mangled_name2 = g_strdup_printf ("_%s@%d", mangled_name, param_count);
1278                                         else
1279                                                 mangled_name2 = mangled_name;
1280 #else
1281                                         mangled_name2 = mangled_name;
1282 #endif
1283
1284                                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1285                                                                 "Probing '%s'.", mangled_name2);
1286
1287                                         error_msg = mono_dl_symbol (module, mangled_name2, &piinfo->addr);
1288
1289                                         if (piinfo->addr)
1290                                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1291                                                                         "Found as '%s'.", mangled_name2);
1292
1293                                         if (mangled_name != mangled_name2)
1294                                                 g_free (mangled_name2);
1295                                         if (mangled_name != import)
1296                                                 g_free (mangled_name);
1297                                 }
1298                         }
1299                 }
1300         }
1301
1302         if (!piinfo->addr) {
1303                 g_free (error_msg);
1304                 if (exc_class) {
1305                         *exc_class = "EntryPointNotFoundException";
1306                         *exc_arg = import;
1307                 }
1308                 return NULL;
1309         }
1310         return piinfo->addr;
1311 }
1312
1313 /*
1314  * LOCKING: assumes the loader lock to be taken.
1315  */
1316 static MonoMethod *
1317 mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
1318                             MonoGenericContext *context, gboolean *used_context)
1319 {
1320         MonoMethod *result;
1321         int table = mono_metadata_token_table (token);
1322         int idx = mono_metadata_token_index (token);
1323         MonoTableInfo *tables = image->tables;
1324         MonoGenericContainer *generic_container = NULL, *container = NULL;
1325         const char *sig = NULL;
1326         int size, i;
1327         guint32 cols [MONO_TYPEDEF_SIZE];
1328
1329         if (image->dynamic)
1330                 return mono_lookup_dynamic_token (image, token);
1331
1332         if (table != MONO_TABLE_METHOD) {
1333                 if (table == MONO_TABLE_METHODSPEC) {
1334                         if (used_context) *used_context = TRUE;
1335                         return method_from_methodspec (image, context, idx);
1336                 }
1337                 if (table != MONO_TABLE_MEMBERREF)
1338                         g_print("got wrong token: 0x%08x\n", token);
1339                 g_assert (table == MONO_TABLE_MEMBERREF);
1340                 return method_from_memberref (image, idx, context, used_context);
1341         }
1342
1343         if (used_context) *used_context = FALSE;
1344
1345         mono_metadata_decode_row (&image->tables [MONO_TABLE_METHOD], idx - 1, cols, 6);
1346
1347         if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1348             (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
1349                 result = (MonoMethod *)mono_mempool_alloc0 (image->mempool, sizeof (MonoMethodPInvoke));
1350         else
1351                 result = (MonoMethod *)mono_mempool_alloc0 (image->mempool, sizeof (MonoMethodNormal));
1352
1353         mono_stats.method_count ++;
1354
1355         if (!klass) {
1356                 guint32 type = mono_metadata_typedef_from_method (image, token);
1357                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
1358                 if (klass == NULL)
1359                         return NULL;
1360         }
1361
1362         result->slot = -1;
1363         result->klass = klass;
1364         result->flags = cols [2];
1365         result->iflags = cols [1];
1366         result->token = token;
1367         result->name = mono_metadata_string_heap (image, cols [3]);
1368
1369         container = klass->generic_container;
1370         generic_container = mono_metadata_load_generic_params (image, token, container);
1371         if (generic_container) {
1372                 generic_container->owner.method = result;
1373
1374                 mono_metadata_load_generic_param_constraints (image, token, generic_container);
1375
1376                 for (i = 0; i < generic_container->type_argc; i++)
1377                         mono_class_from_generic_parameter (&generic_container->type_params [i], image, TRUE);
1378
1379                 container = generic_container;
1380         }
1381
1382
1383         if (!sig) /* already taken from the methodref */
1384                 sig = mono_metadata_blob_heap (image, cols [4]);
1385         size = mono_metadata_decode_blob_size (sig, &sig);
1386
1387         if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1388                 if (result->klass == mono_defaults.string_class && !strcmp (result->name, ".ctor"))
1389                         result->string_ctor = 1;
1390         } else if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (!(cols [1] & METHOD_IMPL_ATTRIBUTE_NATIVE))) {
1391                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)result;
1392                 MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
1393
1394                 piinfo->implmap_idx = mono_metadata_implmap_from_method (image, idx - 1);
1395                 piinfo->piflags = mono_metadata_decode_row_col (im, piinfo->implmap_idx - 1, MONO_IMPLMAP_FLAGS);
1396         }
1397
1398         /* FIXME: lazyness for generics too, but how? */
1399         if (!(result->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
1400             !(cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
1401             !(result->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) && container) {
1402                 gpointer loc = mono_image_rva_map (image, cols [0]);
1403                 g_assert (loc);
1404                 ((MonoMethodNormal *) result)->header = mono_metadata_parse_mh_full (image, container, loc);
1405         }
1406
1407         result->generic_container = generic_container;
1408
1409         return result;
1410 }
1411
1412 MonoMethod *
1413 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
1414 {
1415         return mono_get_method_full (image, token, klass, NULL);
1416 }
1417
1418 MonoMethod *
1419 mono_get_method_full (MonoImage *image, guint32 token, MonoClass *klass,
1420                       MonoGenericContext *context)
1421 {
1422         MonoMethod *result;
1423         gboolean used_context = FALSE;
1424
1425         /* We do everything inside the lock to prevent creation races */
1426
1427         mono_loader_lock ();
1428
1429         if ((result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token)))) {
1430                 mono_loader_unlock ();
1431                 return result;
1432         }
1433
1434         result = mono_get_method_from_token (image, token, klass, context, &used_context);
1435
1436         //printf ("GET: %s\n", mono_method_full_name (result, TRUE));
1437
1438 #if 0
1439         g_message (G_STRLOC ": %s - %d - %d", mono_method_full_name (result, TRUE),
1440                    result->is_inflated, used_context);
1441 #endif
1442
1443         /*
1444          * `used_context' specifies whether or not mono_get_method_from_token() actually
1445          * used the `context' to get the method.  See bug #80969.
1446          */
1447
1448         if (!used_context && !(result && result->is_inflated))
1449                 g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
1450
1451         mono_loader_unlock ();
1452
1453         return result;
1454 }
1455
1456 /**
1457  * mono_get_method_constrained:
1458  *
1459  * This is used when JITing the `constrained.' opcode.
1460  *
1461  * This returns two values: the contrained method, which has been inflated
1462  * as the function return value;   And the original CIL-stream method as
1463  * declared in cil_method.  The later is used for verification.
1464  */
1465 MonoMethod *
1466 mono_get_method_constrained (MonoImage *image, guint32 token, MonoClass *constrained_class,
1467                              MonoGenericContext *context, MonoMethod **cil_method)
1468 {
1469         MonoMethod *method, *result;
1470         MonoClass *ic = NULL;
1471         MonoGenericContext *class_context = NULL, *method_context = NULL;
1472         MonoMethodSignature *sig;
1473
1474         mono_loader_lock ();
1475
1476         *cil_method = mono_get_method_from_token (image, token, NULL, context, NULL);
1477         if (!*cil_method) {
1478                 mono_loader_unlock ();
1479                 return NULL;
1480         }
1481
1482         mono_class_init (constrained_class);
1483         method = *cil_method;
1484         sig = mono_method_signature (method);
1485
1486         if (method->is_inflated && sig->generic_param_count) {
1487                 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1488                 sig = mono_method_signature (imethod->declaring);
1489                 method_context = mono_method_get_context (method);
1490         }
1491
1492         if ((constrained_class != method->klass) && (method->klass->interface_id != 0))
1493                 ic = method->klass;
1494
1495         if (constrained_class->generic_class)
1496                 class_context = mono_class_get_context (constrained_class);
1497
1498         result = find_method (constrained_class, ic, method->name, sig, constrained_class);
1499         if (!result) {
1500                 g_warning ("Missing method %s.%s.%s in assembly %s token %x", method->klass->name_space,
1501                            method->klass->name, method->name, image->name, token);
1502                 mono_loader_unlock ();
1503                 return NULL;
1504         }
1505
1506         if (class_context)
1507                 result = mono_class_inflate_generic_method (result, class_context);
1508         if (method_context)
1509                 result = mono_class_inflate_generic_method (result, method_context);
1510
1511         mono_loader_unlock ();
1512         return result;
1513 }
1514
1515 void
1516 mono_free_method  (MonoMethod *method)
1517 {
1518         if (mono_profiler_get_events () != MONO_PROFILE_NONE)
1519                 return;
1520         
1521         if (method->signature) {
1522                 /* 
1523                  * FIXME: This causes crashes because the types inside signatures and
1524                  * locals are shared.
1525                  */
1526                 /* mono_metadata_free_method_signature (method->signature); */
1527                 /* g_free (method->signature); */
1528         }
1529         
1530         if (method->dynamic) {
1531                 MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
1532                 int i;
1533
1534                 g_free ((char*)method->name);
1535                 if (mw->method.header) {
1536                         g_free ((char*)mw->method.header->code);
1537                         for (i = 0; i < mw->method.header->num_locals; ++i)
1538                                 g_free (mw->method.header->locals [i]);
1539                         g_free (mw->method.header->clauses);
1540                         g_free (mw->method.header);
1541                 }
1542                 g_free (mw->method_data);
1543                 g_free (method->signature);
1544                 g_free (method);
1545         }
1546 }
1547
1548 void
1549 mono_method_get_param_names (MonoMethod *method, const char **names)
1550 {
1551         int i, lastp;
1552         MonoClass *klass = method->klass;
1553         MonoTableInfo *methodt;
1554         MonoTableInfo *paramt;
1555         guint32 idx;
1556
1557         if (!mono_method_signature (method)->param_count)
1558                 return;
1559         for (i = 0; i < mono_method_signature (method)->param_count; ++i)
1560                 names [i] = "";
1561
1562         if (klass->generic_class || klass->rank) /* copy the names later */
1563                 return;
1564
1565         mono_class_init (klass);
1566
1567         if (klass->image->dynamic) {
1568                 MonoReflectionMethodAux *method_aux = 
1569                         g_hash_table_lookup (
1570                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1571                 if (method_aux && method_aux->param_names) {
1572                         for (i = 0; i < mono_method_signature (method)->param_count; ++i)
1573                                 if (method_aux->param_names [i + 1])
1574                                         names [i] = method_aux->param_names [i + 1];
1575                 }
1576                 return;
1577         }
1578
1579         methodt = &klass->image->tables [MONO_TABLE_METHOD];
1580         paramt = &klass->image->tables [MONO_TABLE_PARAM];
1581         idx = mono_method_get_index (method);
1582         if (idx > 0) {
1583                 guint32 cols [MONO_PARAM_SIZE];
1584                 guint param_index;
1585
1586                 param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
1587
1588                 if (idx < methodt->rows)
1589                         lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
1590                 else
1591                         lastp = paramt->rows + 1;
1592                 for (i = param_index; i < lastp; ++i) {
1593                         mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
1594                         if (cols [MONO_PARAM_SEQUENCE]) /* skip return param spec */
1595                                 names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass->image, cols [MONO_PARAM_NAME]);
1596                 }
1597                 return;
1598         }
1599 }
1600
1601 guint32
1602 mono_method_get_param_token (MonoMethod *method, int index)
1603 {
1604         MonoClass *klass = method->klass;
1605         MonoTableInfo *methodt;
1606         guint32 idx;
1607
1608         mono_class_init (klass);
1609
1610         if (klass->image->dynamic) {
1611                 g_assert_not_reached ();
1612         }
1613
1614         methodt = &klass->image->tables [MONO_TABLE_METHOD];
1615         idx = mono_method_get_index (method);
1616         if (idx > 0) {
1617                 guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
1618
1619                 if (index == -1)
1620                         /* Return value */
1621                         return mono_metadata_make_token (MONO_TABLE_PARAM, 0);
1622                 else
1623                         return mono_metadata_make_token (MONO_TABLE_PARAM, param_index + index);
1624         }
1625
1626         return 0;
1627 }
1628
1629 void
1630 mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs)
1631 {
1632         int i, lastp;
1633         MonoClass *klass = method->klass;
1634         MonoTableInfo *methodt;
1635         MonoTableInfo *paramt;
1636         guint32 idx;
1637
1638         for (i = 0; i < mono_method_signature (method)->param_count + 1; ++i)
1639                 mspecs [i] = NULL;
1640
1641         if (method->klass->image->dynamic) {
1642                 MonoReflectionMethodAux *method_aux = 
1643                         g_hash_table_lookup (
1644                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1645                 if (method_aux && method_aux->param_marshall) {
1646                         MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
1647                         for (i = 0; i < mono_method_signature (method)->param_count + 1; ++i)
1648                                 if (dyn_specs [i]) {
1649                                         mspecs [i] = g_new0 (MonoMarshalSpec, 1);
1650                                         memcpy (mspecs [i], dyn_specs [i], sizeof (MonoMarshalSpec));
1651                                 }
1652                 }
1653                 return;
1654         }
1655
1656         mono_class_init (klass);
1657
1658         methodt = &klass->image->tables [MONO_TABLE_METHOD];
1659         paramt = &klass->image->tables [MONO_TABLE_PARAM];
1660         idx = mono_method_get_index (method);
1661         if (idx > 0) {
1662                 guint32 cols [MONO_PARAM_SIZE];
1663                 guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
1664
1665                 if (idx < methodt->rows)
1666                         lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
1667                 else
1668                         lastp = paramt->rows + 1;
1669
1670                 for (i = param_index; i < lastp; ++i) {
1671                         mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
1672
1673                         if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) {
1674                                 const char *tp;
1675                                 tp = mono_metadata_get_marshal_info (klass->image, i - 1, FALSE);
1676                                 g_assert (tp);
1677                                 mspecs [cols [MONO_PARAM_SEQUENCE]]= mono_metadata_parse_marshal_spec (klass->image, tp);
1678                         }
1679                 }
1680
1681                 return;
1682         }
1683 }
1684
1685 gboolean
1686 mono_method_has_marshal_info (MonoMethod *method)
1687 {
1688         int i, lastp;
1689         MonoClass *klass = method->klass;
1690         MonoTableInfo *methodt;
1691         MonoTableInfo *paramt;
1692         guint32 idx;
1693
1694         if (method->klass->image->dynamic) {
1695                 MonoReflectionMethodAux *method_aux = 
1696                         g_hash_table_lookup (
1697                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1698                 MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
1699                 if (dyn_specs) {
1700                         for (i = 0; i < mono_method_signature (method)->param_count + 1; ++i)
1701                                 if (dyn_specs [i])
1702                                         return TRUE;
1703                 }
1704                 return FALSE;
1705         }
1706
1707         mono_class_init (klass);
1708
1709         methodt = &klass->image->tables [MONO_TABLE_METHOD];
1710         paramt = &klass->image->tables [MONO_TABLE_PARAM];
1711         idx = mono_method_get_index (method);
1712         if (idx > 0) {
1713                 guint32 cols [MONO_PARAM_SIZE];
1714                 guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
1715
1716                 if (idx + 1 < methodt->rows)
1717                         lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
1718                 else
1719                         lastp = paramt->rows + 1;
1720
1721                 for (i = param_index; i < lastp; ++i) {
1722                         mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
1723
1724                         if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL)
1725                                 return TRUE;
1726                 }
1727                 return FALSE;
1728         }
1729         return FALSE;
1730 }
1731
1732 gpointer
1733 mono_method_get_wrapper_data (MonoMethod *method, guint32 id)
1734 {
1735         void **data;
1736         g_assert (method != NULL);
1737         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
1738
1739         data = ((MonoMethodWrapper *)method)->method_data;
1740         g_assert (data != NULL);
1741         g_assert (id <= GPOINTER_TO_UINT (*data));
1742         return data [id];
1743 }
1744
1745 static void
1746 default_stack_walk (MonoStackWalk func, gboolean do_il_offset, gpointer user_data) {
1747         g_error ("stack walk not installed");
1748 }
1749
1750 static MonoStackWalkImpl stack_walk = default_stack_walk;
1751
1752 void
1753 mono_stack_walk (MonoStackWalk func, gpointer user_data)
1754 {
1755         stack_walk (func, TRUE, user_data);
1756 }
1757
1758 void
1759 mono_stack_walk_no_il (MonoStackWalk func, gpointer user_data)
1760 {
1761         stack_walk (func, FALSE, user_data);
1762 }
1763
1764 void
1765 mono_install_stack_walk (MonoStackWalkImpl func)
1766 {
1767         stack_walk = func;
1768 }
1769
1770 static gboolean
1771 last_managed (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
1772 {
1773         MonoMethod **dest = data;
1774         *dest = m;
1775         /*g_print ("In %s::%s [%d] [%d]\n", m->klass->name, m->name, no, ilo);*/
1776
1777         return managed;
1778 }
1779
1780 MonoMethod*
1781 mono_method_get_last_managed (void)
1782 {
1783         MonoMethod *m = NULL;
1784         stack_walk (last_managed, FALSE, &m);
1785         return m;
1786 }
1787
1788 void
1789 mono_loader_lock (void)
1790 {
1791         EnterCriticalSection (&loader_mutex);
1792 }
1793
1794 void
1795 mono_loader_unlock (void)
1796 {
1797         LeaveCriticalSection (&loader_mutex);
1798 }
1799
1800 /**
1801  * mono_method_signature:
1802  *
1803  * Return the signature of the method M. On failure, returns NULL.
1804  */
1805 MonoMethodSignature*
1806 mono_method_signature (MonoMethod *m)
1807 {
1808         int idx;
1809         int size;
1810         MonoImage* img;
1811         const char *sig;
1812         gboolean can_cache_signature;
1813         MonoGenericContainer *container;
1814         int *pattrs;
1815
1816         if (m->signature)
1817                 return m->signature;
1818
1819         mono_loader_lock ();
1820
1821         if (m->signature) {
1822                 mono_loader_unlock ();
1823                 return m->signature;
1824         }
1825
1826         if (m->is_inflated) {
1827                 MonoMethodInflated *imethod = (MonoMethodInflated *) m;
1828                 MonoMethodSignature *signature;
1829                 /* the lock is recursive */
1830                 signature = mono_method_signature (imethod->declaring);
1831                 m->signature = inflate_generic_signature (imethod->declaring->klass->image, signature, mono_method_get_context (m));
1832                 mono_loader_unlock ();
1833                 return m->signature;
1834         }
1835
1836         g_assert (mono_metadata_token_table (m->token) == MONO_TABLE_METHOD);
1837         idx = mono_metadata_token_index (m->token);
1838         img = m->klass->image;
1839
1840         sig = mono_metadata_blob_heap (img, mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_SIGNATURE));
1841
1842         g_assert (!m->klass->generic_class);
1843         container = m->generic_container;
1844         if (!container)
1845                 container = m->klass->generic_container;
1846
1847         /* Generic signatures depend on the container so they cannot be cached */
1848         /* icall/pinvoke signatures cannot be cached cause we modify them below */
1849         can_cache_signature = !(m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !(m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && !container;
1850
1851         /* If the method has parameter attributes, that can modify the signature */
1852         pattrs = mono_metadata_get_param_attrs (img, idx);
1853         if (pattrs) {
1854                 can_cache_signature = FALSE;
1855                 g_free (pattrs);
1856         }
1857
1858         if (can_cache_signature)
1859                 m->signature = g_hash_table_lookup (img->method_signatures, sig);
1860
1861         if (!m->signature) {
1862                 const char *sig_body;
1863
1864                 size = mono_metadata_decode_blob_size (sig, &sig_body);
1865
1866                 m->signature = mono_metadata_parse_method_signature_full (img, container, idx, sig_body, NULL);
1867                 if (!m->signature) {
1868                         mono_loader_unlock ();
1869                         return NULL;
1870                 }
1871
1872                 if (can_cache_signature)
1873                         g_hash_table_insert (img->method_signatures, (gpointer)sig, m->signature);
1874         }
1875
1876         /* Verify metadata consistency */
1877         if (m->signature->generic_param_count) {
1878                 if (!container || !container->is_method)
1879                         g_error ("Signature claims method has generic parameters, but generic_params table says it doesn't");
1880                 if (container->type_argc != m->signature->generic_param_count)
1881                         g_error ("Inconsistent generic parameter count.  Signature says %d, generic_params table says %d",
1882                                  m->signature->generic_param_count, container->type_argc);
1883         } else if (container && container->is_method && container->type_argc)
1884                 g_error ("generic_params table claims method has generic parameters, but signature says it doesn't");
1885
1886         if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
1887                 m->signature->pinvoke = 1;
1888         else if ((m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (!(m->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE))) {
1889                 MonoCallConvention conv = 0;
1890                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)m;
1891                 m->signature->pinvoke = 1;
1892
1893                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CALL_CONV_MASK) {
1894                 case 0: /* no call conv, so using default */
1895                 case PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI:
1896                         conv = MONO_CALL_DEFAULT;
1897                         break;
1898                 case PINVOKE_ATTRIBUTE_CALL_CONV_CDECL:
1899                         conv = MONO_CALL_C;
1900                         break;
1901                 case PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL:
1902                         conv = MONO_CALL_STDCALL;
1903                         break;
1904                 case PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL:
1905                         conv = MONO_CALL_THISCALL;
1906                         break;
1907                 case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL:
1908                         conv = MONO_CALL_FASTCALL;
1909                         break;
1910                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC:
1911                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST:
1912                 default:
1913                         g_warning ("unsupported calling convention : 0x%04x", piinfo->piflags);
1914                         g_assert_not_reached ();
1915                 }
1916                 m->signature->call_convention = conv;
1917         }
1918
1919         mono_loader_unlock ();
1920         return m->signature;
1921 }
1922
1923 const char*
1924 mono_method_get_name (MonoMethod *method)
1925 {
1926         return method->name;
1927 }
1928
1929 MonoClass*
1930 mono_method_get_class (MonoMethod *method)
1931 {
1932         return method->klass;
1933 }
1934
1935 guint32
1936 mono_method_get_token (MonoMethod *method)
1937 {
1938         return method->token;
1939 }
1940
1941 MonoMethodHeader*
1942 mono_method_get_header (MonoMethod *method)
1943 {
1944         int idx;
1945         guint32 rva;
1946         MonoImage* img;
1947         gpointer loc;
1948         MonoMethodNormal* mn = (MonoMethodNormal*) method;
1949
1950         if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
1951                 return NULL;
1952
1953 #ifdef G_LIKELY
1954         if (G_LIKELY (mn->header))
1955 #else
1956         if (mn->header)
1957 #endif
1958                 return mn->header;
1959
1960         mono_loader_lock ();
1961
1962         if (mn->header) {
1963                 mono_loader_unlock ();
1964                 return mn->header;
1965         }
1966
1967         if (method->is_inflated) {
1968                 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1969                 MonoMethodHeader *header;
1970                 /* the lock is recursive */
1971                 header = mono_method_get_header (imethod->declaring);
1972                 mn->header = inflate_generic_header (header, mono_method_get_context (method));
1973                 mono_loader_unlock ();
1974                 return mn->header;
1975         }
1976
1977         g_assert (mono_metadata_token_table (method->token) == MONO_TABLE_METHOD);
1978         idx = mono_metadata_token_index (method->token);
1979         img = method->klass->image;
1980         rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
1981         loc = mono_image_rva_map (img, rva);
1982
1983         g_assert (loc);
1984
1985         mn->header = mono_metadata_parse_mh_full (img, method->generic_container, loc);
1986
1987         mono_loader_unlock ();
1988         return mn->header;
1989 }
1990
1991 guint32
1992 mono_method_get_flags (MonoMethod *method, guint32 *iflags)
1993 {
1994         if (iflags)
1995                 *iflags = method->iflags;
1996         return method->flags;
1997 }
1998
1999 /*
2000  * Find the method index in the metadata methodDef table.
2001  */
2002 guint32
2003 mono_method_get_index (MonoMethod *method) {
2004         MonoClass *klass = method->klass;
2005         int i;
2006
2007         if (method->token)
2008                 return mono_metadata_token_index (method->token);
2009
2010         mono_class_setup_methods (klass);
2011         for (i = 0; i < klass->method.count; ++i) {
2012                 if (method == klass->methods [i]) {
2013                         if (klass->image->uncompressed_metadata)
2014                                 return mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, klass->method.first + i + 1);
2015                         else
2016                                 return klass->method.first + i + 1;
2017                 }
2018         }
2019         return 0;
2020 }
2021