Mon Jan 19 17:44:50 CET 2004 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / aot.c
index 6f388fbb7313cfdfdc79a7bbae4c96d384056f6c..a24419d440eff910468080f669dca3d5c3212713 100644 (file)
@@ -30,6 +30,7 @@
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/assembly.h>
+#include <mono/metadata/marshal.h>
 #include <mono/os/gc_wrapper.h>
 
 #include "mini.h"
@@ -68,6 +69,20 @@ static MonoGHashTable *aot_modules;
 
 static CRITICAL_SECTION aot_mutex;
 
+static guint32 mono_aot_verbose = 0;
+
+/*
+ * Disabling this will make a copy of the loaded code and use the copy instead 
+ * of the original. This will place the caller and the callee close to each 
+ * other in memory, possibly improving cache behavior. Since the original
+ * code is in copy-on-write memory, this will not increase the memory usage
+ * of the runtime.
+ */
+static gboolean use_loaded_code = FALSE;
+
+/* For debugging */
+static gint32 mono_last_aot_method = -1;
+
 static MonoClass * 
 decode_class_info (MonoAotModule *module, gpointer *data)
 {
@@ -97,9 +112,6 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        char *aot_version = NULL;
        char *opt_flags = NULL;
 
-       if (mono_no_aot)
-               return;
-
        aot_name = g_strdup_printf ("%s.so", assembly->image->name);
 
        assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
@@ -112,12 +124,14 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
 
        if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
-               printf ("AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
+               if (mono_aot_verbose > 0)
+                       printf ("AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
                usable = FALSE;
        }
        else
                if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
-                       printf ("AOT module %s is out of date.\n", aot_name);
+                       if (mono_aot_verbose > 0)
+                               printf ("AOT module %s is out of date.\n", aot_name);
                        usable = FALSE;
                }
 
@@ -154,10 +168,13 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                for (i = 0; i < table_len; ++i) {
                        info->image_table [i] = mono_image_loaded_by_guid (table);
                        if (!info->image_table [i]) {
-                               printf ("AOT module %s is out of date.\n", aot_name);
-                               g_free (info->methods);
+                               if (mono_aot_verbose > 0)
+                                       printf ("AOT module %s is out of date.\n", aot_name);
+                               mono_g_hash_table_destroy (info->methods);
                                g_free (info->image_table);
+#ifndef HAVE_BOEHM_GC
                                g_free (info);
+#endif
                                g_free (aot_name);
                                g_module_close (assembly->aot_module);
                                assembly->aot_module = NULL;
@@ -192,7 +209,8 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        mono_g_hash_table_insert (aot_modules, assembly, info);
        LeaveCriticalSection (&aot_mutex);
 
-       printf ("Loaded AOT Module for %s.\n", assembly->image->name);
+       if (mono_aot_verbose > 0)
+               printf ("Loaded AOT Module for %s.\n", assembly->image->name);
 }
 
 void
@@ -203,6 +221,9 @@ mono_aot_init (void)
        aot_modules = mono_g_hash_table_new (NULL, NULL);
 
        mono_install_assembly_load_hook (load_aot_module, NULL);
+
+       if (getenv ("MONO_LASTAOT"))
+               mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
 }
  
 static MonoJitInfo *
@@ -212,7 +233,8 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        MonoAssembly *ass = klass->image->assembly;
        MonoJumpInfo *patch_info = NULL;
        GModule *module = ass->aot_module;
-       char *method_label, *info_label;
+       char method_label [256];
+       char info_label [256];
        guint8 *code = NULL;
        gpointer *info;
        guint code_len, used_int_regs, used_strings;
@@ -228,6 +250,15 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        if (!method->token)
                return NULL;
 
+       if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
+               return NULL;
+
+       if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
+               (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+               (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
+               (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
+               return NULL;
+
        aot_module = (MonoAotModule*)mono_g_hash_table_lookup (aot_modules, ass);
 
        g_assert (klass->inited);
@@ -256,11 +287,12 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                        code = mono_mempool_alloc (domain->code_mp, minfo->info->code_size);
                        memcpy (code, minfo->info->code_start, minfo->info->code_size);
 
-                       //printf ("REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + code_len);
+                       if (mono_aot_verbose > 1)
+                               printf ("REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + minfo->info->code_size);
 
                        /* Do this outside the lock to avoid deadlocks */
                        LeaveCriticalSection (&aot_mutex);
-                       mono_arch_patch_code (method, domain, code, minfo->patch_info);
+                       mono_arch_patch_code (method, domain, code, minfo->patch_info, TRUE);
                        EnterCriticalSection (&aot_mutex);
 
                        /* Relocate jinfo */
@@ -288,40 +320,28 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                guint32 w;
                w = aot_module->methods_present_table [index / 32];
                if (! (w & (1 << (index % 32)))) {
-                       //printf ("NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
+                       if (mono_aot_verbose > 1)
+                               printf ("NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
                        return NULL;
                }
        }
 
-       method_label = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
-
-       if (!g_module_symbol (module, method_label, (gpointer *)&code)) {
-               g_free (method_label);          
+       sprintf (method_label, "m_%x", mono_metadata_token_index (method->token));
 
+       if (!g_module_symbol (module, method_label, (gpointer *)&code))
                return NULL;
-       }
 
-       info_label = g_strdup_printf ("%s_p", method_label);
-       if (!g_module_symbol (module, info_label, (gpointer *)&info)) {
-               g_free (method_label);          
-               g_free (info_label);
+       sprintf (info_label, "%s_p", method_label);
 
+       if (!g_module_symbol (module, info_label, (gpointer *)&info))
                return NULL;
-       }
 
-       {
-               static int count = 0;
-
-               count ++;
-
-               if (getenv ("MONO_LASTAOT")) {
-                       if (count > atoi(getenv ("MONO_LASTAOT"))) {
+       if (mono_last_aot_method != -1) {
+               if (mono_jit_stats.methods_aot > mono_last_aot_method)
                                return NULL;
-                       }
-                       else
-                               if (count == atoi(getenv ("MONO_LASTAOT")))
-                                       printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
-               }
+               else
+                       if (mono_jit_stats.methods_aot == mono_last_aot_method)
+                               printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
        }
 
 #ifdef HAVE_BOEHM_GC
@@ -337,7 +357,15 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        used_int_regs = GPOINTER_TO_UINT (*((gpointer **)info));
        info++;
 
-       //printf ("FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
+       if (!use_loaded_code) {
+               guint8 *code2;
+               code2 = mono_mempool_alloc (domain->code_mp, code_len);
+               memcpy (code2, code, code_len);
+               code = code2;
+       }
+
+       if (mono_aot_verbose > 1)
+               printf ("FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
 
        /* Exception table */
        if (header->num_clauses) {
@@ -381,17 +409,24 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        }
 
        if (*info) {
-               MonoMemPool *mp = mono_mempool_new (); 
+               MonoMemPool *mp;
                MonoImage *image;
                guint8 *page_start;
                gpointer *table;
                int pages;
                int i, err;
-               guint32 last_offset;
+               guint32 last_offset, buf_len;
+
+               if (aot_module->opts & MONO_OPT_SHARED)
+                       mp = mono_mempool_new ();
+               else
+                       mp = domain->mp;
 
                last_offset = 0;
                while (*info) {
                        MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
+                       gpointer *data;
+
                        guint8 b1, b2;
 
                        b1 = *(guint8*)info;
@@ -412,25 +447,28 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                        last_offset = ji->ip.i;
                        //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
 
-                       gpointer *data = *((gpointer **)info);
+                       data = *((gpointer **)info);
 
                        switch (ji->type) {
                        case MONO_PATCH_INFO_CLASS:
+                       case MONO_PATCH_INFO_IID:
                                ji->data.klass = decode_class_info (aot_module, data);
                                g_assert (ji->data.klass);
                                mono_class_init (ji->data.klass);
                                break;
                        case MONO_PATCH_INFO_VTABLE:
+                       case MONO_PATCH_INFO_CLASS_INIT:
                                ji->data.klass = decode_class_info (aot_module, data);
                                g_assert (ji->data.klass);
                                mono_class_init (ji->data.klass);
                                break;
                        case MONO_PATCH_INFO_IMAGE:
-                               ji->data.image = aot_module->image_table [(guint32)data [0]];
+                               ji->data.image = aot_module->image_table [(guint32)data];
                                g_assert (ji->data.image);
                                break;
                        case MONO_PATCH_INFO_METHOD:
-                       case MONO_PATCH_INFO_METHODCONST: {
+                       case MONO_PATCH_INFO_METHODCONST:
+                       case MONO_PATCH_INFO_METHOD_JUMP: {
                                guint32 image_index, token;
 
                                image_index = (guint32)data >> 24;
@@ -443,14 +481,31 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
 
                                break;
                        }
+                       case MONO_PATCH_INFO_WRAPPER: {
+                               guint32 image_index, token;
+                               guint32 wrapper_type;
+
+                               wrapper_type = (guint32)data[0];
+                               image_index = (guint32)data[1] >> 24;
+                               token = MONO_TOKEN_METHOD_DEF | ((guint32)data[1] & 0xffffff);
+
+                               image = aot_module->image_table [image_index];
+                               ji->data.method = mono_get_method (image, token, NULL);
+                               g_assert (ji->data.method);
+                               mono_class_init (ji->data.method->klass);
+
+                               g_assert (wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
+                               ji->type = MONO_PATCH_INFO_METHOD;
+                               ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
+                               break;
+                       }
                        case MONO_PATCH_INFO_FIELD:
-                       case MONO_PATCH_INFO_SFLDA:
-                               image = aot_module->image_table [(guint32)data [1]];
-                               g_assert (image);
-                               ji->data.field = mono_field_from_token (image, (guint32)data [0], NULL);
-                               mono_class_init (ji->data.field->parent);
-                               g_assert (ji->data.field);
+                       case MONO_PATCH_INFO_SFLDA: {
+                               MonoClass *klass = decode_class_info (aot_module, data [1]);
+                               mono_class_init (klass);
+                               ji->data.field = mono_class_get_field (klass, (guint32)data [0]);
                                break;
+                       }
                        case MONO_PATCH_INFO_INTERNAL_METHOD:
                                ji->data.name = aot_module->icall_table [(guint32)data];
                                g_assert (ji->data.name);
@@ -471,7 +526,8 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                        case MONO_PATCH_INFO_LDSTR:
                        case MONO_PATCH_INFO_LDTOKEN:
                        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
-                               ji->data.target = *data;
+                               image = aot_module->image_table [(int)data [0]];
+                               ji->data.token = mono_jump_info_token_new (mp, image, (int)data [1]);
                                break;
                        case MONO_PATCH_INFO_EXC_NAME:
                                ji->data.klass = decode_class_info (aot_module, data);
@@ -492,34 +548,38 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
                        patch_info = ji;
                }
 
-#ifndef PLATFORM_WIN32
+               info = (gpointer)((guint8*)info + 4);
+               buf_len = *(guint32*)info;
+               info = (gpointer)((guint8*)info + 4);
+               mono_debug_add_aot_method (domain, method, code, (guint8*)info, buf_len);
+
+               if (use_loaded_code) {
                /* disable write protection */
-               page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
-               pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
-               err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
-               g_assert (err == 0);
+#ifndef PLATFORM_WIN32
+                       page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
+                       pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
+                       err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
+                       g_assert (err == 0);
 #else
-               {
-                       DWORD oldp;
-                       g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
-               }
+                       {
+                               DWORD oldp;
+                               g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
+                       }
 #endif
+               }
 
                /* Do this outside the lock to avoid deadlocks */
                LeaveCriticalSection (&aot_mutex);
-               mono_arch_patch_code (method, domain, code, patch_info);
+               mono_arch_patch_code (method, domain, code, patch_info, TRUE);
                EnterCriticalSection (&aot_mutex);
 
                if (aot_module->opts & MONO_OPT_SHARED)
-                       /* No need to cache this */
+                       /* No need to cache patches */
                        mono_mempool_destroy (mp);
                else
                        minfo->patch_info = patch_info;
        }
 
-       g_free (info_label);
-       g_free (method_label);
-
        mono_jit_stats.methods_aot++;
 
        {
@@ -536,7 +596,7 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        }
 }
 
-gpointer
+MonoJitInfo*
 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
 {
        MonoJitInfo *info;
@@ -548,7 +608,7 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
        /* Do this outside the lock */
        if (info) {
                mono_jit_info_table_add (domain, info);
-               return info->code_start;
+               return info;
        }
        else
                return NULL;
@@ -655,19 +715,20 @@ static char *
 cond_emit_field_label (MonoAotCompile *cfg, MonoJumpInfo *patch_info)
 {
        MonoClassField *field = patch_info->data.field;
-       char *l1;
+       char *l1, *l2;
        guint token;
 
        if ((l1 = g_hash_table_lookup (cfg->ref_hash, field))) 
                return l1;
 
+       l2 = cond_emit_klass_label (cfg, field->parent);
        fprintf (cfg->fp, "\t.align %d\n", sizeof (gpointer));
        token = mono_get_field_token (field);
+       g_assert (token);
        l1 = g_strdup_printf ("klass_p_%08x_%p", token, field);
        fprintf (cfg->fp, "%s:\n", l1);
        fprintf (cfg->fp, "\t.long 0x%08x\n", token);
-       g_assert (token);
-       emit_image_index (cfg, field->parent->image);
+       fprintf (cfg->fp, "\t.long %s\n", l2);
                
        g_hash_table_insert (cfg->ref_hash, field, l1);
 
@@ -764,7 +825,8 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        break;
                }
                case MONO_PATCH_INFO_METHODCONST:
-               case MONO_PATCH_INFO_METHOD: {
+               case MONO_PATCH_INFO_METHOD:
+               case MONO_PATCH_INFO_METHOD_JUMP: {
                        /*
                         * The majority of patches are for methods, so we emit
                         * them inline instead of defining a label for them to
@@ -780,11 +842,30 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        j++;
                        break;
                }
+               case MONO_PATCH_INFO_WRAPPER: {
+                       MonoMethod *m;
+                       guint32 image_index;
+                       guint32 token;
+
+                       m = mono_marshal_method_from_wrapper (patch_info->data.method);
+                       image_index = get_image_index (acfg, m->klass->image);
+                       token = m->token;
+                       g_assert (image_index < 256);
+                       g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
+
+                       fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
+                       fprintf (tmpfp, "%s_p_%d:\n", mname, j);
+                       fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type);
+                       fprintf (tmpfp, "\t.long %d\n", (image_index << 24) + (mono_metadata_token_index (token)));
+                       j++;
+                       break;
+               }
                case MONO_PATCH_INFO_FIELD:
                        patch_info->data.name = cond_emit_field_label (acfg, patch_info);
                        j++;
                        break;
                case MONO_PATCH_INFO_CLASS:
+               case MONO_PATCH_INFO_IID:
                        patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
                        j++;
                        break;
@@ -823,6 +904,7 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        j++;
                        break;
                case MONO_PATCH_INFO_VTABLE:
+               case MONO_PATCH_INFO_CLASS_INIT:
                        patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
                        j++;
                        break;
@@ -835,7 +917,8 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
                        fprintf (tmpfp, "\t.align 8\n");
                        fprintf (tmpfp, "%s_p_%d:\n", mname, j);
-                       fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token);
+                       fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.token->image));
+                       fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token->token);
                        j++;
                        break;
                default:
@@ -888,6 +971,7 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
        if (j) {
                guint32 last_offset;
                last_offset = 0;
+
                j = 0;
                for (pindex = 0; pindex < patches->len; ++pindex) {
                        guint32 offset;
@@ -917,11 +1001,14 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        switch (patch_info->type) {
                        case MONO_PATCH_INFO_METHODCONST:
                        case MONO_PATCH_INFO_METHOD:
+                       case MONO_PATCH_INFO_METHOD_JUMP:
                        case MONO_PATCH_INFO_CLASS:
+                       case MONO_PATCH_INFO_IID:
                        case MONO_PATCH_INFO_FIELD:
                        case MONO_PATCH_INFO_INTERNAL_METHOD:
                        case MONO_PATCH_INFO_IMAGE:
                        case MONO_PATCH_INFO_VTABLE:
+                       case MONO_PATCH_INFO_CLASS_INIT:
                        case MONO_PATCH_INFO_SFLDA:
                        case MONO_PATCH_INFO_EXC_NAME:
                                fprintf (tmpfp, "\t.long %s\n", patch_info->data.name);
@@ -934,6 +1021,7 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
                        case MONO_PATCH_INFO_LDSTR:
                        case MONO_PATCH_INFO_LDTOKEN:
                        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+                       case MONO_PATCH_INFO_WRAPPER:
                                fprintf (tmpfp, "\t.long %s_p_%d\n", mname, j);
                                j++;
                                break;
@@ -954,6 +1042,21 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
        /* NULL terminated array */
        fprintf (tmpfp, "\t.long 0\n");
 
+       {
+               guint8 *buf;
+               guint32 buf_len;
+
+               mono_debug_serialize_debug_info (cfg, &buf, &buf_len);
+
+               fprintf (tmpfp, "\t.long %d\n", buf_len);
+
+               for (i = 0; i < buf_len; ++i)
+                       fprintf (tmpfp, ".byte %d\n", (unsigned int) buf [i]);
+
+               if (buf_len > 0)
+                       g_free (buf);
+       }
+
        /* fixme: save the rest of the required infos */
 
        g_free (mname);
@@ -968,13 +1071,13 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
        char *com, *tmpfname, *opts_str;
        FILE *tmpfp;
        int i;
-       guint8 *mname, *symbol;
+       guint8 *symbol;
        int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
        GHashTable *ref_hash;
        MonoAotCompile *acfg;
        gboolean *emitted;
 
-       printf ("Mono AOT compiler - compiling assembly %s\n", image->name);
+       printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
 
        i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
        tmpfp = fdopen (i, "w+");
@@ -1027,10 +1130,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
                //printf ("START:           %s\n", mono_method_full_name (method, TRUE));
                //mono_compile_method (method);
 
-               cfg = mini_method_compile (method, opts, mono_root_domain, 0);
+               cfg = mini_method_compile (method, opts, mono_root_domain, FALSE, 0);
                g_assert (cfg);
 
                if (cfg->disable_aot) {
+                       printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
                        ocount++;
                        continue;
                }
@@ -1050,13 +1154,20 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
                        continue;
                }
 
+               /* remoting-invoke-with-check wrappers are very common */
+               for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
+                       if ((patch_info->type == MONO_PATCH_INFO_METHOD) &&
+                               ((patch_info->data.method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
+                               patch_info->type = MONO_PATCH_INFO_WRAPPER;
+               }
+
                skip = FALSE;
                for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                        if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
                             patch_info->type == MONO_PATCH_INFO_METHODCONST) &&
                            patch_info->data.method->wrapper_type) {
                                /* unable to handle this */
-                               //printf ("Skip (wrapper call):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
+                               //printf ("Skip (wrapper call):   %s %d -> %s\n", mono_method_full_name (method, TRUE), patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
                                skip = TRUE;    
                                break;
                        }
@@ -1072,7 +1183,6 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
                emitted [i] = TRUE;
                emit_method (acfg, cfg);
 
-               g_free (mname);
                mono_destroy_compile (cfg);
 
                ccount++;
@@ -1151,11 +1261,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts)
        system (com);
        g_free (com);*/
 
-       printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, (ccount*100)/mcount);
-       printf ("%d methods contain absolute addresses (%d%%)\n", abscount, (abscount*100)/mcount);
-       printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, (wrappercount*100)/mcount);
-       printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, (lmfcount*100)/mcount);
-       printf ("%d methods have other problems (%d%%)\n", ocount, (ocount*100)/mcount);
+       printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
+       printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
+       printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
+       printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
+       printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
        unlink (tmpfname);
 
        return 0;