2004-08-04 Bernie Solomon <bernard@ugsolutions.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 void
47 mono_loader_init ()
48 {
49         InitializeCriticalSection (&loader_mutex);
50 }
51
52 static MonoClassField*
53 field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
54                       MonoGenericContext *context)
55 {
56         MonoClass *klass;
57         MonoTableInfo *tables = image->tables;
58         guint32 cols[6];
59         guint32 nindex, class;
60         const char *fname;
61         const char *ptr;
62         guint32 idx = mono_metadata_token_index (token);
63
64         if (image->dynamic) {
65                 MonoClassField *result = mono_lookup_dynamic_token (image, token);
66                 *retklass = result->parent;
67                 return result;
68         }
69
70         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
71         nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
72         class = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
73
74         fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
75         
76         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
77         mono_metadata_decode_blob_size (ptr, &ptr);
78         /* we may want to check the signature here... */
79
80         switch (class) {
81         case MONO_MEMBERREF_PARENT_TYPEREF:
82                 klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
83                 if (!klass) {
84                         g_warning ("Missing field %s in typeref index %d", fname, nindex);
85                         return NULL;
86                 }
87                 mono_class_init (klass);
88                 if (retklass)
89                         *retklass = klass;
90                 return mono_class_get_field_from_name (klass, fname);
91         case MONO_MEMBERREF_PARENT_TYPESPEC: {
92                 /*guint32 bcols [MONO_TYPESPEC_SIZE];
93                 guint32 len;
94                 MonoType *type;
95
96                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
97                                           bcols, MONO_TYPESPEC_SIZE);
98                 ptr = mono_metadata_blob_heap (image, bcols [MONO_TYPESPEC_SIGNATURE]);
99                 len = mono_metadata_decode_value (ptr, &ptr);   
100                 type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
101
102                 klass = mono_class_from_mono_type (type);
103                 mono_class_init (klass);
104                 g_print ("type in sig: %s\n", klass->name);*/
105                 klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, context);
106                 mono_class_init (klass);
107                 if (retklass)
108                         *retklass = klass;
109                 return mono_class_get_field_from_name (klass, fname);
110         }
111         default:
112                 g_warning ("field load from %x", class);
113                 return NULL;
114         }
115 }
116
117 MonoClassField*
118 mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass,
119                        MonoGenericContext *context)
120 {
121         MonoClass *k;
122         guint32 type;
123         MonoClassField *field;
124
125         if (image->dynamic) {
126                 MonoClassField *result = mono_lookup_dynamic_token (image, token);
127                 *retklass = result->parent;
128                 return result;
129         }
130
131         mono_loader_lock ();
132         if ((field = g_hash_table_lookup (image->field_cache, GUINT_TO_POINTER (token)))) {
133                 *retklass = field->parent;
134                 mono_loader_unlock ();
135                 return field;
136         }
137         mono_loader_unlock ();
138
139         if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
140                 field = field_from_memberref (image, token, retklass, context);
141         else {
142                 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
143                 if (!type)
144                         return NULL;
145                 k = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
146                 mono_class_init (k);
147                 if (!k)
148                         return NULL;
149                 if (retklass)
150                         *retklass = k;
151                 field = mono_class_get_field (k, token);
152         }
153
154         mono_loader_lock ();
155         if (!field->parent->generic_inst)
156                 g_hash_table_insert (image->field_cache, GUINT_TO_POINTER (token), field);
157         mono_loader_unlock ();
158         return field;
159 }
160
161 static gboolean
162 mono_metadata_signature_vararg_match (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
163 {
164         int i;
165
166         if (sig1->hasthis != sig2->hasthis ||
167             sig1->sentinelpos != sig2->sentinelpos)
168                 return FALSE;
169
170         for (i = 0; i < sig1->sentinelpos; i++) { 
171                 MonoType *p1 = sig1->params[i];
172                 MonoType *p2 = sig2->params[i];
173                 
174                 /*if (p1->attrs != p2->attrs)
175                         return FALSE;
176                 */
177                 if (!mono_metadata_type_equal (p1, p2))
178                         return FALSE;
179         }
180
181         if (!mono_metadata_type_equal (sig1->ret, sig2->ret))
182                 return FALSE;
183         return TRUE;
184 }
185
186 static MonoMethod *
187 find_method (MonoClass *klass, MonoClass *ic, const char* name, MonoMethodSignature *sig)
188 {
189         int i;
190         MonoClass *sclass = klass;
191         char *qname, *fqname;
192
193         if (ic) {
194                 qname = g_strconcat (ic->name, ".", name, NULL); 
195                 if (ic->name_space && ic->name_space [0])
196                         fqname = g_strconcat (ic->name_space, ".", ic->name, ".", name, NULL);
197                 else
198                         fqname = NULL;
199         } else
200                 qname = fqname = NULL;
201
202         while (klass) {
203                 for (i = 0; i < klass->method.count; ++i) {
204                         MonoMethod *m = klass->methods [i];
205
206                         if (!((fqname && !strcmp (m->name, fqname)) ||
207                               (qname && !strcmp (m->name, qname)) || !strcmp (m->name, name)))
208                                 continue;
209
210                         if (sig->call_convention == MONO_CALL_VARARG) {
211                                 if (mono_metadata_signature_vararg_match (sig, m->signature))
212                                         return m;
213                         } else {
214                                 if (mono_metadata_signature_equal (sig, m->signature))
215                                         return m;
216                         }
217                 }
218
219                 if (name [0] == '.' && (strcmp (name, ".ctor") == 0 || strcmp (name, ".cctor") == 0))
220                         break;
221
222                 klass = klass->parent;
223         }
224
225         if (sclass->generic_inst) {
226                 MonoClass *gclass;
227                 MonoMethod *res;
228
229                 gclass = mono_class_from_mono_type (sclass->generic_inst->generic_type);
230                 mono_class_init (gclass);
231
232                 res = find_method (gclass, ic, name, sig);
233                 if (!res)
234                         return NULL;
235                 for (i = 0; i < res->klass->method.count; ++i) {
236                         if (res == res->klass->methods [i]) {
237                                 return sclass->methods [i];
238                         }
239                 }
240         }
241
242         return NULL;
243 }
244
245 /*
246  * token is the method_ref or method_def token used in a call IL instruction.
247  */
248 MonoMethodSignature*
249 mono_method_get_signature (MonoMethod *method, MonoImage *image, guint32 token)
250 {
251         int table = mono_metadata_token_table (token);
252         int idx = mono_metadata_token_index (token);
253         guint32 cols [MONO_MEMBERREF_SIZE];
254         MonoMethodSignature *sig;
255         const char *ptr;
256
257         /* !table is for wrappers: we should really assign their own token to them */
258         if (!table || table == MONO_TABLE_METHOD)
259                 return method->signature;
260
261         if (table == MONO_TABLE_METHODSPEC) {
262                 g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
263                           !(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
264                           method->signature);
265                 g_assert (method->signature->is_inflated);
266
267                 return method->signature;
268         }
269
270         if (method->klass->generic_inst)
271                 return method->signature;
272
273         if (image->dynamic)
274                 /* FIXME: This might be incorrect for vararg methods */
275                 return method->signature;
276
277         if (!(sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (token)))) {
278                 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
279         
280                 ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
281                 mono_metadata_decode_blob_size (ptr, &ptr);
282                 sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
283                 g_hash_table_insert (image->memberref_signatures, GUINT_TO_POINTER (token), sig);
284         }
285
286         return sig;
287 }
288
289 static MonoMethod *
290 method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *context)
291 {
292         MonoClass *klass;
293         MonoMethod *method;
294         MonoTableInfo *tables = image->tables;
295         guint32 cols[6];
296         guint32 nindex, class;
297         const char *mname;
298         MonoMethodSignature *sig;
299         const char *ptr;
300
301         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
302         nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
303         class = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
304         /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
305                 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
306
307         mname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
308         
309         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
310         mono_metadata_decode_blob_size (ptr, &ptr);
311         sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
312
313         switch (class) {
314         case MONO_MEMBERREF_PARENT_TYPEREF:
315                 klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
316                 if (!klass) {
317                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
318                         mono_metadata_free_method_signature (sig);
319                         return NULL;
320                 }
321                 mono_class_init (klass);
322                 method = find_method (klass, NULL, mname, sig);
323                 if (!method)
324                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
325                 mono_metadata_free_method_signature (sig);
326                 return method;
327         case MONO_MEMBERREF_PARENT_TYPESPEC: {
328                 guint32 bcols [MONO_TYPESPEC_SIZE];
329                 guint32 len;
330                 MonoType *type;
331                 MonoMethod *result;
332                 MonoClass *klass;
333
334                 klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, context);
335                 type = &klass->byval_arg;
336
337                 if (type->type != MONO_TYPE_ARRAY && type->type != MONO_TYPE_SZARRAY) {
338                         mono_class_init (klass);
339                         method = find_method (klass, NULL, mname, sig);
340                         if (!method)
341                                 g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
342                         else if (klass->generic_inst && (klass != method->klass))
343                                 method = mono_class_inflate_generic_method (
344                                         method, klass->generic_inst->context, klass);
345                         mono_metadata_free_method_signature (sig);
346                         return method;
347                 }
348
349                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
350                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_SPEC | nindex);
351                 result->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
352                 result->signature = sig;
353                 result->name = mname;
354
355                 if (!strcmp (mname, ".ctor")) {
356                         /* we special-case this in the runtime. */
357                         result->addr = NULL;
358                         return result;
359                 }
360                 
361                 if (!strcmp (mname, "Set")) {
362                         g_assert (sig->hasthis);
363                         g_assert (type->data.array->rank + 1 == sig->param_count);
364                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
365                         result->addr = NULL;
366                         return result;
367                 }
368
369                 if (!strcmp (mname, "Get")) {
370                         g_assert (sig->hasthis);
371                         g_assert (type->data.array->rank == sig->param_count);
372                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
373                         result->addr = NULL;
374                         return result;
375                 }
376
377                 if (!strcmp (mname, "Address")) {
378                         g_assert (sig->hasthis);
379                         g_assert (type->data.array->rank == sig->param_count);
380                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
381                         result->addr = NULL;
382                         return result;
383                 }
384
385                 g_assert_not_reached ();
386                 break;
387         }
388         case MONO_MEMBERREF_PARENT_TYPEDEF:
389                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex);
390                 if (!klass) {
391                         g_warning ("Missing method %s in assembly %s typedef index %d", mname, image->name, nindex);
392                         mono_metadata_free_method_signature (sig);
393                         return NULL;
394                 }
395                 mono_class_init (klass);
396                 method = find_method (klass, NULL, mname, sig);
397                 if (!method)
398                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
399                 mono_metadata_free_method_signature (sig);
400                 return method;
401         case MONO_MEMBERREF_PARENT_METHODDEF:
402                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | nindex, NULL);
403                 return method;
404         default:
405                 g_error ("Memberref parent unknown: class: %d, index %d", class, nindex);
406                 g_assert_not_reached ();
407         }
408
409         return NULL;
410 }
411
412 static MonoMethod *
413 method_from_methodspec (MonoImage *image, guint32 idx)
414 {
415         MonoMethod *method, *inflated;
416         MonoTableInfo *tables = image->tables;
417         MonoGenericContext *context;
418         MonoGenericMethod *gmethod;
419         const char *ptr;
420         guint32 cols [MONO_METHODSPEC_SIZE];
421         guint32 token, param_count, i;
422
423         mono_metadata_decode_row (&tables [MONO_TABLE_METHODSPEC], idx - 1, cols, MONO_METHODSPEC_SIZE);
424         token = cols [MONO_METHODSPEC_METHOD];
425         if ((token & MONO_METHODDEFORREF_MASK) == MONO_METHODDEFORREF_METHODDEF)
426                 token = MONO_TOKEN_METHOD_DEF | (token >> MONO_METHODDEFORREF_BITS);
427         else
428                 token = MONO_TOKEN_MEMBER_REF | (token >> MONO_METHODDEFORREF_BITS);
429
430         method = mono_get_method (image, token, NULL);
431
432         ptr = mono_metadata_blob_heap (image, cols [MONO_METHODSPEC_SIGNATURE]);
433         
434         mono_metadata_decode_value (ptr, &ptr);
435         ptr++;
436         param_count = mono_metadata_decode_value (ptr, &ptr);
437
438         gmethod = g_new0 (MonoGenericMethod, 1);
439         gmethod->mtype_argc = param_count;
440         gmethod->mtype_argv = g_new0 (MonoType *, param_count);
441         
442         for (i = 0; i < param_count; i++) {
443                 gmethod->mtype_argv [i] = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
444
445                 if (!gmethod->is_open)
446                         gmethod->is_open = mono_class_is_open_constructed_type (gmethod->mtype_argv [i]);
447         }
448
449         context = g_new0 (MonoGenericContext, 1);
450         context->gmethod = gmethod;
451
452         mono_stats.generics_metadata_size += sizeof (MonoGenericMethod) +
453                 sizeof (MonoGenericContext) + param_count * sizeof (MonoType);
454
455         inflated = mono_class_inflate_generic_method (method, context, NULL);
456
457         context->ginst = inflated->klass->generic_inst;
458         return inflated;
459 }
460
461 typedef struct MonoDllMap MonoDllMap;
462
463 struct MonoDllMap {
464         char *name;
465         char *target;
466         char *dll;
467         MonoDllMap *next;
468 };
469
470 static GHashTable *global_dll_map;
471
472 static int 
473 mono_dllmap_lookup_hash (GHashTable *dll_map, const char *dll, const char* func, const char **rdll, const char **rfunc) {
474         MonoDllMap *map, *tmp;
475
476         *rdll = dll;
477
478         if (!dll_map)
479                 return 0;
480
481         mono_loader_lock ();
482
483         map = g_hash_table_lookup (dll_map, dll);
484         if (!map) {
485                 mono_loader_unlock ();
486                 return 0;
487         }
488         *rdll = map->target? map->target: dll;
489                 
490         for (tmp = map->next; tmp; tmp = tmp->next) {
491                 if (strcmp (func, tmp->name) == 0) {
492                         *rfunc = tmp->name;
493                         if (tmp->dll)
494                                 *rdll = tmp->dll;
495                         mono_loader_unlock ();
496                         return 1;
497                 }
498         }
499         *rfunc = func;
500         mono_loader_unlock ();
501         return 1;
502 }
503
504 static int 
505 mono_dllmap_lookup (MonoImage *assembly, const char *dll, const char* func, const char **rdll, const char **rfunc)
506 {
507         int res;
508         if (assembly && assembly->dll_map) {
509                 res = mono_dllmap_lookup_hash (assembly->dll_map, dll, func, rdll, rfunc);
510                 if (res)
511                         return res;
512         }
513         return mono_dllmap_lookup_hash (global_dll_map, dll, func, rdll, rfunc);
514 }
515
516 void
517 mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc) {
518         MonoDllMap *map, *entry;
519         GHashTable *dll_map = NULL;
520
521         mono_loader_lock ();
522
523         if (!assembly) {
524                 if (!global_dll_map)
525                         global_dll_map = g_hash_table_new (g_str_hash, g_str_equal);
526                 dll_map = global_dll_map;
527         } else {
528                 if (!assembly->dll_map)
529                         assembly->dll_map = g_hash_table_new (g_str_hash, g_str_equal);
530                 dll_map = assembly->dll_map;
531         }
532
533         map = g_hash_table_lookup (dll_map, dll);
534         if (!map) {
535                 map = g_new0 (MonoDllMap, 1);
536                 map->dll = g_strdup (dll);
537                 if (tdll)
538                         map->target = g_strdup (tdll);
539                 g_hash_table_insert (dll_map, map->dll, map);
540         }
541         if (func) {
542                 entry = g_new0 (MonoDllMap, 1);
543                 entry->name = g_strdup (func);
544                 if (tfunc)
545                         entry->target = g_strdup (tfunc);
546                 if (tdll && map->target && strcmp (map->target, tdll))
547                         entry->dll = g_strdup (tdll);
548                 entry->next = map->next;
549                 map->next = entry;
550         }
551
552         mono_loader_unlock ();
553 }
554
555 static void
556 mono_dllmap_free (GHashTable *dll_map)
557 {
558 }
559
560 static int wine_test_needed = 1;
561
562 gpointer
563 mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char **exc_arg)
564 {
565         MonoImage *image = method->klass->image;
566         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
567         MonoTableInfo *tables = image->tables;
568         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
569         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
570         guint32 im_cols [MONO_IMPLMAP_SIZE];
571         guint32 scope_token;
572         const char *import = NULL;
573         const char *orig_scope;
574         const char *new_scope;
575         char *full_name, *file_name;
576         int i;
577         GModule *gmodule = NULL;
578
579         g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
580
581         if (exc_class) {
582                 *exc_class = NULL;
583                 *exc_arg = NULL;
584         }
585
586         if (method->addr)
587                 return method->addr;
588         if (!piinfo->implmap_idx)
589                 return NULL;
590         
591         mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
592
593         piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
594         import = mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]);
595         scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME);
596         orig_scope = mono_metadata_string_heap (image, scope_token);
597
598         mono_dllmap_lookup (image, orig_scope, import, &new_scope, &import);
599
600         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
601                         "DllImport attempting to load: '%s'.", new_scope);
602
603         /*
604          * Try loading the module using a variety of names
605          */
606         for (i = 0; i < 2; ++i) {
607                 if (i == 0)
608                         /* Try the original name */
609                         file_name = g_strdup (new_scope);
610                 else {
611                         /* Try trimming the .dll extension */
612                         if (strstr (new_scope, ".dll") == (new_scope + strlen (new_scope) - 4)) {
613                                 file_name = g_strdup (new_scope);
614                                 file_name [strlen (new_scope) - 4] = '\0';
615                         }
616                         else
617                                 break;
618                 }
619
620                 if (!gmodule) {
621                         full_name = g_module_build_path (NULL, file_name);
622                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
623                                         "DllImport loading location: '%s'.", full_name);
624                         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
625                         if (!gmodule) {
626                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
627                                                 "DllImport error loading library: '%s'.",
628                                                 g_module_error ());
629                         }
630                         g_free (full_name);
631                 }
632
633                 if (!gmodule) {
634                         full_name = g_module_build_path (".", file_name);
635                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
636                                         "DllImport loading library: '%s'.", full_name);
637                         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
638                         if (!gmodule) {
639                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
640                                                 "DllImport error loading library '%s'.",
641                                                 g_module_error ());
642                         }
643                         g_free (full_name);
644                 }
645
646                 if (!gmodule) {
647                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
648                                         "DllImport loading: '%s'.", file_name);
649                         gmodule=g_module_open (file_name, G_MODULE_BIND_LAZY);
650                         if (!gmodule) {
651                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
652                                                 "DllImport error loading library '%s'.",
653                                                 g_module_error ());
654                         }
655                 }
656
657                 g_free (file_name);
658
659                 if (gmodule)
660                         break;
661         }
662
663         if (!gmodule) {
664                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_DLLIMPORT,
665                                 "DllImport unable to load library '%s'.",
666                                 g_module_error ());
667
668                 if (exc_class) {
669                         *exc_class = "DllNotFoundException";
670                         *exc_arg = orig_scope;
671                 }
672                 return NULL;
673         }
674
675         if (piinfo->piflags & PINVOKE_ATTRIBUTE_NO_MANGLE) {
676                 g_module_symbol (gmodule, import, &method->addr); 
677         } else {
678                 char *mangled_name;
679
680                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
681                 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
682                         mangled_name = g_strconcat (import, "W", NULL);
683                         g_module_symbol (gmodule, mangled_name, &method->addr); 
684                         g_free (mangled_name);
685
686                         if (!method->addr)
687                                 g_module_symbol (gmodule, import, &method->addr); 
688                         break;
689                 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
690                         g_module_symbol (gmodule, import, &method->addr); 
691                         break;
692                 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
693                 default:
694                         mangled_name = g_strconcat (import, "A", NULL);
695                         g_module_symbol (gmodule, mangled_name, &method->addr); 
696                         g_free (mangled_name);
697
698                         if (!method->addr)
699                                 g_module_symbol (gmodule, import, &method->addr); 
700                                
701                         break;                                  
702                 }
703         }
704
705         if (!method->addr) {
706                 if (exc_class) {
707                         *exc_class = "EntryPointNotFoundException";
708                         *exc_arg = import;
709                 }
710                 return NULL;
711         }
712         return method->addr;
713 }
714
715 static MonoMethod *
716 mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
717                             MonoGenericContext *context)
718 {
719         MonoMethod *result;
720         int table = mono_metadata_token_table (token);
721         int idx = mono_metadata_token_index (token);
722         MonoTableInfo *tables = image->tables;
723         const char *loc, *sig = NULL;
724         int size, i;
725         guint32 cols [MONO_TYPEDEF_SIZE];
726
727         if (image->dynamic)
728                 return mono_lookup_dynamic_token (image, token);
729
730         if (table != MONO_TABLE_METHOD) {
731                 if (table == MONO_TABLE_METHODSPEC)
732                         return method_from_methodspec (image, idx);
733                 if (table != MONO_TABLE_MEMBERREF)
734                         g_print("got wrong token: 0x%08x\n", token);
735                 g_assert (table == MONO_TABLE_MEMBERREF);
736                 result = method_from_memberref (image, idx, context);
737
738                 return result;
739         }
740
741         mono_metadata_decode_row (&tables [table], idx - 1, cols, 6);
742
743         if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
744             (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
745                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
746         else 
747                 result = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
748         
749         result->slot = -1;
750         result->klass = klass;
751         result->flags = cols [2];
752         result->iflags = cols [1];
753         result->token = token;
754         result->name = mono_metadata_string_heap (image, cols [3]);
755
756         if (!sig) /* already taken from the methodref */
757                 sig = mono_metadata_blob_heap (image, cols [4]);
758         size = mono_metadata_decode_blob_size (sig, &sig);
759         result->signature = mono_metadata_parse_method_signature (image, idx, sig, NULL);
760
761         if (!result->klass) {
762                 guint32 type = mono_metadata_typedef_from_method (image, token);
763                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
764         }
765
766         if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
767                 if (result->klass == mono_defaults.string_class && !strcmp (result->name, ".ctor"))
768                         result->string_ctor = 1;
769
770                 result->signature->pinvoke = 1;
771         } else if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (!(cols [1] & METHOD_IMPL_ATTRIBUTE_NATIVE))) {
772                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)result;
773                 MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
774                 MonoCallConvention conv = 0;
775
776                 result->signature->pinvoke = 1;
777                 piinfo->implmap_idx = mono_metadata_implmap_from_method (image, idx - 1);
778                 piinfo->piflags = mono_metadata_decode_row_col (im, piinfo->implmap_idx - 1, MONO_IMPLMAP_FLAGS);
779
780                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CALL_CONV_MASK) {
781                 case PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI:
782                         conv = MONO_CALL_DEFAULT;
783                         break;
784                 case PINVOKE_ATTRIBUTE_CALL_CONV_CDECL:
785                         conv = MONO_CALL_C;
786                         break;
787                 case PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL:
788                         conv = MONO_CALL_STDCALL;
789                         break;
790                 case PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL:
791                         conv = MONO_CALL_THISCALL;
792                         break;
793                 case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL:
794                         conv = MONO_CALL_FASTCALL;
795                         break;
796                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC:
797                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST:
798                 default:
799                         g_warning ("unsupported calling convention");
800                         g_assert_not_reached ();
801                 }       
802                 result->signature->call_convention = conv;
803         } else {
804                 MonoGenericParam *gen_params = NULL;
805
806                 /* if this is a methodref from another module/assembly, this fails */
807                 loc = mono_image_rva_map (image, cols [0]);
808
809                 if (result->signature->generic_param_count) {
810                         MonoMethodSignature *sig = result->signature;
811
812                         gen_params = mono_metadata_load_generic_params (image, token, NULL);
813
814                         for (i = 0; i < sig->generic_param_count; i++) {
815                                 gen_params [i].method = result;
816
817                                 mono_class_from_generic_parameter (
818                                         &gen_params [i], image, TRUE);
819                         }
820
821                         if (sig->ret->type == MONO_TYPE_MVAR) {
822                                 int num = sig->ret->data.generic_param->num;
823                                 sig->ret->data.generic_param = &gen_params [num];
824                         }
825
826                         for (i = 0; i < sig->param_count; i++) {
827                                 MonoType *t = sig->params [i];
828                                 if (t->type == MONO_TYPE_MVAR) {
829                                         int num = t->data.generic_param->num;
830                                         sig->params [i]->data.generic_param = &gen_params [num];
831                                 }
832                         }
833                 }
834
835                 if (!result->klass->dummy && !(result->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
836                                         !(result->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
837                         MonoMethodNormal *mn = (MonoMethodNormal *) result;
838
839                         g_assert (loc);
840                         mn->header = mono_metadata_parse_mh (image, loc);
841                         mn->header->gen_params = gen_params;
842                 }
843         }
844
845         return result;
846 }
847
848 MonoMethod *
849 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
850 {
851         return mono_get_method_full (image, token, klass, NULL);
852 }
853
854 MonoMethod *
855 mono_get_method_full (MonoImage *image, guint32 token, MonoClass *klass,
856                       MonoGenericContext *context)
857 {
858         MonoMethod *result;
859
860         /* We do everything inside the lock to prevent creation races */
861
862         mono_loader_lock ();
863
864         if ((result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token)))) {
865                 mono_loader_unlock ();
866                 return result;
867         }
868
869         result = mono_get_method_from_token (image, token, klass, context);
870
871         if (!(result && result->signature->is_inflated))
872                 g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
873
874         mono_loader_unlock ();
875
876         return result;
877 }
878
879 MonoMethod *
880 mono_get_method_constrained (MonoImage *image, guint32 token, MonoClass *constrained_class,
881                              MonoGenericContext *context)
882 {
883         MonoMethod *method, *result;
884         MonoClass *ic = NULL;
885         int i;
886
887         mono_loader_lock ();
888
889         method = mono_get_method_from_token (image, token, NULL, context);
890         if (!method) {
891                 mono_loader_unlock ();
892                 return NULL;
893         }
894
895         mono_class_init (constrained_class);
896
897         if ((constrained_class != method->klass) && (method->klass->interface_id != 0))
898                 ic = method->klass;
899
900         result = find_method (constrained_class, ic, method->name, method->signature);
901         if (!result)
902                 g_warning ("Missing method %s in assembly %s token %x", method->name,
903                            image->name, token);
904
905         mono_loader_unlock ();
906         return result;
907 }
908
909 void
910 mono_free_method  (MonoMethod *method)
911 {
912         mono_metadata_free_method_signature (method->signature);
913         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
914                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
915                 g_free (piinfo->code);
916         } else if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
917                 mono_metadata_free_mh (((MonoMethodNormal *)method)->header);
918         }
919
920         g_free (method);
921 }
922
923 void
924 mono_method_get_param_names (MonoMethod *method, const char **names)
925 {
926         int i, lastp;
927         MonoClass *klass = method->klass;
928         MonoTableInfo *methodt;
929         MonoTableInfo *paramt;
930
931         if (!method->signature->param_count)
932                 return;
933         for (i = 0; i < method->signature->param_count; ++i)
934                 names [i] = "";
935
936         if (klass->generic_inst) /* copy the names later */
937                 return;
938
939         mono_class_init (klass);
940
941         if (klass->image->dynamic) {
942                 MonoReflectionMethodAux *method_aux = 
943                         mono_g_hash_table_lookup (
944                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
945                 if (method_aux && method_aux->param_names) {
946                         for (i = 0; i < method->signature->param_count; ++i)
947                                 if (method_aux->param_names [i + 1])
948                                         names [i] = method_aux->param_names [i + 1];
949                 }
950                 return;
951         }
952
953         methodt = &klass->image->tables [MONO_TABLE_METHOD];
954         paramt = &klass->image->tables [MONO_TABLE_PARAM];
955         for (i = 0; i < klass->method.count; ++i) {
956                 if (method == klass->methods [i]) {
957                         guint32 idx = klass->method.first + i;
958                         guint32 cols [MONO_PARAM_SIZE];
959                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
960
961                         if (idx + 1 < methodt->rows)
962                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
963                         else
964                                 lastp = paramt->rows + 1;
965                         for (i = param_index; i < lastp; ++i) {
966                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
967                                 if (cols [MONO_PARAM_SEQUENCE]) /* skip return param spec */
968                                         names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass->image, cols [MONO_PARAM_NAME]);
969                         }
970                         return;
971                 }
972         }
973 }
974
975 void
976 mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs)
977 {
978         int i, lastp;
979         MonoClass *klass = method->klass;
980         MonoTableInfo *methodt;
981         MonoTableInfo *paramt;
982
983         for (i = 0; i < method->signature->param_count + 1; ++i)
984                 mspecs [i] = NULL;
985
986         if (method->klass->image->dynamic) {
987                 MonoReflectionMethodAux *method_aux = 
988                         mono_g_hash_table_lookup (
989                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
990                 if (method_aux && method_aux->param_marshall) {
991                         MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
992                         for (i = 0; i < method->signature->param_count + 1; ++i)
993                                 if (dyn_specs [i]) {
994                                         mspecs [i] = g_new0 (MonoMarshalSpec, 1);
995                                         memcpy (mspecs [i], dyn_specs [i], sizeof (MonoMarshalSpec));
996                                 }
997                 }
998                 return;
999         }
1000
1001         mono_class_init (klass);
1002
1003         methodt = &klass->image->tables [MONO_TABLE_METHOD];
1004         paramt = &klass->image->tables [MONO_TABLE_PARAM];
1005
1006         for (i = 0; i < klass->method.count; ++i) {
1007                 if (method == klass->methods [i]) {
1008                         guint32 idx = klass->method.first + i;
1009                         guint32 cols [MONO_PARAM_SIZE];
1010                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
1011
1012                         if (idx + 1 < methodt->rows)
1013                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
1014                         else
1015                                 lastp = paramt->rows + 1;
1016
1017                         for (i = param_index; i < lastp; ++i) {
1018                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
1019
1020                                 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) {
1021                                         const char *tp;
1022                                         tp = mono_metadata_get_marshal_info (klass->image, i - 1, FALSE);
1023                                         g_assert (tp);
1024                                         mspecs [cols [MONO_PARAM_SEQUENCE]]= mono_metadata_parse_marshal_spec (klass->image, tp);
1025                                 }
1026                         }
1027
1028                         return;
1029                 }
1030         }
1031 }
1032
1033 gboolean
1034 mono_method_has_marshal_info (MonoMethod *method)
1035 {
1036         int i, lastp;
1037         MonoClass *klass = method->klass;
1038         MonoTableInfo *methodt;
1039         MonoTableInfo *paramt;
1040
1041         if (method->klass->image->dynamic) {
1042                 MonoReflectionMethodAux *method_aux = 
1043                         mono_g_hash_table_lookup (
1044                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1045                 MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
1046                 if (dyn_specs) {
1047                         for (i = 0; i < method->signature->param_count + 1; ++i)
1048                                 if (dyn_specs [i])
1049                                         return TRUE;
1050                 }
1051                 return FALSE;
1052         }
1053
1054         mono_class_init (klass);
1055
1056         methodt = &klass->image->tables [MONO_TABLE_METHOD];
1057         paramt = &klass->image->tables [MONO_TABLE_PARAM];
1058
1059         for (i = 0; i < klass->method.count; ++i) {
1060                 if (method == klass->methods [i]) {
1061                         guint32 idx = klass->method.first + i;
1062                         guint32 cols [MONO_PARAM_SIZE];
1063                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
1064
1065                         if (idx + 1 < methodt->rows)
1066                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
1067                         else
1068                                 lastp = paramt->rows + 1;
1069
1070                         for (i = param_index; i < lastp; ++i) {
1071                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
1072
1073                                 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL)
1074                                         return TRUE;
1075                         }
1076                         return FALSE;
1077                 }
1078         }
1079         return FALSE;
1080 }
1081
1082 gpointer
1083 mono_method_get_wrapper_data (MonoMethod *method, guint32 id)
1084 {
1085         GList *l;
1086         g_assert (method != NULL);
1087         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
1088
1089         if (!(l = g_list_nth (((MonoMethodWrapper *)method)->data, id - 1)))
1090                 g_assert_not_reached ();
1091
1092         return l->data;
1093 }
1094
1095 static void
1096 default_stack_walk (MonoStackWalk func, gpointer user_data) {
1097         g_error ("stack walk not installed");
1098 }
1099
1100 static MonoStackWalkImpl stack_walk = default_stack_walk;
1101
1102 void
1103 mono_stack_walk (MonoStackWalk func, gpointer user_data)
1104 {
1105         stack_walk (func, user_data);
1106 }
1107
1108 void
1109 mono_install_stack_walk (MonoStackWalkImpl func)
1110 {
1111         stack_walk = func;
1112 }
1113
1114 static gboolean
1115 last_managed (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
1116 {
1117         MonoMethod **dest = data;
1118         *dest = m;
1119         /*g_print ("In %s::%s [%d] [%d]\n", m->klass->name, m->name, no, ilo);*/
1120
1121         return managed;
1122 }
1123
1124 MonoMethod*
1125 mono_method_get_last_managed (void)
1126 {
1127         MonoMethod *m = NULL;
1128         stack_walk (last_managed, &m);
1129         return m;
1130 }
1131
1132 void
1133 mono_loader_lock (void)
1134 {
1135         EnterCriticalSection (&loader_mutex);
1136 }
1137
1138 void
1139 mono_loader_unlock (void)
1140 {
1141         LeaveCriticalSection (&loader_mutex);
1142 }
1143
1144 MonoMethodSignature* 
1145 mono_method_signature (MonoMethod *method)
1146 {
1147         return method->signature;
1148 }
1149
1150 const char*
1151 mono_method_get_name (MonoMethod *method)
1152 {
1153         return method->name;
1154 }
1155
1156 MonoClass*
1157 mono_method_get_class (MonoMethod *method)
1158 {
1159         return method->klass;
1160 }
1161
1162 guint32
1163 mono_method_get_token (MonoMethod *method)
1164 {
1165         return method->token;
1166 }
1167
1168 guint32
1169 mono_method_get_flags (MonoMethod *method, guint32 *iflags)
1170 {
1171         if (iflags)
1172                 *iflags = method->iflags;
1173         return method->flags;
1174 }
1175
1176