2003-12-20 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / loader.c
1 /*
2  * loader.c: Image Loader 
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Miguel de Icaza (miguel@ximian.com)
7  *   Patrik Torstensson (patrik.torstensson@labs2.com)
8  *
9  * (C) 2001 Ximian, Inc.
10  *
11  * This file is used by the interpreter and the JIT engine to locate
12  * assemblies.  Used to load AssemblyRef and later to resolve various
13  * kinds of `Refs'.
14  *
15  * TODO:
16  *   This should keep track of the assembly versions that we are loading.
17  *
18  */
19 #include <config.h>
20 #include <glib.h>
21 #include <gmodule.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <mono/metadata/metadata.h>
26 #include <mono/metadata/image.h>
27 #include <mono/metadata/assembly.h>
28 #include <mono/metadata/tokentype.h>
29 #include <mono/metadata/cil-coff.h>
30 #include <mono/metadata/tabledefs.h>
31 #include <mono/metadata/loader.h>
32 #include <mono/metadata/class.h>
33 #include <mono/metadata/debug-helpers.h>
34 #include <mono/metadata/reflection.h>
35
36 static gboolean dummy_icall = TRUE;
37
38 MonoDefaults mono_defaults;
39
40 CRITICAL_SECTION loader_mutex;
41
42 static GHashTable *icall_hash = NULL;
43
44 void
45 mono_loader_init ()
46 {
47         InitializeCriticalSection (&loader_mutex);
48 }
49
50 void
51 mono_add_internal_call (const char *name, gconstpointer method)
52 {
53         mono_loader_lock ();
54
55         if (!icall_hash) {
56                 dummy_icall = FALSE;
57                 icall_hash = g_hash_table_new (g_str_hash , g_str_equal);
58         }
59
60         g_hash_table_insert (icall_hash, g_strdup (name), (gpointer) method);
61
62         mono_loader_unlock ();
63 }
64
65 static void
66 ves_icall_dummy (void)
67 {
68         g_warning ("the mono runtime is not initialized");
69         g_assert_not_reached ();
70 }
71
72 gpointer
73 mono_lookup_internal_call (MonoMethod *method)
74 {
75         char *name;
76         char *tmpsig;
77         gpointer res;
78
79         if (dummy_icall)
80                 return ves_icall_dummy;
81
82         if (!method) {
83                 g_warning ("can't resolve internal call, method is null");
84         }
85
86         if (!icall_hash) {
87                 g_warning ("icall_hash not initialized");
88                 g_assert_not_reached ();
89         }
90
91         mono_loader_lock ();
92
93         if (*method->klass->name_space)
94                 name = g_strconcat (method->klass->name_space, ".", method->klass->name, "::", method->name, NULL);
95         else
96                 name = g_strconcat (method->klass->name, "::", method->name, NULL);
97         if (!(res = g_hash_table_lookup (icall_hash, name))) {
98                 /* trying to resolve with full signature */
99                 g_free (name);
100         
101                 tmpsig = mono_signature_get_desc(method->signature, TRUE);
102                 if (*method->klass->name_space)
103                         name = g_strconcat (method->klass->name_space, ".", method->klass->name, "::", method->name, "(", tmpsig, ")", NULL);
104                 else
105                         name = g_strconcat (method->klass->name, "::", method->name, "(", tmpsig, ")", NULL);
106                 if (!(res = g_hash_table_lookup (icall_hash, name))) {
107                         g_warning ("cant resolve internal call to \"%s\" (tested without signature also)", name);
108                         g_print ("\nYour mono runtime and corlib are out of sync.\n");
109                         g_print ("Corlib is: %s\n", method->klass->image->name);
110                         g_print ("\nWhen you update one from cvs you need to update, compile and install\nthe other too.\n");
111                         g_print ("Do not report this as a bug unless you're sure you have updated correctly:\nyou probably have a broken mono install.\n");
112                         g_print ("If you see other errors or faults after this message they are probably related\n");
113                         g_print ("and you need to fix your mono install first.\n");
114
115                         g_free (name);
116                         g_free (tmpsig);
117
118                         mono_loader_unlock ();
119
120                         return NULL;
121                 }
122
123                 g_free(tmpsig);
124         }
125
126         mono_loader_unlock ();
127
128         g_free (name);
129
130         return res;
131 }
132
133 MonoClassField*
134 mono_field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass)
135 {
136         MonoClass *klass;
137         MonoTableInfo *tables = image->tables;
138         guint32 cols[6];
139         guint32 nindex, class;
140         const char *fname;
141         const char *ptr;
142         guint32 idx = mono_metadata_token_index (token);
143
144         if (image->dynamic) {
145                 MonoClassField *result = mono_lookup_dynamic_token (image, token);
146                 *retklass = result->parent;
147                 return result;
148         }
149
150         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
151         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
152         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
153
154         fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
155         
156         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
157         mono_metadata_decode_blob_size (ptr, &ptr);
158         /* we may want to check the signature here... */
159
160         switch (class) {
161         case MEMBERREF_PARENT_TYPEREF:
162                 klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
163                 if (!klass) {
164                         g_warning ("Missing field %s in typeref index %d", fname, nindex);
165                         return NULL;
166                 }
167                 mono_class_init (klass);
168                 if (retklass)
169                         *retklass = klass;
170                 return mono_class_get_field_from_name (klass, fname);
171         case MEMBERREF_PARENT_TYPESPEC: {
172                 /*guint32 bcols [MONO_TYPESPEC_SIZE];
173                 guint32 len;
174                 MonoType *type;
175
176                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
177                                           bcols, MONO_TYPESPEC_SIZE);
178                 ptr = mono_metadata_blob_heap (image, bcols [MONO_TYPESPEC_SIGNATURE]);
179                 len = mono_metadata_decode_value (ptr, &ptr);   
180                 type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
181
182                 klass = mono_class_from_mono_type (type);
183                 mono_class_init (klass);
184                 g_print ("type in sig: %s\n", klass->name);*/
185                 klass = mono_class_get (image, MONO_TOKEN_TYPE_SPEC | nindex);
186                 mono_class_init (klass);
187                 if (retklass)
188                         *retklass = klass;
189                 return mono_class_get_field_from_name (klass, fname);
190         }
191         default:
192                 g_warning ("field load from %x", class);
193                 return NULL;
194         }
195 }
196
197 MonoClassField*
198 mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass)
199 {
200         MonoClass *k;
201         guint32 type;
202         MonoClassField *field;
203
204         if (image->dynamic) {
205                 MonoClassField *result = mono_lookup_dynamic_token (image, token);
206                 *retklass = result->parent;
207                 return result;
208         }
209
210         mono_loader_lock ();
211         if ((field = g_hash_table_lookup (image->field_cache, GUINT_TO_POINTER (token)))) {
212                 *retklass = field->parent;
213                 mono_loader_unlock ();
214                 return field;
215         }
216         mono_loader_unlock ();
217
218         if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
219                 field = mono_field_from_memberref (image, token, retklass);
220         else {
221                 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
222                 if (!type)
223                         return NULL;
224                 k = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
225                 mono_class_init (k);
226                 if (!k)
227                         return NULL;
228                 if (retklass)
229                         *retklass = k;
230                 field = mono_class_get_field (k, token);
231         }
232
233         mono_loader_lock ();
234         g_hash_table_insert (image->field_cache, GUINT_TO_POINTER (token), field);
235         mono_loader_unlock ();
236         return field;
237 }
238
239 static gboolean
240 mono_metadata_signature_vararg_match (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
241 {
242         int i;
243
244         if (sig1->hasthis != sig2->hasthis ||
245             sig1->sentinelpos != sig2->sentinelpos)
246                 return FALSE;
247
248         for (i = 0; i < sig1->sentinelpos; i++) { 
249                 MonoType *p1 = sig1->params[i];
250                 MonoType *p2 = sig2->params[i];
251                 
252                 //if (p1->attrs != p2->attrs)
253                 //      return FALSE;
254                 
255                 if (!mono_metadata_type_equal (p1, p2))
256                         return FALSE;
257         }
258
259         if (!mono_metadata_type_equal (sig1->ret, sig2->ret))
260                 return FALSE;
261         return TRUE;
262 }
263
264 static MonoMethod *
265 find_method (MonoClass *klass, const char* name, MonoMethodSignature *sig)
266 {
267         int i;
268         MonoClass *sclass = klass;
269         
270         if (sig->call_convention == MONO_CALL_VARARG) {
271                 while (klass) {
272                         /* mostly dumb search for now */
273                         for (i = 0; i < klass->method.count; ++i) {
274                                 MonoMethod *m = klass->methods [i];
275                                 if (!strcmp (name, m->name)) {
276                                         if (mono_metadata_signature_vararg_match (sig, m->signature))
277                                                 return m;
278                                 }
279                         }
280                         if (name [0] == '.' && (strcmp (name, ".ctor") == 0 || strcmp (name, ".cctor") == 0))
281                                 break;
282                         klass = klass->parent;
283                 }
284                 return NULL;
285         }
286         while (klass) {
287                 /* mostly dumb search for now */
288                 for (i = 0; i < klass->method.count; ++i) {
289                         MonoMethod *m = klass->methods [i];
290                         if (!strcmp (name, m->name)) {
291                                 if (mono_metadata_signature_equal (sig, m->signature))
292                                         return m;
293                         }
294                 }
295                 if (name [0] == '.' && (strcmp (name, ".ctor") == 0 || strcmp (name, ".cctor") == 0))
296                         break;
297                 klass = klass->parent;
298         }
299         if (sclass->generic_inst) {
300                 MonoClass *gclass = mono_class_from_mono_type (sclass->generic_inst->data.generic_inst->generic_type);
301                 MonoMethod *res = find_method (gclass, name, sig);
302                 if (!res)
303                         return NULL;
304                 for (i = 0; i < res->klass->method.count; ++i) {
305                         if (res == res->klass->methods [i]) {
306                                 return sclass->methods [i];
307                         }
308                 }
309         }
310         return NULL;
311
312 }
313
314 /*
315  * token is the method_ref or method_def token used in a call IL instruction.
316  */
317 MonoMethodSignature*
318 mono_method_get_signature (MonoMethod *method, MonoImage *image, guint32 token)
319 {
320         int table = mono_metadata_token_table (token);
321         int idx = mono_metadata_token_index (token);
322         guint32 cols [MONO_MEMBERREF_SIZE];
323         MonoMethodSignature *sig;
324         const char *ptr;
325
326         /* !table is for wrappers: we should really assign their own token to them */
327         if (!table || table == MONO_TABLE_METHOD)
328                 return method->signature;
329
330         if (table == MONO_TABLE_METHODSPEC) {
331                 MonoMethodNormal *mn;
332
333                 g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
334                           !(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
335                           method->signature);
336                 mn = (MonoMethodNormal *) method;
337                 g_assert (mn->header->geninst);
338
339                 return method->signature;
340         }
341
342         if (method->klass->generic_inst)
343                 return method->signature;
344
345         if (image->dynamic)
346                 /* FIXME: This might be incorrect for vararg methods */
347                 return method->signature;
348
349         mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
350         
351         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
352         mono_metadata_decode_blob_size (ptr, &ptr);
353         sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
354
355         return sig;
356 }
357
358 static MonoMethod *
359 method_from_memberref (MonoImage *image, guint32 idx)
360 {
361         MonoClass *klass;
362         MonoMethod *method;
363         MonoTableInfo *tables = image->tables;
364         guint32 cols[6];
365         guint32 nindex, class;
366         const char *mname;
367         MonoMethodSignature *sig;
368         const char *ptr;
369
370         mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
371         nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
372         class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
373         /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
374                 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
375
376         mname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
377         
378         ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
379         mono_metadata_decode_blob_size (ptr, &ptr);
380         sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
381
382         switch (class) {
383         case MEMBERREF_PARENT_TYPEREF:
384                 klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
385                 if (!klass) {
386                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
387                         mono_metadata_free_method_signature (sig);
388                         return NULL;
389                 }
390                 mono_class_init (klass);
391                 method = find_method (klass, mname, sig);
392                 if (!method)
393                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
394                 mono_metadata_free_method_signature (sig);
395                 return method;
396         case MEMBERREF_PARENT_TYPESPEC: {
397                 guint32 bcols [MONO_TYPESPEC_SIZE];
398                 guint32 len;
399                 MonoType *type;
400                 MonoMethod *result;
401
402                 mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
403                                           bcols, MONO_TYPESPEC_SIZE);
404                 ptr = mono_metadata_blob_heap (image, bcols [MONO_TYPESPEC_SIGNATURE]);
405                 len = mono_metadata_decode_value (ptr, &ptr);   
406                 type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
407
408                 if (type->type != MONO_TYPE_ARRAY && type->type != MONO_TYPE_SZARRAY) {
409                         klass = mono_class_from_mono_type (type);
410                         mono_class_init (klass);
411                         method = find_method (klass, mname, sig);
412                         if (!method)
413                                 g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
414                         else if (klass->generic_inst)
415                                 method = mono_class_inflate_generic_method (method, klass->generic_inst->data.generic_inst);
416                         mono_metadata_free_method_signature (sig);
417                         return method;
418                 }
419
420                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
421                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_SPEC | nindex);
422                 result->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
423                 result->signature = sig;
424                 result->name = mname;
425
426                 if (!strcmp (mname, ".ctor")) {
427                         /* we special-case this in the runtime. */
428                         result->addr = NULL;
429                         return result;
430                 }
431                 
432                 if (!strcmp (mname, "Set")) {
433                         g_assert (sig->hasthis);
434                         g_assert (type->data.array->rank + 1 == sig->param_count);
435                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
436                         result->addr = NULL;
437                         return result;
438                 }
439
440                 if (!strcmp (mname, "Get")) {
441                         g_assert (sig->hasthis);
442                         g_assert (type->data.array->rank == sig->param_count);
443                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
444                         result->addr = NULL;
445                         return result;
446                 }
447
448                 if (!strcmp (mname, "Address")) {
449                         g_assert (sig->hasthis);
450                         g_assert (type->data.array->rank == sig->param_count);
451                         result->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
452                         result->addr = NULL;
453                         return result;
454                 }
455
456                 g_assert_not_reached ();
457                 break;
458         }
459         case MEMBERREF_PARENT_TYPEDEF:
460                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex);
461                 if (!klass) {
462                         g_warning ("Missing method %s in assembly %s typedef index %d", mname, image->name, nindex);
463                         mono_metadata_free_method_signature (sig);
464                         return NULL;
465                 }
466                 mono_class_init (klass);
467                 method = find_method (klass, mname, sig);
468                 if (!method)
469                         g_warning ("Missing method %s in assembly %s typeref index %d", mname, image->name, nindex);
470                 mono_metadata_free_method_signature (sig);
471                 return method;
472         case MEMBERREF_PARENT_METHODDEF:
473                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | nindex, NULL);
474                 return method;
475         default:
476                 g_error ("Memberref parent unknown: class: %d, index %d", class, nindex);
477                 g_assert_not_reached ();
478         }
479
480         return NULL;
481 }
482
483 static MonoMethod *
484 method_from_methodspec (MonoImage *image, guint32 idx)
485 {
486         MonoMethod *method;
487         MonoTableInfo *tables = image->tables;
488         MonoGenericInst *ginst;
489         const char *ptr;
490         guint32 cols [MONO_METHODSPEC_SIZE];
491         guint32 token, param_count, i;
492
493         mono_metadata_decode_row (&tables [MONO_TABLE_METHODSPEC], idx - 1, cols, MONO_METHODSPEC_SIZE);
494         token = cols [MONO_METHODSPEC_METHOD];
495         if ((token & METHODDEFORREF_MASK) == METHODDEFORREF_METHODDEF)
496                 token = MONO_TOKEN_METHOD_DEF | (token >> METHODDEFORREF_BITS);
497         else
498                 token = MONO_TOKEN_MEMBER_REF | (token >> METHODDEFORREF_BITS);
499
500         method = mono_get_method (image, token, NULL);
501
502         ptr = mono_metadata_blob_heap (image, cols [MONO_METHODSPEC_SIGNATURE]);
503         
504         mono_metadata_decode_value (ptr, &ptr);
505         ptr++;
506         param_count = mono_metadata_decode_value (ptr, &ptr);
507
508         ginst = g_new0 (MonoGenericInst, 1);
509         ginst->generic_method = method;
510         ginst->type_argc = param_count;
511         ginst->type_argv = g_new0 (MonoType *, param_count);
512         
513         for (i = 0; i < param_count; i++) {
514                 ginst->type_argv [i] = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
515
516                 if (!ginst->is_open)
517                         ginst->is_open = mono_class_is_open_constructed_type (ginst->type_argv [i]);
518         }
519
520         return mono_class_inflate_generic_method (method, ginst);
521 }
522
523 typedef struct MonoDllMap MonoDllMap;
524
525 struct MonoDllMap {
526         char *name;
527         char *target;
528         char *dll;
529         MonoDllMap *next;
530 };
531
532 static GHashTable *dll_map;
533
534 int 
535 mono_dllmap_lookup (const char *dll, const char* func, const char **rdll, const char **rfunc) {
536         MonoDllMap *map, *tmp;
537
538         if (!dll_map)
539                 return 0;
540
541         mono_loader_lock ();
542
543         map = g_hash_table_lookup (dll_map, dll);
544         if (!map) {
545                 mono_loader_unlock ();
546                 return 0;
547         }
548         *rdll = map->target? map->target: dll;
549                 
550         for (tmp = map->next; tmp; tmp = tmp->next) {
551                 if (strcmp (func, tmp->name) == 0) {
552                         *rfunc = tmp->name;
553                         if (tmp->dll)
554                                 *rdll = tmp->dll;
555                         mono_loader_unlock ();
556                         return 1;
557                 }
558         }
559         *rfunc = func;
560         mono_loader_unlock ();
561         return 1;
562 }
563
564 void
565 mono_dllmap_insert (const char *dll, const char *func, const char *tdll, const char *tfunc) {
566         MonoDllMap *map, *entry;
567
568         mono_loader_lock ();
569
570         if (!dll_map)
571                 dll_map = g_hash_table_new (g_str_hash, g_str_equal);
572
573         map = g_hash_table_lookup (dll_map, dll);
574         if (!map) {
575                 map = g_new0 (MonoDllMap, 1);
576                 map->dll = g_strdup (dll);
577                 if (tdll)
578                         map->target = g_strdup (tdll);
579                 g_hash_table_insert (dll_map, map->dll, map);
580         }
581         if (func) {
582                 entry = g_new0 (MonoDllMap, 1);
583                 entry->name = g_strdup (func);
584                 if (tfunc)
585                         entry->target = g_strdup (tfunc);
586                 if (tdll && map->target && strcmp (map->target, tdll))
587                         entry->dll = g_strdup (tdll);
588                 entry->next = map->next;
589                 map->next = entry;
590         }
591
592         mono_loader_unlock ();
593 }
594
595 gpointer
596 mono_lookup_pinvoke_call (MonoMethod *method)
597 {
598         MonoImage *image = method->klass->image;
599         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
600         MonoTableInfo *tables = image->tables;
601         MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
602         MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
603         guint32 im_cols [MONO_IMPLMAP_SIZE];
604         guint32 scope_token;
605         const char *import = NULL;
606         const char *scope = NULL;
607         char *full_name;
608         GModule *gmodule;
609
610         g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
611
612         if (method->addr)
613                 return method->addr;
614         if (!piinfo->implmap_idx)
615                 return NULL;
616         
617         mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
618
619         piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
620         import = mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]);
621         scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME);
622         scope = mono_metadata_string_heap (image, scope_token);
623
624         mono_dllmap_lookup (scope, import, &scope, &import);
625
626         full_name = g_module_build_path (NULL, scope);
627         gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
628
629         if (!gmodule) {
630                 g_free (full_name);
631                 full_name = g_module_build_path (".", scope);
632                 gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
633         }
634
635         if (!gmodule) {
636                 gchar *error = g_strdup (g_module_error ());
637                 if (!(gmodule=g_module_open (scope, G_MODULE_BIND_LAZY))) {
638                         g_warning ("Failed to load library %s (%s): %s", full_name, scope, error);
639                         g_free (error);
640                         g_free (full_name);
641                         return NULL;
642                 }
643                 g_free (error);
644         }
645         g_free (full_name);
646
647         if (piinfo->piflags & PINVOKE_ATTRIBUTE_NO_MANGLE) {
648                 g_module_symbol (gmodule, import, &method->addr); 
649         } else {
650                 char *mangled_name;
651
652                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
653                 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
654                         mangled_name = g_strconcat (import, "W", NULL);
655                         g_module_symbol (gmodule, mangled_name, &method->addr); 
656                         g_free (mangled_name);
657
658                         if (!method->addr)
659                                 g_module_symbol (gmodule, import, &method->addr); 
660                         break;
661                 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
662                         g_module_symbol (gmodule, import, &method->addr); 
663                         break;
664                 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
665                 default:
666                         mangled_name = g_strconcat (import, "A", NULL);
667                         g_module_symbol (gmodule, mangled_name, &method->addr); 
668                         g_free (mangled_name);
669
670                         if (!method->addr)
671                                 g_module_symbol (gmodule, import, &method->addr); 
672                                
673                         break;                                  
674                 }
675         }
676
677         if (!method->addr) {
678                 g_warning ("Failed to load function %s from %s", import, scope);
679                 return NULL;
680         }
681         return method->addr;
682 }
683
684 static MonoMethod *
685 mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass)
686 {
687         MonoMethod *result;
688         int table = mono_metadata_token_table (token);
689         int idx = mono_metadata_token_index (token);
690         MonoTableInfo *tables = image->tables;
691         const char *loc, *sig = NULL;
692         int size, i;
693         guint32 cols [MONO_TYPEDEF_SIZE];
694
695         if (image->dynamic)
696                 return mono_lookup_dynamic_token (image, token);
697
698         if (table != MONO_TABLE_METHOD) {
699                 if (table == MONO_TABLE_METHODSPEC)
700                         return method_from_methodspec (image, idx);
701                 if (table != MONO_TABLE_MEMBERREF)
702                         g_print("got wrong token: 0x%08x\n", token);
703                 g_assert (table == MONO_TABLE_MEMBERREF);
704                 result = method_from_memberref (image, idx);
705
706                 return result;
707         }
708
709         mono_metadata_decode_row (&tables [table], idx - 1, cols, 6);
710
711         if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
712             (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
713                 result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
714         else 
715                 result = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
716         
717         result->slot = -1;
718         result->klass = klass;
719         result->flags = cols [2];
720         result->iflags = cols [1];
721         result->token = token;
722         result->name = mono_metadata_string_heap (image, cols [3]);
723
724         if (!sig) /* already taken from the methodref */
725                 sig = mono_metadata_blob_heap (image, cols [4]);
726         size = mono_metadata_decode_blob_size (sig, &sig);
727         result->signature = mono_metadata_parse_method_signature (image, idx, sig, NULL);
728
729         if (!result->klass) {
730                 guint32 type = mono_metadata_typedef_from_method (image, token);
731                 result->klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
732         }
733
734         if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
735                 if (result->klass == mono_defaults.string_class && !strcmp (result->name, ".ctor"))
736                         result->string_ctor = 1;
737
738                 result->signature->pinvoke = 1;
739         } else if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (!(cols [1] & METHOD_IMPL_ATTRIBUTE_NATIVE))) {
740                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)result;
741                 MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
742                 MonoCallConvention conv = 0;
743
744                 result->signature->pinvoke = 1;
745                 piinfo->implmap_idx = mono_metadata_implmap_from_method (image, idx - 1);
746                 piinfo->piflags = mono_metadata_decode_row_col (im, piinfo->implmap_idx - 1, MONO_IMPLMAP_FLAGS);
747
748                 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CALL_CONV_MASK) {
749                 case PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI:
750                         conv = MONO_CALL_DEFAULT;
751                         break;
752                 case PINVOKE_ATTRIBUTE_CALL_CONV_CDECL:
753                         conv = MONO_CALL_C;
754                         break;
755                 case PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL:
756                         conv = MONO_CALL_STDCALL;
757                         break;
758                 case PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL:
759                         conv = MONO_CALL_THISCALL;
760                         break;
761                 case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL:
762                         conv = MONO_CALL_FASTCALL;
763                         break;
764                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC:
765                 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST:
766                 default:
767                         g_warning ("unsupported calling convention");
768                         g_assert_not_reached ();
769                 }       
770                 result->signature->call_convention = conv;
771         } else {
772                 /* if this is a methodref from another module/assembly, this fails */
773                 loc = mono_cli_rva_map ((MonoCLIImageInfo *)image->image_info, cols [0]);
774
775                 if (!result->klass->dummy && !(result->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
776                                         !(result->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
777                         MonoMethodNormal *mn = (MonoMethodNormal *) result;
778
779                         g_assert (loc);
780                         mn->header = mono_metadata_parse_mh (image, loc);
781
782                         if (result->signature->generic_param_count) {
783                                 mn->header->gen_params = mono_metadata_load_generic_params (image, token, NULL);
784
785                                 for (i = 0; i < result->signature->generic_param_count; i++)
786                                         mn->header->gen_params [i].method = result;
787                         }
788                 }
789         }
790
791         return result;
792 }
793
794 MonoMethod *
795 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
796 {
797         MonoMethod *result;
798
799         /* We do everything inside the lock to prevent creation races */
800
801         mono_loader_lock ();
802
803         if ((result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token)))) {
804                 mono_loader_unlock ();
805                 return result;
806         }
807
808         result = mono_get_method_from_token (image, token, klass);
809
810         g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
811
812         mono_loader_unlock ();
813
814         return result;
815 }
816
817 void
818 mono_free_method  (MonoMethod *method)
819 {
820         mono_metadata_free_method_signature (method->signature);
821         if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
822                 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
823                 g_free (piinfo->code);
824         } else if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
825                 mono_metadata_free_mh (((MonoMethodNormal *)method)->header);
826         }
827
828         g_free (method);
829 }
830
831 void
832 mono_method_get_param_names (MonoMethod *method, const char **names)
833 {
834         int i, lastp;
835         MonoClass *klass = method->klass;
836         MonoTableInfo *methodt;
837         MonoTableInfo *paramt;
838
839         if (!method->signature->param_count)
840                 return;
841         for (i = 0; i < method->signature->param_count; ++i)
842                 names [i] = "";
843
844         mono_class_init (klass);
845
846         if (klass->wastypebuilder || klass->generic_inst) /* copy the names later */
847                 return;
848
849         if (klass->image->dynamic) {
850                 MonoReflectionMethodAux *method_aux = 
851                         mono_g_hash_table_lookup (
852                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
853                 if (method_aux && method_aux->param_names) {
854                         for (i = 0; i < method->signature->param_count; ++i)
855                                 if (method_aux->param_names [i])
856                                         names [i] = method_aux->param_names [i];
857                 }
858                 return;
859         }
860
861         methodt = &klass->image->tables [MONO_TABLE_METHOD];
862         paramt = &klass->image->tables [MONO_TABLE_PARAM];
863         for (i = 0; i < klass->method.count; ++i) {
864                 if (method == klass->methods [i]) {
865                         guint32 idx = klass->method.first + i;
866                         guint32 cols [MONO_PARAM_SIZE];
867                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
868
869                         if (idx + 1 < methodt->rows)
870                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
871                         else
872                                 lastp = paramt->rows + 1;
873                         for (i = param_index; i < lastp; ++i) {
874                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
875                                 if (cols [MONO_PARAM_SEQUENCE]) /* skip return param spec */
876                                         names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass->image, cols [MONO_PARAM_NAME]);
877                         }
878                         return;
879                 }
880         }
881 }
882
883 void
884 mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs)
885 {
886         int i, lastp;
887         MonoClass *klass = method->klass;
888         MonoTableInfo *methodt;
889         MonoTableInfo *paramt;
890
891         for (i = 0; i < method->signature->param_count + 1; ++i)
892                 mspecs [i] = NULL;
893
894         if (method->klass->image->dynamic) {
895                 MonoReflectionMethodAux *method_aux = 
896                         mono_g_hash_table_lookup (
897                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
898                 if (method_aux && method_aux->param_marshall) {
899                         MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
900                         for (i = 0; i < method->signature->param_count + 1; ++i)
901                                 if (dyn_specs [i]) {
902                                         mspecs [i] = g_new0 (MonoMarshalSpec, 1);
903                                         memcpy (mspecs [i], dyn_specs [i], sizeof (MonoMarshalSpec));
904                                 }
905                 }
906                 return;
907         }
908
909         mono_class_init (klass);
910
911         methodt = &klass->image->tables [MONO_TABLE_METHOD];
912         paramt = &klass->image->tables [MONO_TABLE_PARAM];
913
914         for (i = 0; i < klass->method.count; ++i) {
915                 if (method == klass->methods [i]) {
916                         guint32 idx = klass->method.first + i;
917                         guint32 cols [MONO_PARAM_SIZE];
918                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
919
920                         if (idx + 1 < methodt->rows)
921                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
922                         else
923                                 lastp = paramt->rows + 1;
924
925                         for (i = param_index; i < lastp; ++i) {
926                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
927
928                                 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) {
929                                         const char *tp;
930                                         tp = mono_metadata_get_marshal_info (klass->image, i - 1, FALSE);
931                                         g_assert (tp);
932                                         mspecs [cols [MONO_PARAM_SEQUENCE]]= mono_metadata_parse_marshal_spec (klass->image, tp);
933                                 }
934                         }
935
936                         return;
937                 }
938         }
939 }
940
941 gboolean
942 mono_method_has_marshal_info (MonoMethod *method)
943 {
944         int i, lastp;
945         MonoClass *klass = method->klass;
946         MonoTableInfo *methodt;
947         MonoTableInfo *paramt;
948
949         if (method->klass->image->dynamic) {
950                 MonoReflectionMethodAux *method_aux = 
951                         mono_g_hash_table_lookup (
952                                 ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
953                 MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
954                 if (dyn_specs) {
955                         for (i = 0; i < method->signature->param_count + 1; ++i)
956                                 if (dyn_specs [i])
957                                         return TRUE;
958                 }
959                 return FALSE;
960         }
961
962         mono_class_init (klass);
963
964         methodt = &klass->image->tables [MONO_TABLE_METHOD];
965         paramt = &klass->image->tables [MONO_TABLE_PARAM];
966
967         for (i = 0; i < klass->method.count; ++i) {
968                 if (method == klass->methods [i]) {
969                         guint32 idx = klass->method.first + i;
970                         guint32 cols [MONO_PARAM_SIZE];
971                         guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
972
973                         if (idx + 1 < methodt->rows)
974                                 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
975                         else
976                                 lastp = paramt->rows + 1;
977
978                         for (i = param_index; i < lastp; ++i) {
979                                 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
980
981                                 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL)
982                                         return TRUE;
983                         }
984                         return FALSE;
985                 }
986         }
987         return FALSE;
988 }
989
990 gpointer
991 mono_method_get_wrapper_data (MonoMethod *method, guint32 id)
992 {
993         GList *l;
994         g_assert (method != NULL);
995         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
996
997         if (!(l = g_list_nth (((MonoMethodWrapper *)method)->data, id - 1)))
998                 g_assert_not_reached ();
999
1000         return l->data;
1001 }
1002
1003 static void
1004 default_stack_walk (MonoStackWalk func, gpointer user_data) {
1005         g_error ("stack walk not installed");
1006 }
1007
1008 static MonoStackWalkImpl stack_walk = default_stack_walk;
1009
1010 void
1011 mono_stack_walk (MonoStackWalk func, gpointer user_data)
1012 {
1013         stack_walk (func, user_data);
1014 }
1015
1016 void
1017 mono_install_stack_walk (MonoStackWalkImpl func)
1018 {
1019         stack_walk = func;
1020 }
1021
1022 static gboolean
1023 last_managed (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
1024 {
1025         MonoMethod **dest = data;
1026         *dest = m;
1027         /*g_print ("In %s::%s [%d] [%d]\n", m->klass->name, m->name, no, ilo);*/
1028
1029         return managed;
1030 }
1031
1032 MonoMethod*
1033 mono_method_get_last_managed (void)
1034 {
1035         MonoMethod *m = NULL;
1036         stack_walk (last_managed, &m);
1037         return m;
1038 }
1039
1040
1041