2008-08-19 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-compiler.c
index 91588e83ef5e1524dd85e6602e707b262b9ad922..89378abe3ce25e65265917883e33a153c8b2045a 100644 (file)
 #define SHARED_EXT ".so"
 #endif
 
-#if defined(sparc) || defined(__ppc__)
+#if defined(sparc) || defined(__ppc__) || defined(__MACH__)
 #define AS_STRING_DIRECTIVE ".asciz"
 #else
 /* GNU as */
 #define AS_STRING_DIRECTIVE ".string"
 #endif
 
+
+// __MACH__
+// .byte generates 1 byte per expression.
+// .short generates 2 bytes per expression.
+// .long generates 4 bytes per expression.
+// .quad generates 8 bytes per expression.
+
 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
 
@@ -83,6 +90,8 @@ typedef struct MonoAotOptions {
        gboolean metadata_only;
        gboolean bind_to_runtime_version;
        gboolean full_aot;
+       gboolean no_dlsym;
+       gboolean static_link;
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
@@ -123,7 +132,6 @@ typedef struct MonoAotCompile {
        GHashTable *method_indexes;
        MonoCompile **cfgs;
        GHashTable *patch_to_plt_offset;
-       GHashTable **patch_to_plt_offset_wrapper;
        GHashTable *plt_offset_to_patch;
        GHashTable *patch_to_shared_got_offset;
        GPtrArray *shared_patches;
@@ -131,6 +139,7 @@ typedef struct MonoAotCompile {
        GHashTable *method_to_cfg;
        GHashTable *token_info_hash;
        GPtrArray *image_table;
+       GPtrArray *globals;
        GList *method_order;
        /* Number of trampolines emitted into the AOT file */
        guint32 num_aot_trampolines;
@@ -144,6 +153,7 @@ typedef struct MonoAotCompile {
        MonoMemPool *mempool;
        MonoAotStats stats;
        int method_index;
+       char *static_linking_symbol;
 #ifdef USE_BIN_WRITER
        BinSymbol *symbols;
        BinSection *sections;
@@ -199,6 +209,9 @@ get_patch_name (int info)
 
 #endif
 
+static void
+emit_global (MonoAotCompile *acfg, const char *name, gboolean func);
+
 static gboolean 
 is_got_patch (MonoJumpInfoType patch_type)
 {
@@ -287,7 +300,7 @@ emit_section_change (MonoAotCompile *acfg, const char *section_name, int subsect
 }
 
 static void
-emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
+emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
 {
        BinSymbol *symbol = g_new0 (BinSymbol, 1);
        symbol->name = g_strdup (name);
@@ -375,6 +388,10 @@ static void
 emit_pointer (MonoAotCompile *acfg, const char *target)
 {
        BinReloc *reloc;
+
+       if (!target)
+               // FIXME:
+               g_assert_not_reached ();
        emit_alignment (acfg, sizeof (gpointer));
        reloc = g_new0 (BinReloc, 1);
        reloc->val1 = g_strdup (target);
@@ -1273,12 +1290,12 @@ emit_section_change (MonoAotCompile *acfg, const char *section_name, int subsect
        emit_unset_mode (acfg);
 #if defined(PLATFORM_WIN32)
        fprintf (acfg->fp, ".section %s\n", section_name);
+#elif defined(__MACH__)
+       /* This needs to be made more precise on mach. */
+       fprintf (acfg->fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
 #elif defined(sparc) || defined(__arm__)
        /* For solaris as, GNU as should accept the same */
        fprintf (acfg->fp, ".section \"%s\"\n", section_name);
-#elif defined(__ppc__) && defined(__MACH__)
-       /* This needs to be made more precise on mach. */
-       fprintf (acfg->fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
 #else
        fprintf (acfg->fp, "%s %d\n", section_name, subsection_index);
 #endif
@@ -1295,19 +1312,21 @@ emit_symbol_type (MonoAotCompile *acfg, const char *name, gboolean func)
                stype = "object";
 
        emit_unset_mode (acfg);
-#if defined(sparc) || defined(__arm__)
+#if defined(__MACH__)
+
+#elif defined(sparc) || defined(__arm__)
        fprintf (acfg->fp, "\t.type %s,#%s\n", name, stype);
 #elif defined(PLATFORM_WIN32)
 
-#elif !(defined(__ppc__) && defined(__MACH__))
-       fprintf (acfg->fp, "\t.type %s,@%s\n", name, stype);
 #elif defined(__x86_64__) || defined(__i386__)
        fprintf (acfg->fp, "\t.type %s,@%s\n", name, stype);
+#else
+       fprintf (acfg->fp, "\t.type %s,@%s\n", name, stype);
 #endif
 }
 
 static void
-emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
+emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
 {
        emit_unset_mode (acfg);
 #if  (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
@@ -1383,11 +1402,11 @@ emit_pointer (MonoAotCompile *acfg, const char *target)
        emit_unset_mode (acfg);
        emit_alignment (acfg, sizeof (gpointer));
 #if defined(__x86_64__)
-       fprintf (acfg->fp, "\t.quad %s\n", target);
+       fprintf (acfg->fp, "\t.quad %s\n", target ? target : "0");
 #elif defined(sparc) && SIZEOF_VOID_P == 8
-       fprintf (acfg->fp, "\t.xword %s\n", target);
+       fprintf (acfg->fp, "\t.xword %s\n", target ? target : "0");
 #else
-       fprintf (acfg->fp, "\t.long %s\n", target);
+       fprintf (acfg->fp, "\t.long %s\n", target ? target : "0");
 #endif
 }
 
@@ -1416,7 +1435,9 @@ emit_int16 (MonoAotCompile *acfg, int value)
                acfg->col_count = 0;
        }
        if ((acfg->col_count++ % 8) == 0)
-#if defined(__arm__)
+#if defined(__MACH__)
+               fprintf (acfg->fp, "\n\t.short ");
+#elif defined(__arm__)
                /* FIXME: Use .hword on other archs as well */
                fprintf (acfg->fp, "\n\t.hword ");
 #else
@@ -1464,7 +1485,11 @@ static void
 emit_zero_bytes (MonoAotCompile *acfg, int num)
 {
        emit_unset_mode (acfg);
+#if defined(__MACH__)
+       fprintf (acfg->fp, "\t.space %d\n", num);
+#else
        fprintf (acfg->fp, "\t.skip %d\n", num);
+#endif
 }
 
 static int
@@ -1482,15 +1507,32 @@ emit_writeout (MonoAotCompile *acfg)
 #else
 #define AS_OPTIONS ""
 #endif
-       command = g_strdup_printf ("as %s %s -o %s.o", AS_OPTIONS, acfg->tmpfname, acfg->tmpfname);
+
+       if (acfg->aot_opts.static_link) {
+               if (acfg->aot_opts.outfile)
+                       objfile = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+               else
+                       objfile = g_strdup_printf ("%s.o", acfg->image->name);
+       } else {
+               objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
+       }
+       command = g_strdup_printf ("as %s %s -o %s", AS_OPTIONS, acfg->tmpfname, objfile);
        printf ("Executing the native assembler: %s\n", command);
        if (system (command) != 0) {
                g_free (command);
+               g_free (objfile);
                return 1;
        }
 
        g_free (command);
 
+       if (acfg->aot_opts.static_link) {
+               printf ("Output file: '%s'.\n", objfile);
+               printf ("Linking symbol: '%s'.\n", acfg->static_linking_symbol);
+               g_free (objfile);
+               return 0;
+       }
+
        if (acfg->aot_opts.outfile)
                outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
        else
@@ -1505,20 +1547,26 @@ emit_writeout (MonoAotCompile *acfg)
 #elif defined(PLATFORM_WIN32)
        command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, acfg->tmpfname);
 #else
-       command = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, acfg->tmpfname);
+       if (acfg->aot_opts.no_dlsym) {
+               /* 
+                * Need to link using gcc so our ctor function gets called.
+                */
+               command = g_strdup_printf ("gcc -shared -o %s %s.o", outfile_name, acfg->tmpfname);
+       } else {
+               command = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, acfg->tmpfname);
+       }
 #endif
        printf ("Executing the native linker: %s\n", command);
        if (system (command) != 0) {
                g_free (tmp_outfile_name);
                g_free (outfile_name);
                g_free (command);
+               g_free (objfile);
                return 1;
        }
 
        g_free (command);
-       objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
        unlink (objfile);
-       g_free (objfile);
        /*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, SHARED_EXT);
        printf ("Stripping the binary: %s\n", com);
        system (com);
@@ -1528,6 +1576,7 @@ emit_writeout (MonoAotCompile *acfg)
 
        g_free (tmp_outfile_name);
        g_free (outfile_name);
+       g_free (objfile);
 
        if (acfg->aot_opts.save_temps)
                printf ("Retained input file.\n");
@@ -1539,6 +1588,16 @@ emit_writeout (MonoAotCompile *acfg)
 
 #endif /* ASM_WRITER */
 
+static void
+emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
+{
+       if (acfg->aot_opts.no_dlsym) {
+               g_ptr_array_add (acfg->globals, g_strdup (name));
+       } else {
+               emit_global_inner (acfg, name, func);
+       }
+}
+
 static void
 emit_byte (MonoAotCompile *acfg, guint8 val)
 {
@@ -1631,9 +1690,20 @@ find_typespec_for_class (MonoAotCompile *acfg, MonoClass *klass)
                return 0;
 }
 
+static void
+encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf);
+
+/*
+ * encode_klass_ref:
+ *
+ *   Encode a reference to KLASS. We use our home-grown encoding instead of the
+ * standard metadata encoding.
+ */
 static void
 encode_klass_ref (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
 {
+       guint8 *p = buf;
+
        if (klass->generic_class) {
                guint32 token;
                g_assert (klass->type_token);
@@ -1641,8 +1711,8 @@ encode_klass_ref (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 **
                /* Find a typespec for a class if possible */
                token = find_typespec_for_class (acfg, klass);
                if (token) {
-                       encode_value (token, buf, &buf);
-                       encode_value (get_image_index (acfg, acfg->image), buf, &buf);
+                       encode_value (token, p, &p);
+                       encode_value (get_image_index (acfg, acfg->image), p, &p);
                } else {
                        MonoClass *gclass = klass->generic_class->container_class;
                        MonoGenericInst *inst = klass->generic_class->context.class_inst;
@@ -1650,36 +1720,53 @@ encode_klass_ref (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 **
 
                        /* Encode it ourselves */
                        /* Marker */
-                       encode_value (MONO_TOKEN_TYPE_SPEC, buf, &buf);
-                       encode_klass_ref (acfg, gclass, buf, &buf);
-                       encode_value (inst->type_argc, buf, &buf);
+                       encode_value (MONO_TOKEN_TYPE_SPEC, p, &p);
+                       encode_value (MONO_TYPE_GENERICINST, p, &p);
+                       encode_klass_ref (acfg, gclass, p, &p);
+                       encode_value (inst->type_argc, p, &p);
                        for (i = 0; i < inst->type_argc; ++i)
-                               encode_klass_ref (acfg, mono_class_from_mono_type (inst->type_argv [i]), buf, &buf);
+                               encode_klass_ref (acfg, mono_class_from_mono_type (inst->type_argv [i]), p, &p);
                }
        } else if (klass->type_token) {
                g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
-               encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
-               encode_value (get_image_index (acfg, klass->image), buf, &buf);
+               encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, p, &p);
+               encode_value (get_image_index (acfg, klass->image), p, &p);
+       } else if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR)) {
+               MonoGenericParam *param = klass->byval_arg.data.generic_param;
+
+               /* Marker */
+               encode_value (MONO_TOKEN_TYPE_SPEC, p, &p);
+               encode_value (klass->byval_arg.type, p, &p);
+
+               encode_value (param->num, p, &p);
+               
+               g_assert (param->owner);
+               encode_value (param->owner->is_method, p, &p);
+               if (param->owner->is_method)
+                       encode_method_ref (acfg, param->owner->owner.method, p, &p);
+               else
+                       encode_klass_ref (acfg, param->owner->owner.klass, p, &p);
        } else {
                /* Array class */
                g_assert (klass->rank > 0);
-               encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
-               encode_value (get_image_index (acfg, klass->image), buf, &buf);
-               encode_value (klass->rank, buf, &buf);
-               encode_klass_ref (acfg, klass->element_class, buf, &buf);
+               encode_value (MONO_TOKEN_TYPE_DEF, p, &p);
+               encode_value (get_image_index (acfg, klass->image), p, &p);
+               encode_value (klass->rank, p, &p);
+               encode_klass_ref (acfg, klass->element_class, p, &p);
        }
-       *endbuf = buf;
+       *endbuf = p;
 }
 
 static void
 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, guint8 *buf, guint8 **endbuf)
 {
        guint32 token = mono_get_field_token (field);
+       guint8 *p = buf;
 
-       encode_klass_ref (cfg, field->parent, buf, &buf);
+       encode_klass_ref (cfg, field->parent, p, &p);
        g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
-       encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
-       *endbuf = buf;
+       encode_value (token - MONO_TOKEN_FIELD_DEF, p, &p);
+       *endbuf = p;
 }
 
 #if 0
@@ -1703,14 +1790,17 @@ find_methodspec_for_method (MonoAotCompile *acfg, MonoMethod *method)
 }
 #endif
 
+#define MAX_IMAGE_INDEX 250
+
 static void
 encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf)
 {
        guint32 image_index = get_image_index (acfg, method->klass->image);
        guint32 token = method->token;
        MonoJumpInfoToken *ji;
+       guint8 *p = buf;
 
-       g_assert (image_index < 255);
+       g_assert (image_index < MAX_IMAGE_INDEX);
 
        if (mono_method_signature (method)->is_inflated) {
                /* 
@@ -1725,33 +1815,58 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                */
                /* Obtain the token from information recorded by the JIT */
                ji = g_hash_table_lookup (acfg->token_info_hash, method);
-               g_assert (ji);
-               image_index = get_image_index (acfg, ji->image);
-               g_assert (image_index < 255);
-               token = ji->token;
+               if (!ji) {
+                       MonoMethod *declaring;
 
-               /* Marker */
-               encode_value ((255 << 24), buf, &buf);
-               encode_value (image_index, buf, &buf);
-               encode_value (token, buf, &buf);
+                       g_assert (method->is_inflated);
+                       declaring = ((MonoMethodInflated*)method)->declaring;
+
+                       /* 
+                        * This might be a non-generic method of a generic instance, which doesn't
+                        * have a token since the reference is generated by the JIT like 
+                        * Nullable:Box/Unbox.
+                        */
+
+                       /* Marker */
+                       encode_value ((254 << 24), p, &p);
+                       /* Encode the klass */
+                       encode_klass_ref (acfg, method->klass, p, &p);
+                       /* Encode the method */
+                       image_index = get_image_index (acfg, method->klass->image);
+                       g_assert (image_index < MAX_IMAGE_INDEX);
+                       g_assert (declaring->token);
+                       token = declaring->token;
+                       g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
+                       encode_value (image_index, p, &p);
+                       encode_value (token, p, &p);
+               } else {
+                       image_index = get_image_index (acfg, ji->image);
+                       g_assert (image_index < MAX_IMAGE_INDEX);
+                       token = ji->token;
+
+                       /* Marker */
+                       encode_value ((255 << 24), p, &p);
+                       encode_value (image_index, p, &p);
+                       encode_value (token, p, &p);
+               }
        } else if (token == 0) {
                /* This might be a method of a constructed type like int[,].Set */
                /* Obtain the token from information recorded by the JIT */
                ji = g_hash_table_lookup (acfg->token_info_hash, method);
                g_assert (ji);
                image_index = get_image_index (acfg, ji->image);
-               g_assert (image_index < 255);
+               g_assert (image_index < MAX_IMAGE_INDEX);
                token = ji->token;
 
                /* Marker */
-               encode_value ((255 << 24), buf, &buf);
-               encode_value (image_index, buf, &buf);
-               encode_value (token, buf, &buf);
+               encode_value ((255 << 24), p, &p);
+               encode_value (image_index, p, &p);
+               encode_value (token, p, &p);
        } else {
                g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
-               encode_value ((image_index << 24) | mono_metadata_token_index (token), buf, &buf);
+               encode_value ((image_index << 24) | mono_metadata_token_index (token), p, &p);
        }
-       *endbuf = buf;
+       *endbuf = p;
 }
 
 static gint
@@ -1771,70 +1886,78 @@ compare_patches (gconstpointer a, gconstpointer b)
                return 0;
 }
 
-static int
-get_plt_index (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
+/*
+ * is_plt_patch:
+ *
+ *   Return whenever PATCH_INFO refers to a direct call, and thus requires a
+ * PLT entry.
+ */
+static inline gboolean
+is_plt_patch (MonoJumpInfo *patch_info)
 {
-       int res = -1;
-       int idx;
-       GHashTable *hash = acfg->patch_to_plt_offset;
-
        switch (patch_info->type) {
        case MONO_PATCH_INFO_METHOD:
        case MONO_PATCH_INFO_WRAPPER:
        case MONO_PATCH_INFO_INTERNAL_METHOD:
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
-       case MONO_PATCH_INFO_CLASS_INIT: {
-               MonoJumpInfo *new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
-               gpointer patch_id = NULL;
+       case MONO_PATCH_INFO_CLASS_INIT:
+       case MONO_PATCH_INFO_RGCTX_FETCH:
+       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
+               return TRUE;
+       default:
+               return FALSE;
+       }
+}
 
-               /* First check for an existing patch */
-               switch (patch_info->type) {
-               case MONO_PATCH_INFO_METHOD:
-                       patch_id = patch_info->data.method;
-                       break;
-               case MONO_PATCH_INFO_INTERNAL_METHOD:
-                       patch_id = (gpointer)patch_info->data.name;
-                       break;
-               case MONO_PATCH_INFO_CLASS_INIT:
-                       patch_id = patch_info->data.klass;
-                       break;
-               case MONO_PATCH_INFO_WRAPPER:
-                       hash = acfg->patch_to_plt_offset_wrapper [patch_info->data.method->wrapper_type];
-                       if (!hash) {
-                               acfg->patch_to_plt_offset_wrapper [patch_info->data.method->wrapper_type] = g_hash_table_new (NULL, NULL);
-                               hash = acfg->patch_to_plt_offset_wrapper [patch_info->data.method->wrapper_type];
-                       }
-                       patch_id = patch_info->data.method;
-                       break;
-               case MONO_PATCH_INFO_JIT_ICALL_ADDR:
-                       /* Each addr should only occur once */
-                       break;
-               default:
-                       g_assert_not_reached ();
-               }
+/*
+ * is_shared_got_patch:
+ *
+ *   Return whenever PATCH_INFO refers to a patch which needs a shared GOT
+ * entry.
+ * Keep it in sync with the version in aot-runtime.c.
+ */
+static inline gboolean
+is_shared_got_patch (MonoJumpInfo *patch_info)
+{
+       switch (patch_info->type) {
+       case MONO_PATCH_INFO_VTABLE:
+       case MONO_PATCH_INFO_CLASS:
+       case MONO_PATCH_INFO_IID:
+       case MONO_PATCH_INFO_ADJUSTED_IID:
+       case MONO_PATCH_INFO_FIELD:
+       case MONO_PATCH_INFO_SFLDA:
+       case MONO_PATCH_INFO_DECLSEC:
+       case MONO_PATCH_INFO_LDTOKEN:
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+       case MONO_PATCH_INFO_RVA:
+       case MONO_PATCH_INFO_METHODCONST:
+               return TRUE;
+       default:
+               return FALSE;
+       }
+}
 
-               if (patch_id) {
-                       idx = GPOINTER_TO_UINT (g_hash_table_lookup (hash, patch_id));
-                       if (idx)
-                               res = idx;
-                       else
-                               g_hash_table_insert (hash, patch_id, GUINT_TO_POINTER (acfg->plt_offset));
-               }
+static int
+get_plt_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
+{
+       int res = -1;
+
+       if (is_plt_patch (patch_info)) {
+               int idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info));
+
+               if (idx) {
+                       res = idx;
+               } else {
+                       MonoJumpInfo *new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
 
-               if (res == -1) {
                        res = acfg->plt_offset;
-                       g_hash_table_insert (acfg->plt_offset_to_patch, GUINT_TO_POINTER (acfg->plt_offset), new_ji);
+                       g_hash_table_insert (acfg->plt_offset_to_patch, GUINT_TO_POINTER (res), new_ji);
+                       g_hash_table_insert (acfg->patch_to_plt_offset, new_ji, GUINT_TO_POINTER (res));
                        acfg->plt_offset ++;
                }
-
-               /* Nullify the patch */
-               patch_info->type = MONO_PATCH_INFO_NONE;
-
-               return res;
-       }
-       default:
-               return -1;
        }
+
+       return res;
 }
 
 /**
@@ -2022,21 +2145,23 @@ add_wrappers (MonoAotCompile *acfg)
                        add_method (acfg, mono_marshal_get_runtime_invoke (method));
        }
 
-       /* JIT icall wrappers */
-       /* FIXME: locking */
-       g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper, acfg);
+       if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
+               /* JIT icall wrappers */
+               /* FIXME: locking */
+               g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper, acfg);
+
+               /* Managed Allocators */
+               nallocators = mono_gc_get_managed_allocator_types ();
+               for (i = 0; i < nallocators; ++i) {
+                       m = mono_gc_get_managed_allocator_by_type (i);
+                       if (m)
+                               add_method (acfg, m);
+               }
 
-       /* Managed Allocators */
-       nallocators = mono_gc_get_managed_allocator_types ();
-       for (i = 0; i < nallocators; ++i) {
-               m = mono_gc_get_managed_allocator_by_type (i);
-               if (m)
-                       add_method (acfg, m);
+               /* stelemref */
+               add_method (acfg, mono_marshal_get_stelemref ());
        }
 
-       /* stelemref */
-       add_method (acfg, mono_marshal_get_stelemref ());
-
        /* remoting-invoke wrappers */
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
                MonoMethod *method;
@@ -2105,7 +2230,6 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                break;
                        }
                        default: {
-                               int plt_index;
                                char *direct_call_target;
 
                                if (!is_got_patch (patch_info->type))
@@ -2132,10 +2256,13 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                }
 
                                if (!got_only && !direct_call_target) {
-                                       plt_index = get_plt_index (acfg, patch_info);
-                                       if (plt_index != -1) {
+                                       int plt_offset = get_plt_offset (acfg, patch_info);
+                                       if (plt_offset != -1) {
                                                /* This patch has a PLT entry, so we must emit a call to the PLT entry */
-                                               direct_call_target = g_strdup_printf (".Lp_%d", plt_index);
+                                               direct_call_target = g_strdup_printf (".Lp_%d", plt_offset);
+               
+                                               /* Nullify the patch */
+                                               patch_info->type = MONO_PATCH_INFO_NONE;
                                        }
                                }
 
@@ -2156,6 +2283,8 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                        i += 4 - 1;
 #endif
 #endif
+
+                                       g_free (direct_call_target);
                                } else {
                                        got_slot = get_got_offset (acfg, patch_info);
 
@@ -2193,7 +2322,7 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        int func_alignment = 16;
        MonoMethodHeader *header;
 
-       method = cfg->method;
+       method = cfg->orig_method;
        code = cfg->native_code;
        header = mono_method_get_header (method);
 
@@ -2209,6 +2338,7 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
 
        if (cfg->verbose_level > 0)
                g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
+       g_free (symbol);
 
        acfg->stats.code_size += cfg->code_len;
 
@@ -2222,11 +2352,10 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
 /**
  * encode_patch:
  *
- *  Encode PATCH_INFO into its disk representation. If SHARED is true, encode some types
- * of patches by allocating a GOT entry for them, and encode the GOT offset instead.
+ *  Encode PATCH_INFO into its disk representation.
  */
 static void
-encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint8 **endbuf, gboolean shared)
+encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint8 **endbuf)
 {
        guint8 *p = buf;
 
@@ -2252,6 +2381,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        case MONO_PATCH_INFO_METHOD:
        case MONO_PATCH_INFO_METHOD_JUMP:
        case MONO_PATCH_INFO_ICALL_ADDR:
+       case MONO_PATCH_INFO_METHOD_RGCTX:
                encode_method_ref (acfg, patch_info->data.method, p, &p);
                break;
        case MONO_PATCH_INFO_INTERNAL_METHOD:
@@ -2277,13 +2407,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        case MONO_PATCH_INFO_DECLSEC:
        case MONO_PATCH_INFO_LDTOKEN:
        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
-               if (shared) {
-                       guint32 offset = get_got_offset (acfg, patch_info);
-                       encode_value (offset, p, &p);
-               } else {
-                       encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
-                       encode_value (patch_info->data.token->token, p, &p);
-               }
+               encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
+               encode_value (patch_info->data.token->token, p, &p);
                break;
        case MONO_PATCH_INFO_EXC_NAME: {
                MonoClass *ex_class;
@@ -2306,12 +2431,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        case MONO_PATCH_INFO_CLASS:
        case MONO_PATCH_INFO_IID:
        case MONO_PATCH_INFO_ADJUSTED_IID:
-               if (shared) {
-                       guint32 offset = get_got_offset (acfg, patch_info);
-                       encode_value (offset, p, &p);
-               } else {
-                       encode_klass_ref (acfg, patch_info->data.klass, p, &p);
-               }
+               encode_klass_ref (acfg, patch_info->data.klass, p, &p);
                break;
        case MONO_PATCH_INFO_CLASS_INIT:
        case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
@@ -2319,12 +2439,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                break;
        case MONO_PATCH_INFO_FIELD:
        case MONO_PATCH_INFO_SFLDA:
-               if (shared) {
-                       guint32 offset = get_got_offset (acfg, patch_info);
-                       encode_value (offset, p, &p);
-               } else {
-                       encode_field_info (acfg, patch_info->data.field, p, &p);
-               }
+               encode_field_info (acfg, patch_info->data.field, p, &p);
                break;
        case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
                break;
@@ -2372,6 +2487,18 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                        g_assert_not_reached ();
                }
                break;
+       case MONO_PATCH_INFO_RGCTX_FETCH: {
+               MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
+
+               encode_method_ref (acfg, entry->method, p, &p);
+               encode_value (entry->in_mrgctx, p, &p);
+               encode_value (entry->info_type, p, &p);
+               encode_value (entry->data->type, p, &p);
+               encode_patch (acfg, entry->data, p, &p);
+               break;
+       }
+       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
+               break;
        default:
                g_warning ("unable to handle jump info %d", patch_info->type);
                g_assert_not_reached ();
@@ -2417,7 +2544,12 @@ encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, int
        for (pindex = 0; pindex < patches->len; ++pindex) {
                patch_info = g_ptr_array_index (patches, pindex);
 
-               encode_patch (acfg, patch_info, p, &p, TRUE);
+               if (is_shared_got_patch (patch_info)) {
+                       guint32 offset = get_got_offset (acfg, patch_info);
+                       encode_value (offset, p, &p);
+               } else {
+                       encode_patch (acfg, patch_info, p, &p);
+               }
        }
 
        *endbuf = p;
@@ -2438,7 +2570,7 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        guint8 *p, *buf;
        guint32 first_got_offset;
 
-       method = cfg->method;
+       method = cfg->orig_method;
        code = cfg->native_code;
        header = mono_method_get_header (method);
 
@@ -2496,11 +2628,7 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
                        continue;
                }
 
-               if ((patch_info->type == MONO_PATCH_INFO_METHOD) ||
-                       (patch_info->type == MONO_PATCH_INFO_INTERNAL_METHOD) ||
-                       (patch_info->type == MONO_PATCH_INFO_JIT_ICALL_ADDR) ||
-                       (patch_info->type == MONO_PATCH_INFO_WRAPPER) ||
-                       (patch_info->type == MONO_PATCH_INFO_CLASS_INIT)) {
+               if (is_plt_patch (patch_info)) {
                        /* Calls are made through the PLT */
                        patch_info->type = MONO_PATCH_INFO_NONE;
                        continue;
@@ -2519,12 +2647,11 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        /* Emit method info */
 
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        g_assert (p - buf < buf_size);
        emit_bytes (acfg, buf, p - buf);
        g_free (buf);
-
-       g_free (symbol);
 }
 
 static void
@@ -2538,7 +2665,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        MonoMethodHeader *header;
        guint8 *p, *buf, *debug_info;
 
-       method = cfg->method;
+       method = cfg->orig_method;
        code = cfg->native_code;
        header = mono_method_get_header (method);
 
@@ -2587,12 +2714,11 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        /* Emit info */
 
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        g_assert (p - buf < buf_size);
        emit_bytes (acfg, buf, p - buf);
        g_free (buf);
-
-       g_free (symbol);
 }
 
 static void
@@ -2601,7 +2727,7 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
        MonoClass *klass = mono_class_get (acfg->image, token);
        guint8 *p, *buf;
        int i, buf_size;
-       char *label;
+       char *symbol;
        gboolean no_special_static, cant_encode;
 
        buf_size = 10240 + (klass->vtable_size * 16);
@@ -2658,8 +2784,9 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
        acfg->stats.class_info_size += p - buf;
 
        /* Emit the info */
-       label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
-       emit_label (acfg, label);
+       symbol = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
+       emit_label (acfg, symbol);
+       g_free (symbol);
 
        g_assert (p - buf < buf_size);
        emit_bytes (acfg, buf, p - buf);
@@ -2696,7 +2823,7 @@ emit_plt (MonoAotCompile *acfg)
 
                plt_info_offsets [i] = p - buf;
                encode_value (patch_info->type, p, &p);
-               encode_patch (acfg, patch_info, p, &p, FALSE);
+               encode_patch (acfg, patch_info, p, &p);
        }
 
        emit_line (acfg);
@@ -2707,6 +2834,7 @@ emit_plt (MonoAotCompile *acfg)
        emit_global (acfg, symbol, TRUE);
        emit_alignment (acfg, PAGESIZE);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
 #if defined(USE_BIN_WRITER) && defined(__arm__)
        /* FIXME: */
@@ -2729,11 +2857,10 @@ emit_plt (MonoAotCompile *acfg)
                        /* It is filled up during loading by the AOT loader. */
                        emit_zero_bytes (acfg, 16);
                } else {
-                       /* Need to make sure this is 5 bytes long */
+                       /* Need to make sure this is 9 bytes long */
                        emit_byte (acfg, '\xe9');
-                       label = g_strdup_printf (".Lpd_%d", i);
-                       emit_symbol_diff (acfg, label, ".", -4);
-                       g_free (label);
+                       emit_symbol_diff (acfg, "plt", ".", -4);
+                       emit_int32 (acfg, plt_info_offsets [i]);
                }
 #elif defined(__x86_64__)
                /*
@@ -2742,24 +2869,16 @@ emit_plt (MonoAotCompile *acfg)
                 * point to .Lpd entries. ELF stores these in the GOT too, but we don't, since
                 * methods with GOT entries can't be called directly.
                 * We also emit the default PLT code here since the PLT code will not be patched.
-                * An x86_64 plt entry is 16 bytes long, init_plt () depends on this.
+                * An x86_64 plt entry is 10 bytes long, init_plt () depends on this.
                 */
                /* jmpq *<offset>(%rip) */
                emit_byte (acfg, '\xff');
                emit_byte (acfg, '\x25');
                emit_symbol_diff (acfg, "plt_jump_table", ".", (i * sizeof (gpointer)) -4);
-               /* mov <plt info offset>, %eax */
-               emit_byte (acfg, '\xb8');
+               /* Used by mono_aot_get_plt_info_offset */
                emit_int32 (acfg, plt_info_offsets [i]);
-               /* jmp .Lp_0 */
-               emit_byte (acfg, '\xe9');
-               emit_symbol_diff (acfg, ".Lp_0", ".", -4);
 #elif defined(__arm__)
-               /* 
-                * Emit an indirect call since branch displacements are limited to 24 bits on 
-                * ARM. Put the jump table entries inline since offsets are even smaller on
-                * ARM.
-                * FIXME:
+               /* FIXME:
                 * - optimize OP_AOTCONST implementation
                 * - optimize the PLT entries
                 * - optimize SWITCH AOT implementation
@@ -2771,55 +2890,29 @@ emit_plt (MonoAotCompile *acfg)
                fprintf (acfg->fp, "\tldr pc, [ip, #0]\n");
                emit_symbol_diff (acfg, "plt_jump_table", ".", 0);
                /* Used by mono_aot_get_plt_info_offset */
+    #if defined(__MACH__)
+               fprintf (acfg->fp, "\n\t.long %d\n", plt_info_offsets [i]);
+    #else
                fprintf (acfg->fp, "\n\t.word %d\n", plt_info_offsets [i]);
+    #endif
+
 #else
                g_assert_not_reached ();
 #endif
        }
 
+       g_free (plt_info_offsets);
+
        symbol = g_strdup_printf ("plt_end");
        emit_global (acfg, symbol, TRUE);
        emit_label (acfg, symbol);
-
-       /* 
-        * Emit the default targets for the PLT entries separately since these will not
-        * be modified at runtime.
-        */
-       for (i = 1; i < acfg->plt_offset; ++i) {
-               char *label;
-
-               label = g_strdup_printf (".Lpd_%d", i);
-               emit_label (acfg, label);
-               g_free (label);
-
-               /* Put the offset into the register expected by mono_aot_plt_trampoline */
-#if defined(__i386__)
-               /* movl $const, %eax */
-               emit_byte (acfg, '\xb8');
-               emit_int32 (acfg, plt_info_offsets [i]);
-               /* jmp .Lp_0 */
-               emit_byte (acfg, '\xe9');
-               emit_symbol_diff (acfg, ".Lp_0", ".", -4);
-#elif defined(__x86_64__)
-               /* Emitted along with the PLT entries since they will not be patched */
-#elif defined(__arm__)
-               /* Emitted along with the PLT entries since they will not be patched */
-#if 0
-               /* This is 12 bytes long, init_plt () depends on this */
-               emit_unset_mode (acfg);
-               fprintf (acfg->fp, "\tldr ip, [pc, #0]\n");
-               fprintf (acfg->fp, "\tb .Lp_0\n");
-               fprintf (acfg->fp, "\t.word %d\n", plt_info_offsets [i]);
-#endif
-#else
-               g_assert_not_reached ();
-#endif
-       }
+       g_free (symbol);
 
        /* Emit PLT info */
        symbol = g_strdup_printf ("plt_info");
        emit_global (acfg, symbol, FALSE);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        g_assert (p - buf < buf_size);
        emit_bytes (acfg, buf, p - buf);
@@ -2831,6 +2924,7 @@ emit_plt (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
        emit_pointer (acfg, "plt_jump_table");
+       g_free (symbol);
 
        symbol = g_strdup_printf ("plt_jump_table_size");
        emit_section_change (acfg, ".data", 0);
@@ -2838,11 +2932,13 @@ emit_plt (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
        emit_symbol_diff (acfg, "plt_jump_table_end", "plt_jump_table", 0);
+       g_free (symbol);
 
        /* Don't make this a global so accesses don't need relocations */
        symbol = g_strdup_printf ("plt_jump_table");
        emit_section_change (acfg, ".bss", 0);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
 #if defined(__x86_64__) || defined(__arm__)
        emit_zero_bytes (acfg, (int)(acfg->plt_offset * sizeof (gpointer)));
@@ -2850,6 +2946,7 @@ emit_plt (MonoAotCompile *acfg)
 
        symbol = g_strdup_printf ("plt_jump_table_end");
        emit_label (acfg, symbol);
+       g_free (symbol);
 }
 
 static void
@@ -2929,7 +3026,7 @@ emit_trampolines (MonoAotCompile *acfg)
        
        g_assert (acfg->image->assembly);
 
-       /* Currently, we only most trampolines into the mscorlib AOT image. */
+       /* Currently, we only emit most trampolines into the mscorlib AOT image. */
        if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
                /*
@@ -3049,7 +3146,7 @@ emit_trampolines (MonoAotCompile *acfg)
                method = mono_get_method (acfg->image, token, NULL);
 
                cfg = g_hash_table_lookup (acfg->method_to_cfg, method);
-               if (!cfg || !cfg->method->klass->valuetype || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL))
+               if (!cfg || !cfg->orig_method->klass->valuetype || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL))
                        continue;
 
                symbol = g_strdup_printf ("unbox_trampoline_%d", i);
@@ -3058,14 +3155,14 @@ emit_trampolines (MonoAotCompile *acfg)
                emit_global (acfg, symbol, TRUE);
                emit_label (acfg, symbol);
 
-               call_target = g_strdup_printf (".Lm_%x", get_method_index (acfg, cfg->method));
+               call_target = g_strdup_printf (".Lm_%x", get_method_index (acfg, cfg->orig_method));
 
 #if defined(__x86_64__)
                {
                        guint8 buf [32];
                        int this_reg;
 
-                       this_reg = mono_arch_get_this_arg_reg (mono_method_signature (cfg->method), cfg->generic_sharing_context, NULL);
+                       this_reg = mono_arch_get_this_arg_reg (mono_method_signature (cfg->orig_method), cfg->generic_sharing_context, NULL);
                        code = buf;
                        amd64_alu_reg_imm (code, X86_ADD, this_reg, sizeof (MonoObject));
 
@@ -3081,7 +3178,7 @@ emit_trampolines (MonoAotCompile *acfg)
 
                        code = buf;
 
-                       if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->method)->ret))
+                       if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->orig_method)->ret))
                                this_pos = 1;
 
                        ARM_ADD_REG_IMM8 (code, this_pos, this_pos, sizeof (MonoObject));
@@ -3142,11 +3239,25 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->bind_to_runtime_version = TRUE;
                } else if (str_begins_with (arg, "full")) {
                        opts->full_aot = TRUE;
+                       /*
+                        * The no-dlsym option is only useful on the iphone, and even there,
+                        * do to other limitations of the dynamic linker, it doesn't seem to
+                        * work. So disable it for now so we don't have to support it.
+                        */
+                       /*
+               } else if (str_begins_with (arg, "no-dlsym")) {
+                       opts->no_dlsym = TRUE;
+                       */
+               } else if (str_begins_with (arg, "static")) {
+                       opts->static_link = TRUE;
+                       opts->no_dlsym = TRUE;
                } else {
                        fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
                        exit (1);
                }
        }
+
+       g_strfreev (args);
 }
 
 static void
@@ -3199,12 +3310,14 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
        //acfg->opts &= ~MONO_OPT_GSHARED;
 
        // FIXME: GSHARED is on by default
+#if 1
        if (TRUE || !(acfg->opts & MONO_OPT_GSHARED)) {
                if (method->is_generic || method->klass->generic_container) {
                        acfg->stats.genericcount ++;
                        return;
                }
        }
+#endif
 
        if (acfg->aot_opts.full_aot)
                mono_use_imt = FALSE;
@@ -3267,35 +3380,13 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                return;
        }
 
+       /* Convert method patches referring to wrapper methods to 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_JUMP) {
-                       /* 
-                        * FIXME: We can't handle this because mono_jit_compile_method_inner will try
-                        * to patch the AOT code when the target of the jump is compiled.
-                        */
-                       skip = TRUE;
-                       break;
-               }
-       }
-
-       if (skip) {
-               acfg->stats.ocount++;
-               mono_destroy_compile (cfg);
-               return;
-       }
-
-       /* some wrappers are very common */
-       for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
-               if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
-                       switch (patch_info->data.method->wrapper_type) {
-                       case MONO_WRAPPER_PROXY_ISINST:
-                               patch_info->type = MONO_PATCH_INFO_WRAPPER;
-                       }
-               }
-
-               if (patch_info->type == MONO_PATCH_INFO_METHOD) {
+               if ((patch_info->type == MONO_PATCH_INFO_METHODCONST) || (patch_info->type == MONO_PATCH_INFO_METHOD)) {
                        switch (patch_info->data.method->wrapper_type) {
+                       case MONO_WRAPPER_NONE:
+                               break;
                        case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
                        case MONO_WRAPPER_XDOMAIN_INVOKE:
                        case MONO_WRAPPER_STFLD:
@@ -3310,29 +3401,42 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                        case MONO_WRAPPER_REMOTING_INVOKE:
                                patch_info->type = MONO_PATCH_INFO_WRAPPER;
                                break;
+                       default:
+                               /* unable to handle this */
+                               //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;
                        }
                }
        }
 
+       if (skip) {
+               acfg->stats.wrappercount++;
+               mono_destroy_compile (cfg);
+               return;
+       }
+
        skip = FALSE;
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                switch (patch_info->type) {
                case MONO_PATCH_INFO_METHOD:
                case MONO_PATCH_INFO_METHODCONST:
-                       if (patch_info->data.method->wrapper_type) {
-                               /* unable to handle this */
-                               //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;
-                       }
                        if (!patch_info->data.method->token) {
                                /* The method is part of a constructed type like Int[,].Set (). */
                                if (!g_hash_table_lookup (acfg->token_info_hash, patch_info->data.method))
                                        skip = TRUE;
                        }
-                       if (patch_info->data.method->is_inflated && !g_hash_table_lookup (acfg->token_info_hash, patch_info->data.method))
-                               /* FIXME: Can't encode these */
-                               skip = TRUE;
+                       if (patch_info->data.method->is_inflated && !g_hash_table_lookup (acfg->token_info_hash, patch_info->data.method)) {
+                               /* 
+                                * encode_method_ref () can handle this method if it is not generic
+                                * and its class can be encoded.
+                                */
+                               if (!g_hash_table_lookup (acfg->token_info_hash, patch_info->data.method->klass) || mono_method_get_context (patch_info->data.method)->method_inst) {
+                                       /* FIXME: Can't encode these */
+                                       //printf ("Skip (can't encode):   %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;
                case MONO_PATCH_INFO_VTABLE:
                case MONO_PATCH_INFO_CLASS_INIT:
@@ -3350,7 +3454,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
        }
 
        if (skip) {
-               acfg->stats.wrappercount++;
+               acfg->stats.ocount++;
                mono_destroy_compile (cfg);
                return;
        }
@@ -3360,18 +3464,15 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                switch (patch_info->type) {
                case MONO_PATCH_INFO_GOT_OFFSET:
                case MONO_PATCH_INFO_NONE:
-               case MONO_PATCH_INFO_METHOD:
-               case MONO_PATCH_INFO_INTERNAL_METHOD:
-               case MONO_PATCH_INFO_JIT_ICALL_ADDR:
-               case MONO_PATCH_INFO_WRAPPER:
                        break;
                case MONO_PATCH_INFO_IMAGE:
-                       if (patch_info->data.image == acfg->image)
-                               /* Stored in GOT slot 0 */
-                               break;
-                       /* Fall through */
+                       /* The assembly is stored in GOT slot 0 */
+                       if (patch_info->data.image != acfg->image)
+                               cfg->has_got_slots = TRUE;
+                       break;
                default:
-                       cfg->has_got_slots = TRUE;
+                       if (!is_plt_patch (patch_info))
+                               cfg->has_got_slots = TRUE;
                        break;
                }
        }
@@ -3411,7 +3512,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
 
        acfg->cfgs [index] = cfg;
 
-       g_hash_table_insert (acfg->method_to_cfg, cfg->method, cfg);
+       g_hash_table_insert (acfg->method_to_cfg, cfg->orig_method, cfg);
 
        acfg->stats.ccount++;
 }
@@ -3430,13 +3531,16 @@ load_profile_files (MonoAotCompile *acfg)
        while (TRUE) {
                tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg->image->assembly_name, acfg->image->guid, file_index);
 
-               if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR))
+               if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) {
+                       g_free (tmp);
                        break;
+               }
 
                infile = fopen (tmp, "r");
                g_assert (infile);
 
                printf ("Using profile data file '%s'\n", tmp);
+               g_free (tmp);
 
                file_index ++;
 
@@ -3500,22 +3604,8 @@ alloc_got_slots (MonoAotCompile *acfg)
                        MonoCompile *cfg = acfg->cfgs [i];
 
                        for (ji = cfg->patch_info; ji; ji = ji->next) {
-                               switch (ji->type) {
-                               case MONO_PATCH_INFO_VTABLE:
-                               case MONO_PATCH_INFO_CLASS:
-                               case MONO_PATCH_INFO_IID:
-                               case MONO_PATCH_INFO_ADJUSTED_IID:
-                               case MONO_PATCH_INFO_FIELD:
-                               case MONO_PATCH_INFO_SFLDA:
-                               case MONO_PATCH_INFO_DECLSEC:
-                               case MONO_PATCH_INFO_LDTOKEN:
-                               case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
-                               case MONO_PATCH_INFO_RVA:
+                               if (is_shared_got_patch (ji))
                                        get_shared_got_offset (acfg, ji);
-                                       break;
-                               default:
-                                       break;
-                               }
                        }
                }
        }
@@ -3533,6 +3623,7 @@ emit_code (MonoAotCompile *acfg)
        emit_global (acfg, symbol, TRUE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        for (l = acfg->method_order; l != NULL; l = l->next) {
                i = GPOINTER_TO_UINT (l->data);
@@ -3546,17 +3637,20 @@ emit_code (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        symbol = g_strdup_printf ("method_offsets");
        emit_section_change (acfg, ".text", 1);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
                        symbol = g_strdup_printf (".Lm_%x", i);
                        emit_symbol_diff (acfg, symbol, "methods", 0);
+                       g_free (symbol);
                } else {
                        emit_int32 (acfg, 0xffffffff);
                }
@@ -3577,10 +3671,12 @@ emit_info (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        /* To reduce size of generated assembly code */
        symbol = g_strdup_printf ("mi");
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        for (l = acfg->method_order; l != NULL; l = l->next) {
                i = GPOINTER_TO_UINT (l->data);
@@ -3594,11 +3690,13 @@ emit_info (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
                        symbol = g_strdup_printf (".Lm_%x_p", i);
                        emit_symbol_diff (acfg, symbol, "mi", 0);
+                       g_free (symbol);
                } else {
                        emit_int32 (acfg, 0);
                }
@@ -3619,6 +3717,7 @@ emit_wrapper_info (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        if (!acfg->aot_opts.full_aot)
                return;
@@ -3626,13 +3725,13 @@ emit_wrapper_info (MonoAotCompile *acfg)
        for (i = 0; i < acfg->nmethods; ++i) {
                MonoCompile *cfg = acfg->cfgs [i];
 
-               if (!cfg || !cfg->method->wrapper_type)
+               if (!cfg || !cfg->orig_method->wrapper_type)
                        continue;
 
-               index = get_method_index (acfg, cfg->method);
+               index = get_method_index (acfg, cfg->orig_method);
 
                // FIXME: Optimize disk usage and lookup speed
-               name = mono_method_full_name (cfg->method, TRUE);
+               name = mono_method_full_name (cfg->orig_method, TRUE);
                emit_string (acfg, name);
                emit_alignment (acfg, 4);
                emit_int32 (acfg, index);
@@ -3655,6 +3754,7 @@ emit_method_order (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        /* First emit an index table */
        index = 0;
@@ -3688,6 +3788,7 @@ emit_method_order (MonoAotCompile *acfg)
        emit_section_change (acfg, ".text", 1);
        emit_global (acfg, symbol, FALSE);
        emit_label (acfg, symbol);
+       g_free (symbol);
 }
 
 static void
@@ -3701,10 +3802,12 @@ emit_exception_info (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        /* To reduce size of generated assembly */
        symbol = g_strdup_printf ("ex");
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i])
@@ -3716,11 +3819,13 @@ emit_exception_info (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
                        symbol = g_strdup_printf (".Le_%x_p", i);
                        emit_symbol_diff (acfg, symbol, "ex", 0);
+                       g_free (symbol);
                } else {
                        emit_int32 (acfg, 0);
                }
@@ -3739,6 +3844,7 @@ emit_class_info (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
                emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
@@ -3748,10 +3854,12 @@ emit_class_info (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
                symbol = g_strdup_printf (".LK_I_%x", i);
                emit_symbol_diff (acfg, symbol, "class_info", 0);
+               g_free (symbol);
        }
        emit_line (acfg);
 }
@@ -3810,6 +3918,7 @@ emit_class_name_table (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        /* FIXME: Optimize memory usage */
        g_assert (table_size < 65000);
@@ -3847,6 +3956,8 @@ emit_image_table (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
+
        emit_int32 (acfg, acfg->image_table->len);
        for (i = 0; i < acfg->image_table->len; i++) {
                MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
@@ -3897,7 +4008,7 @@ emit_got_info (MonoAotCompile *acfg)
 
                /* No need to encode the patch type */
                got_info_offsets [i] = p - buf;
-               encode_patch (acfg, ji, p, &p, FALSE);
+               encode_patch (acfg, ji, p, &p);
        }
 
        g_assert (p - buf <= buf_size);
@@ -3910,6 +4021,7 @@ emit_got_info (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        emit_bytes (acfg, buf, p - buf);
 
@@ -3919,6 +4031,7 @@ emit_got_info (MonoAotCompile *acfg)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        for (i = 0; i < acfg->shared_patches->len; ++i)
                emit_int32 (acfg, got_info_offsets [i]);
@@ -3938,6 +4051,7 @@ emit_got (MonoAotCompile *acfg)
        emit_label (acfg, symbol);
        if ((acfg->got_offset + acfg->num_trampoline_got_entries) > 0)
                emit_zero_bytes (acfg, (int)((acfg->got_offset + acfg->num_trampoline_got_entries) * sizeof (gpointer)));
+       g_free (symbol);
 
        symbol = g_strdup_printf ("got_addr");
        emit_section_change (acfg, ".data", 1);
@@ -3945,6 +4059,7 @@ emit_got (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
        emit_pointer (acfg, "got");
+       g_free (symbol);
 
        symbol = g_strdup_printf ("got_size");
        emit_section_change (acfg, ".data", 1);
@@ -3952,6 +4067,7 @@ emit_got (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
        emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
+       g_free (symbol);
 }
 
 static void
@@ -3973,6 +4089,135 @@ emit_globals (MonoAotCompile *acfg)
                emit_string_symbol (acfg, "mono_runtime_version", FULL_VERSION);
        else
                emit_string_symbol (acfg, "mono_runtime_version", "");
+
+       /*
+        * Some platforms like the iphone have no working dlsym (). To work around this,
+        * we create an ELF ctor function which will be invoked by dlopen, and which
+        * will call a function in the AOT loader to register the symbols used by the
+        * image.
+        * When static linking, we emit a global which will point to the symbol table.
+        */
+       if (acfg->aot_opts.no_dlsym) {
+               int i;
+               char *symbol;
+
+               if (acfg->aot_opts.static_link)
+                       /* Emit a string holding the assembly name */
+                       emit_string_symbol (acfg, "mono_aot_assembly_name", acfg->image->assembly->aname.name);
+
+               /* Emit the names */
+               for (i = 0; i < acfg->globals->len; ++i) {
+                       char *name = g_ptr_array_index (acfg->globals, i);
+
+                       symbol = g_strdup_printf ("name_%d", i);
+                       emit_section_change (acfg, ".text", 1);
+                       emit_label (acfg, symbol);
+                       emit_string (acfg, name);
+                       g_free (symbol);
+               }
+
+               /* Emit the globals table */
+               symbol = g_strdup_printf ("globals");
+               emit_section_change (acfg, ".data", 0);
+               /* This is not a global, since it is accessed by the init function */
+               emit_alignment (acfg, 8);
+               emit_label (acfg, symbol);
+
+               for (i = 0; i < acfg->globals->len; ++i) {
+                       char *name = g_ptr_array_index (acfg->globals, i);
+
+                       symbol = g_strdup_printf ("name_%d", i);
+                       emit_pointer (acfg, symbol);
+                       g_free (symbol);
+
+                       symbol = g_strdup_printf ("%s", name);
+                       emit_pointer (acfg, symbol);
+                       g_free (symbol);
+               }
+               /* Null terminate the table */
+               emit_pointer (acfg, NULL);
+               emit_pointer (acfg, NULL);
+
+               if (acfg->aot_opts.static_link) {
+                       /* 
+                        * Emit a global symbol which can be passed by an embedding app to
+                        * mono_aot_register_module ().
+                        */
+                       symbol = g_strdup_printf ("mono_aot_module_%s_info", acfg->image->assembly->aname.name);
+                       acfg->static_linking_symbol = g_strdup (symbol);
+                       emit_global_inner (acfg, symbol, FALSE);
+                       emit_alignment (acfg, 8);
+                       emit_label (acfg, symbol);
+                       emit_pointer (acfg, "globals");
+               } else {
+                       symbol = g_strdup_printf ("init_%s", acfg->image->assembly->aname.name);
+                       emit_section_change (acfg, ".text", 1);
+                       emit_alignment (acfg, 8);
+                       emit_label (acfg, symbol);
+#ifdef USE_BIN_WRITER
+                       g_assert_not_reached ();
+#else
+#ifdef __x86_64__
+                       fprintf (acfg->fp, "leaq globals(%%rip), %%rdi\n");
+                       fprintf (acfg->fp, "call mono_aot_register_globals@PLT\n");
+                       fprintf (acfg->fp, "ret\n");
+                       fprintf (acfg->fp, ".section .ctors,\"aw\",@progbits\n");
+                       emit_alignment (acfg, 8);
+                       emit_pointer (acfg, symbol);
+#elif defined(__arm__)
+                       /* 
+                        * Taken from gcc generated code for:
+                        * static int i;
+                        * void foo () { bar (&i); }
+                        * gcc --shared -fPIC -O2
+                        */
+                       fprintf (acfg->fp, "ldr r3, .L5\n");
+                       fprintf (acfg->fp, "ldr r0, .L5+4\n");
+                       fprintf (acfg->fp, ".LPIC0:\n");
+                       fprintf (acfg->fp, "add r3, pc, r3\n");
+                       fprintf (acfg->fp, "add r0, r3, r0\n");
+                       fprintf (acfg->fp, "b   mono_aot_register_globals(PLT)\n");
+
+                       fprintf (acfg->fp, ".L5:\n");
+                       fprintf (acfg->fp, ".word       _GLOBAL_OFFSET_TABLE_-(.LPIC0+8)\n");
+                       fprintf (acfg->fp, ".word       globals(GOTOFF)\n");
+
+                       fprintf (acfg->fp, ".section    .init_array,\"aw\",%%init_array\n");
+                       fprintf (acfg->fp, ".align      2\n");
+                       fprintf (acfg->fp, ".word       %s(target1)\n", symbol);
+#else
+                       g_assert_not_reached ();
+#endif
+#endif
+                       g_free (symbol);
+               }
+       }
+}
+
+static void
+acfg_free (MonoAotCompile *acfg)
+{
+       int i;
+
+       for (i = 0; i < acfg->nmethods; ++i)
+               if (acfg->cfgs [i])
+                       g_free (acfg->cfgs [i]);
+       g_free (acfg->cfgs);
+       g_free (acfg->method_got_offsets);
+       g_free (acfg->static_linking_symbol);
+       g_ptr_array_free (acfg->methods, TRUE);
+       g_ptr_array_free (acfg->shared_patches, TRUE);
+       g_ptr_array_free (acfg->image_table, TRUE);
+       g_ptr_array_free (acfg->globals, TRUE);
+       g_hash_table_destroy (acfg->method_indexes);
+       g_hash_table_destroy (acfg->plt_offset_to_patch);
+       g_hash_table_destroy (acfg->patch_to_plt_offset);
+       g_hash_table_destroy (acfg->patch_to_shared_got_offset);
+       g_hash_table_destroy (acfg->method_to_cfg);
+       g_hash_table_destroy (acfg->token_info_hash);
+       g_hash_table_destroy (acfg->image_hash);
+       mono_mempool_destroy (acfg->mempool);
+       g_free (acfg);
 }
 
 int
@@ -3989,14 +4234,14 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->methods = g_ptr_array_new ();
        acfg->method_indexes = g_hash_table_new (NULL, NULL);
        acfg->plt_offset_to_patch = g_hash_table_new (NULL, NULL);
-       acfg->patch_to_plt_offset = g_hash_table_new (NULL, NULL);
-       acfg->patch_to_plt_offset_wrapper = g_malloc0 (sizeof (GHashTable*) * 128);
+       acfg->patch_to_plt_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
        acfg->patch_to_shared_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
        acfg->shared_patches = g_ptr_array_new ();
        acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
-       acfg->token_info_hash = g_hash_table_new (NULL, NULL);
+       acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, g_free);
        acfg->image_hash = g_hash_table_new (NULL, NULL);
        acfg->image_table = g_ptr_array_new ();
+       acfg->globals = g_ptr_array_new ();
        acfg->image = image;
        acfg->opts = opts;
        acfg->mempool = mono_mempool_new ();
@@ -4021,7 +4266,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                if (acfg->aot_opts.full_aot && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
                        /* Compile the wrapper instead */
                        /* We do this here instead of add_wrappers () because it is easy to do it here */
-                       MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, check_for_pending_exc);
+                       MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, check_for_pending_exc, TRUE);
                        method = wrapper;
                }
 
@@ -4033,7 +4278,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        if (acfg->aot_opts.full_aot)
                add_wrappers (acfg);
 
-       acfg->nmethods = acfg->methods->len;
+       acfg->nmethods = acfg->methods->len + 1;
        acfg->cfgs = g_new0 (MonoCompile*, acfg->nmethods + 32);
        acfg->method_got_offsets = g_new0 (guint32, acfg->nmethods + 32);
 
@@ -4078,19 +4323,27 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
        printf ("Code: %d Info: %d Ex Info: %d Class Info: %d PLT: %d GOT Info: %d GOT Info Offsets: %d GOT: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, acfg->stats.got_info_offsets_size, (int)(acfg->got_offset * sizeof (gpointer)));
 
        res = emit_writeout (acfg);
-       if (res != 0)
+       if (res != 0) {
+               acfg_free (acfg);
                return res;
+       }
 
        printf ("Compiled %d out of %d methods (%d%%)\n", acfg->stats.ccount, acfg->stats.mcount, acfg->stats.mcount ? (acfg->stats.ccount * 100) / acfg->stats.mcount : 100);
-       printf ("%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
-       printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
-       printf ("%d methods contain wrapper references (%d%%)\n", acfg->stats.wrappercount, acfg->stats.mcount ? (acfg->stats.wrappercount * 100) / acfg->stats.mcount : 100);
-       printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
-       printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
+       if (acfg->stats.genericcount)
+               printf ("%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
+       if (acfg->stats.abscount)
+               printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
+       if (acfg->stats.wrappercount)
+               printf ("%d methods contain wrapper references (%d%%)\n", acfg->stats.wrappercount, acfg->stats.mcount ? (acfg->stats.wrappercount * 100) / acfg->stats.mcount : 100);
+       if (acfg->stats.lmfcount)
+               printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
+       if (acfg->stats.ocount)
+               printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
        printf ("Methods without GOT slots: %d (%d%%)\n", acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100);
        printf ("Direct calls: %d (%d%%)\n", acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100);
 
@@ -4099,6 +4352,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                if (acfg->stats.got_slot_types [i])
                        printf ("\t%s: %d\n", get_patch_name (i), acfg->stats.got_slot_types [i]);
 
+       acfg_free (acfg);
+       
        return 0;
 }