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