Mon Apr 15 11:37:33 CEST 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / loader.c
index 84f4251444c41b5b55cc910aee300354906f0e60..42f9c2366eec4b05b8ac30be0062cd989723e64d 100644 (file)
 #include <string.h>
 #include <mono/metadata/metadata.h>
 #include <mono/metadata/image.h>
+#include <mono/metadata/assembly.h>
 #include <mono/metadata/tokentype.h>
 #include <mono/metadata/cil-coff.h>
 #include <mono/metadata/tabledefs.h>
-#include "cli.h"
+#include <mono/metadata/loader.h>
+#include <mono/metadata/class.h>
 
-static guint32
-typedef_from_name (MonoImage *image, const char *name, const char *nspace, guint32 *mlist)
+static gboolean dummy_icall = TRUE;
+
+MonoDefaults mono_defaults;
+
+#ifdef __CYGWIN__
+#define mono_map_dll(name) (name)
+#else
+static const char *dll_map[] = {
+       "libc", "libc.so.6",
+       "libm", "libm.so.6",
+       "cygwin1.dll", "libc.so.6", 
+       NULL, NULL
+};
+
+static const char *
+mono_map_dll (const char *name)
 {
-       metadata_t *m = &image->metadata;
-       metadata_tableinfo_t *t = &m->tables [META_TABLE_TYPEDEF];
-       guint32 i;
-       guint32 cols [META_TYPEDEF_SIZE];
-
-       for (i=0; i < t->rows; ++i) {
-               mono_metadata_decode_row (t, i, cols, META_TYPEDEF_SIZE);
-               if (strcmp (name, mono_metadata_string_heap (m, cols [META_TYPEDEF_NAME])) == 0 
-                               && strcmp (nspace, mono_metadata_string_heap (m, cols [META_TYPEDEF_NAMESPACE])) == 0) {
-                       *mlist = cols [META_TYPEDEF_METHOD_LIST];
-                       return i + 1;
-               }
+       int i = 0;
+
+       while (dll_map [i]) {
+               if (!strcmp (dll_map [i], name))
+                       return  dll_map [i + 1];
+               i += 2;
        }
-       g_assert_not_reached ();
-       return 0;
+
+       return name;
+}
+#endif
+
+static GHashTable *icall_hash = NULL;
+
+void
+mono_add_internal_call (const char *name, gconstpointer method)
+{
+       if (!icall_hash) {
+               dummy_icall = FALSE;
+               icall_hash = g_hash_table_new (g_str_hash , g_str_equal);
+       }
+
+       g_hash_table_insert (icall_hash, g_strdup (name), method);
 }
 
 static void
-methoddef_from_memberref (MonoImage *image, guint32 index, MonoImage **rimage, guint32 *rindex)
+ves_icall_dummy (void)
 {
-       metadata_t *m = &image->metadata;
-       metadata_tableinfo_t *tables = m->tables;
+       g_warning ("the mono runtime is not initialized");
+       g_assert_not_reached ();
+}
+
+gpointer
+mono_lookup_internal_call (const char *name)
+{
+       gpointer res;
+
+       if (dummy_icall)
+               return ves_icall_dummy;
+
+       if (!icall_hash) {
+               g_warning ("icall_hash not initialized");
+               g_assert_not_reached ();
+       }
+
+       if (!(res = g_hash_table_lookup (icall_hash, name))) {
+               g_warning ("cant resolve internal call to \"%s\"", name);
+               return NULL;
+       }
+
+       return res;
+}
+
+MonoClassField*
+mono_field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass)
+{
+       MonoImage *mimage;
+       MonoClass *klass;
+       MonoTableInfo *tables = image->tables;
        guint32 cols[6];
-       guint32 nindex, sig_len, msig_len, class, i;
-       const char *sig, *msig, *mname, *name, *nspace;
+       guint32 nindex, class, i;
+       const char *fname, *name, *nspace;
+       const char *ptr;
+       guint32 idx = mono_metadata_token_index (token);
+
+       mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
+       nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
+       class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
+
+       fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
        
-       mono_metadata_decode_row (&tables [META_TABLE_MEMBERREF], index-1, cols, 3);
-       nindex = cols [META_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
-       class = cols [META_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
-       /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
-               mono_metadata_string_heap (m, cols [META_MEMBERREF_NAME]));*/
-       sig = mono_metadata_blob_heap (m, cols [META_MEMBERREF_SIGNATURE]);
-       sig_len = mono_metadata_decode_blob_size (sig, &sig);
-       mname = mono_metadata_string_heap (m, cols [META_MEMBERREF_NAME]);
+       ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
+       mono_metadata_decode_blob_size (ptr, &ptr);
+       /* we may want to check the signature here... */
 
        switch (class) {
        case MEMBERREF_PARENT_TYPEREF: {
                guint32 scopeindex, scopetable;
 
-               mono_metadata_decode_row (&tables [META_TABLE_TYPEREF], nindex-1, cols, META_TYPEREF_SIZE);
-               scopeindex = cols [META_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
-               scopetable = cols [META_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK;
+               mono_metadata_decode_row (&tables [MONO_TABLE_TYPEREF], nindex-1, cols, MONO_TYPEREF_SIZE);
+               scopeindex = cols [MONO_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
+               scopetable = cols [MONO_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK;
                /*g_print ("typeref: 0x%x 0x%x %s.%s\n", scopetable, scopeindex,
-                       mono_metadata_string_heap (m, cols [META_TYPEREF_NAMESPACE]),
-                       mono_metadata_string_heap (m, cols [META_TYPEREF_NAME]));*/
+                       mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]),
+                       mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]));*/
                switch (scopetable) {
                case RESOLTION_SCOPE_ASSEMBLYREF:
                        /*
-                        * To find the method we have the following info:
+                        * To find the field we have the following info:
                         * *) name and namespace of the class from the TYPEREF table
-                        * *) name and signature of the method from the MEMBERREF table
+                        * *) name and signature of the field from the MEMBERREF table
                         */
-                       nspace = mono_metadata_string_heap (m, cols [META_TYPEREF_NAMESPACE]);
-                       name = mono_metadata_string_heap (m, cols [META_TYPEREF_NAME]);
-                       
-                       image = image->references [scopeindex-1]->image;
-                       m = &image->metadata;
-                       tables = &m->tables [META_TABLE_METHOD];
-                       typedef_from_name (image, name, nspace, &i);
+                       nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
+                       name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
+
+                       /* this will triggered by references to mscorlib */
+                       if (image->references [scopeindex-1] == NULL)
+                               g_error ("Reference to mscorlib? Probably need to implement %s.%s::%s in corlib", nspace, name, fname);
+
+                       mimage = image->references [scopeindex-1]->image;
+
+                       klass = mono_class_from_name (mimage, nspace, name);
+                       mono_class_init (klass);
+
                        /* mostly dumb search for now */
-                       for (;i < tables->rows; ++i) {
-                               mono_metadata_decode_row (tables, i, cols, META_METHOD_SIZE);
-                               msig = mono_metadata_blob_heap (m, cols [META_METHOD_SIGNATURE]);
-                               msig_len = mono_metadata_decode_blob_size (msig, &msig);
-                               
-                               if (strcmp (mname, mono_metadata_string_heap (m, cols [META_METHOD_NAME])) == 0 
-                                               && sig_len == msig_len
-                                               && strncmp (sig, msig, sig_len) == 0) {
-                                       *rimage = image;
-                                       *rindex = i + 1;
-                                       return;
+                       for (i = 0; i < klass->field.count; ++i) {
+                               MonoClassField *f = &klass->fields [i];
+                               if (!strcmp (fname, f->name)) {
+                                       if (retklass)
+                                               *retklass = klass;
+                                       return f;
                                }
                        }
-                       g_assert_not_reached ();
-                       break;
+                       g_warning ("Missing field %s.%s::%s", nspace, name, fname);
+                       return NULL;
                default:
-                       g_assert_not_reached ();
+                       return NULL;
                }
                break;
        }
        default:
-               g_assert_not_reached ();
+               return NULL;
        }
 }
 
-static ffi_type *
-ves_map_ffi_type (MonoType *type)
+static MonoMethod *
+method_from_memberref (MonoImage *image, guint32 idx)
 {
-       ffi_type *rettype;
+       MonoImage *mimage;
+       MonoClass *klass;
+       MonoTableInfo *tables = image->tables;
+       guint32 cols[6];
+       guint32 nindex, class, i;
+       const char *mname, *name, *nspace;
+       MonoMethodSignature *sig;
+       const char *ptr;
+
+       mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
+       nindex = cols [MONO_MEMBERREF_CLASS] >> MEMBERREF_PARENT_BITS;
+       class = cols [MONO_MEMBERREF_CLASS] & MEMBERREF_PARENT_MASK;
+       /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
+               mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
 
-       if (!type)
-               return &ffi_type_void;
+       mname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
+       
+       ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
+       mono_metadata_decode_blob_size (ptr, &ptr);
+       sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
 
-       switch (type->type) {
-       case ELEMENT_TYPE_I1:
-               rettype = &ffi_type_sint8;
-               break;
-       case ELEMENT_TYPE_BOOLEAN:
-       case ELEMENT_TYPE_U1:
-               rettype = &ffi_type_uint8;
-               break;
-       case ELEMENT_TYPE_I2:
-               rettype = &ffi_type_sint16;
-               break;
-       case ELEMENT_TYPE_U2:
-       case ELEMENT_TYPE_CHAR:
-               rettype = &ffi_type_uint16;
-               break;
-       case ELEMENT_TYPE_I4:
-               rettype = &ffi_type_sint32;
-               break;
-       case ELEMENT_TYPE_U4:
-               rettype = &ffi_type_sint32;
-               break;
-       case ELEMENT_TYPE_R4:
-               rettype = &ffi_type_float;
-               break;
-       case ELEMENT_TYPE_R8:
-               rettype = &ffi_type_double;
+       switch (class) {
+       case MEMBERREF_PARENT_TYPEREF: {
+               guint32 scopeindex, scopetable;
+
+               mono_metadata_decode_row (&tables [MONO_TABLE_TYPEREF], nindex-1, cols, MONO_TYPEREF_SIZE);
+               scopeindex = cols [MONO_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
+               scopetable = cols [MONO_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK;
+               /*g_print ("typeref: 0x%x 0x%x %s.%s\n", scopetable, scopeindex,
+                       mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAMESPACE]),
+                       mono_metadata_string_heap (m, cols [MONO_TYPEREF_NAME]));*/
+               switch (scopetable) {
+               case RESOLTION_SCOPE_ASSEMBLYREF:
+                       /*
+                        * To find the method we have the following info:
+                        * *) name and namespace of the class from the TYPEREF table
+                        * *) name and signature of the method from the MEMBERREF table
+                        */
+                       nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
+                       name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
+
+                       /* this will triggered by references to mscorlib */
+                       if (image->references [scopeindex-1] == NULL)
+                               g_error ("Reference to mscorlib? Probably need to implement %s.%s::%s in corlib", nspace, name, mname);
+
+                       mimage = image->references [scopeindex-1]->image;
+
+                       klass = mono_class_from_name (mimage, nspace, name);
+                       if (!klass) {
+                               g_warning ("Missing method %s.%s::%s", nspace, name, mname);
+                               mono_metadata_free_method_signature (sig);
+                               return NULL;
+                       }
+                       mono_class_init (klass);
+
+                       /* mostly dumb search for now */
+                       for (i = 0; i < klass->method.count; ++i) {
+                               MonoMethod *m = klass->methods [i];
+                               if (!strcmp (mname, m->name)) {
+                                       if (mono_metadata_signature_equal (sig, m->signature)) {
+                                               mono_metadata_free_method_signature (sig);
+                                               return m;
+                                       }
+                               }
+                       }
+                       g_warning ("Missing method %s.%s::%s", nspace, name, mname);
+                       mono_metadata_free_method_signature (sig);
+                       return NULL;
+               default:
+                       mono_metadata_free_method_signature (sig);
+                       return NULL;
+               }
                break;
-       case ELEMENT_TYPE_STRING:
-               rettype = &ffi_type_pointer;
+       }
+       case MEMBERREF_PARENT_TYPESPEC: {
+               guint32 bcols [MONO_TYPESPEC_SIZE];
+               guint32 len;
+               MonoType *type;
+               MonoMethod *result;
+
+               mono_metadata_decode_row (&tables [MONO_TABLE_TYPESPEC], nindex - 1, 
+                                         bcols, MONO_TYPESPEC_SIZE);
+               ptr = mono_metadata_blob_heap (image, bcols [MONO_TYPESPEC_SIGNATURE]);
+               len = mono_metadata_decode_value (ptr, &ptr);   
+               type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
+
+               if (type->type != MONO_TYPE_ARRAY)
+                       g_assert_not_reached ();                
+
+               result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
+               result->klass = mono_class_get (image, MONO_TOKEN_TYPE_SPEC | nindex);
+               result->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
+               result->signature = sig;
+               result->name = mname;
+
+               if (!strcmp (mname, ".ctor")) {
+                       /* we special-case this in the runtime. */
+                       result->addr = NULL;
+                       return result;
+               }
+               
+               if (!strcmp (mname, "Set")) {
+                       g_assert (sig->hasthis);
+                       g_assert (type->data.array->rank + 1 == sig->param_count);
+
+                       result->addr = mono_lookup_internal_call ("__array_Set");
+                       return result;
+               }
+
+               if (!strcmp (mname, "Get")) {
+                       g_assert (sig->hasthis);
+                       g_assert (type->data.array->rank == sig->param_count);
+
+                       result->addr = mono_lookup_internal_call ("__array_Get");
+                       return result;
+               }
+
+               if (!strcmp (mname, "Address")) {
+                       g_assert (sig->hasthis);
+                       g_assert (type->data.array->rank == sig->param_count);
+
+                       result->addr = mono_lookup_internal_call ("__array_Address");
+                       return result;
+               }
+
+               g_assert_not_reached ();
                break;
+       }
        default:
-               g_warning ("not implemented");
                g_assert_not_reached ();
        }
 
-       return rettype;
+       return NULL;
 }
 
 static void
-fill_pinvoke_info (MonoImage *image, MonoMethodPInvoke *piinfo, int index, 
-                  guint16 iflags)
+fill_pinvoke_info (MonoImage *image, MonoMethodPInvoke *piinfo, int idx)
 {
        MonoMethod *mh = &piinfo->method;
-       metadata_tableinfo_t *tables = image->metadata.tables;
-       metadata_tableinfo_t *im = &tables [META_TABLE_IMPLMAP];
-       metadata_tableinfo_t *mr = &tables [META_TABLE_MODULEREF];
+       MonoTableInfo *tables = image->tables;
+       MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
+       MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
        guint32 im_cols [4];
        guint32 mr_cols [1];
        const char *import = NULL;
        const char *scope = NULL;
+       char *full_name;
        GModule *gmodule;
-       ffi_type **args, *rettype;
-       int i, acount;
+       int i;
 
        for (i = 0; i < im->rows; i++) {
                        
                mono_metadata_decode_row (im, i, im_cols, 4);
 
-               if ((im_cols[1] >> 1) == index + 1) {
+               if ((im_cols[1] >> 1) == idx + 1) {
 
-                       import = mono_metadata_string_heap (&image->metadata, 
-                                                           im_cols [2]);
+                       import = mono_metadata_string_heap (image, im_cols [2]);
 
                        mono_metadata_decode_row (mr, im_cols [3] - 1, mr_cols,
                                                  1);
                        
-                       scope = mono_metadata_string_heap (&image->metadata, 
-                                                          mr_cols [0]);
+                       scope = mono_metadata_string_heap (image, mr_cols [0]);
                }
        }
 
-       g_assert (import && scope);
-
-       if (!strcmp (scope, "cygwin1.dll"))
-               scope = "libc.so.6";
-
-       gmodule = g_module_open (scope, G_MODULE_BIND_LAZY);
-
-       g_assert (gmodule);
-
-       piinfo->cif = g_new (ffi_cif , 1);
-       piinfo->iflags = iflags;
-       
-       g_module_symbol (gmodule, import, &piinfo->addr); 
-                       
-       g_assert (piinfo->addr);
+       piinfo->piflags = im_cols [0];
 
-       acount = mh->signature->param_count;
+       g_assert (import && scope);
 
-       args = g_new (ffi_type *, acount);
+       scope = mono_map_dll (scope);
+       full_name = g_module_build_path (NULL, scope);
+       gmodule = g_module_open (full_name, G_MODULE_BIND_LAZY);
 
-       for (i = 0; i < acount; i++)
-               args[i] = ves_map_ffi_type (mh->signature->params [i]->type);
+       mh->addr = NULL;
+       if (!gmodule) {
+               if (!(gmodule=g_module_open (scope, G_MODULE_BIND_LAZY))) {
+                       g_warning ("Failed to load library %s (%s)", full_name, scope);
+                       g_free (full_name);
+                       return;
+               }
+       }
+       g_free (full_name);
 
-       rettype = ves_map_ffi_type (mh->signature->ret->type);
+       g_module_symbol (gmodule, import, &mh->addr); 
 
-       if (!ffi_prep_cif (piinfo->cif, FFI_DEFAULT_ABI, acount, rettype, 
-                          args) == FFI_OK) {
-               g_warning ("prepare pinvoke failed");
-               g_assert_not_reached ();
+       if (!mh->addr) {
+               g_warning ("Failed to load function %s from %s", import, scope);
+               return;
        }
+
+       mh->flags |= METHOD_ATTRIBUTE_PINVOKE_IMPL;
 }
 
 MonoMethod *
-mono_get_method (MonoImage *image, guint32 token)
+mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
 {
        MonoMethod *result;
        int table = mono_metadata_token_table (token);
-       int index = mono_metadata_token_index (token);
-       metadata_tableinfo_t *tables = image->metadata.tables;
-       const char *loc;
-       const char *sig = NULL;
+       int idx = mono_metadata_token_index (token);
+       MonoTableInfo *tables = image->tables;
+       const char *loc, *sig = NULL;
+       char *name;
        int size;
-       guint32 cols[6];
+       guint32 cols [MONO_TYPEDEF_SIZE];
 
-       if (table == META_TABLE_METHOD && (result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token))))
+       if ((result = g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token))))
                        return result;
-       
-       if (table != META_TABLE_METHOD) {
-               g_assert (table == META_TABLE_MEMBERREF);
-               methoddef_from_memberref (image, index, &image, &token);
-               return mono_get_method (image, TOKEN_TYPE_METHOD_DEF | token);
+
+       if (table != MONO_TABLE_METHOD) {
+               if (table != MONO_TABLE_MEMBERREF)
+                       g_print("got wrong token: 0x%08x\n", token);
+               g_assert (table == MONO_TABLE_MEMBERREF);
+               result = method_from_memberref (image, idx);
+               g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
+               return result;
        }
 
-       
-       mono_metadata_decode_row (&tables [table], index - 1, cols, 6);
+       mono_metadata_decode_row (&tables [table], idx - 1, cols, 6);
 
-       if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL)
+       if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+           (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
                result = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
-       else
-               result = (MonoMethod *)g_new0 (MonoMethodManaged, 1);
-
-       result->image = image;
+       else 
+               result = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
+       
+       result->slot = -1;
+       result->klass = klass;
        result->flags = cols [2];
-       result->name = mono_metadata_string_heap (&image->metadata, cols [3]);
+       result->iflags = cols [1];
+       result->name = mono_metadata_string_heap (image, cols [3]);
 
        if (!sig) /* already taken from the methodref */
-               sig = mono_metadata_blob_heap (&image->metadata, cols [4]);
+               sig = mono_metadata_blob_heap (image, cols [4]);
        size = mono_metadata_decode_blob_size (sig, &sig);
-       result->signature = mono_metadata_parse_method_signature (&image->metadata, 0, sig, NULL);
+       result->signature = mono_metadata_parse_method_signature (image, 0, sig, NULL);
 
+       if (!result->klass) {
+               guint32 type = mono_metadata_typedef_from_method (image, token);
+               result->klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
+       }
 
-       if (result->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
-               fill_pinvoke_info (image, (MonoMethodPInvoke *)result, 
-                                  index, cols [1]);
+       if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
+               name = g_strconcat (result->klass->name_space, ".", result->klass->name, "::", 
+                                   mono_metadata_string_heap (image, cols [MONO_METHOD_NAME]), NULL);
+               result->addr = mono_lookup_internal_call (name);
+               g_free (name);
+               result->flags |= METHOD_ATTRIBUTE_PINVOKE_IMPL;
+       } else if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
+               fill_pinvoke_info (image, (MonoMethodPInvoke *)result, idx - 1);
        } else {
                /* if this is a methodref from another module/assembly, this fails */
-               loc = cli_rva_map ((cli_image_info_t *)image->image_info, cols [0]);
-               g_assert (loc);
-               ((MonoMethodManaged *)result)->header = 
-                       mono_metadata_parse_mh (&image->metadata, loc);
+               loc = mono_cli_rva_map ((MonoCLIImageInfo *)image->image_info, cols [0]);
+
+               if (!result->klass->dummy && !(result->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
+                                       !(result->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
+                       g_assert (loc);
+                       ((MonoMethodNormal *)result)->header = mono_metadata_parse_mh (image, loc);
+               }
        }
 
        g_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
@@ -287,11 +445,48 @@ mono_free_method  (MonoMethod *method)
        mono_metadata_free_method_signature (method->signature);
        if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
                MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
-               g_free (piinfo->cif->arg_types);
-               g_free (piinfo->cif);
-       } else {
-               mono_metadata_free_mh (((MonoMethodManaged *)method)->header);
+               g_free (piinfo->code);
+       } else if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
+               mono_metadata_free_mh (((MonoMethodNormal *)method)->header);
        }
 
        g_free (method);
 }
+
+void
+mono_method_get_param_names (MonoMethod *method, const char **names)
+{
+       int i, lastp;
+       MonoClass *klass = method->klass;
+       MonoTableInfo *methodt = &klass->image->tables [MONO_TABLE_METHOD];
+       MonoTableInfo *paramt = &klass->image->tables [MONO_TABLE_PARAM];
+
+       if (!method->signature->param_count)
+               return;
+       for (i = 0; i < method->signature->param_count; ++i)
+               names [i] = "";
+
+       mono_class_init (klass);
+       if (!klass->methods)
+               return;
+
+       for (i = 0; i < klass->method.count; ++i) {
+               if (method == klass->methods [i]) {
+                       guint32 idx = klass->method.first + i;
+                       guint32 cols [MONO_PARAM_SIZE];
+                       guint param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
+
+                       if (idx < methodt->rows)
+                               lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
+                       else
+                               lastp = paramt->rows;
+                       for (i = param_index; i < lastp; ++i) {
+                               mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
+                               if (cols [MONO_PARAM_SEQUENCE]) /* skip return param spec */
+                                       names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass->image, cols [MONO_PARAM_NAME]);
+                       }
+                       return;
+               }
+       }
+}
+