2008-08-19 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-compiler.c
index 08b375ba5435abf5a9679c4d656f81d46353b683..89378abe3ce25e65265917883e33a153c8b2045a 100644 (file)
@@ -8,9 +8,21 @@
  * (C) 2002 Ximian, Inc.
  */
 
+/* Remaining AOT-only work:
+ * - reduce the length of the wrapper names.
+ * - during loading, collect the names into a hashtable to avoid linear
+ *   searches.
+ * - aot IMT tables, so we don't have two kinds of aot code.
+ * - optimize the trampolines, generate more code in the arch files.
+ * - make things more consistent with how elf works, for example, use ELF 
+ *   relocations.
+ */
+
 #include "config.h"
 #include <sys/types.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <fcntl.h>
 #include <string.h>
 #ifndef PLATFORM_WIN32
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/metadata-internals.h>
 #include <mono/metadata/marshal.h>
+#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/method-builder.h>
 #include <mono/utils/mono-logger.h>
 #include "mono/utils/mono-compiler.h"
 
 #include "mini.h"
+#include "version.h"
 
 #ifndef DISABLE_AOT
 
 #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))
 
@@ -66,10 +88,14 @@ typedef struct MonoAotOptions {
        gboolean save_temps;
        gboolean write_symbols;
        gboolean metadata_only;
+       gboolean bind_to_runtime_version;
+       gboolean full_aot;
+       gboolean no_dlsym;
+       gboolean static_link;
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
-       int ccount, mcount, lmfcount, abscount, wrappercount, gcount, ocount;
+       int ccount, mcount, lmfcount, abscount, wrappercount, gcount, ocount, genericcount;
        int code_size, info_size, ex_info_size, got_size, class_info_size, got_info_size, got_info_offsets_size;
        int methods_without_got_slots, direct_calls, all_calls;
        int got_slots;
@@ -102,6 +128,8 @@ enum {
 
 typedef struct MonoAotCompile {
        MonoImage *image;
+       GPtrArray *methods;
+       GHashTable *method_indexes;
        MonoCompile **cfgs;
        GHashTable *patch_to_plt_offset;
        GHashTable *plt_offset_to_patch;
@@ -109,16 +137,23 @@ typedef struct MonoAotCompile {
        GPtrArray *shared_patches;
        GHashTable *image_hash;
        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;
        guint32 got_offset, plt_offset;
+       /* Number of GOT entries reserved for trampolines */
+       guint32 num_trampoline_got_entries;
        guint32 *method_got_offsets;
-       gboolean *has_got_slots;
        MonoAotOptions aot_opts;
        guint32 nmethods;
        guint32 opts;
        MonoMemPool *mempool;
        MonoAotStats stats;
+       int method_index;
+       char *static_linking_symbol;
 #ifdef USE_BIN_WRITER
        BinSymbol *symbols;
        BinSection *sections;
@@ -134,55 +169,56 @@ typedef struct MonoAotCompile {
 #endif
 } MonoAotCompile;
 
-/* Keep in synch with MonoJumpInfoType */
-static const char* patch_types [] = {
-       "bb",
-       "abs",
-       "label",
-       "method",
-       "method_jump",
-       "method_rel",
-       "methodconst",
-       "internal_method",
-       "switch",
-       "exc",
-       "exc_name",
-       "class",
-       "image",
-       "field",
-       "vtable",
-       "class_init",
-       "sflda",
-       "ldstr",
-       "ldtoken",
-       "type_from_handle",
-       "r4",
-       "r8",
-       "ip",
-       "iid",
-       "adjusted_iid",
-       "bb_ovf",
-       "exc_ovf",
-       "wrapper",
-       "got_offset",
-       "declsec",
-       "none"
+#ifdef HAVE_ARRAY_ELEM_INIT
+#define MSGSTRFIELD(line) MSGSTRFIELD1(line)
+#define MSGSTRFIELD1(line) str##line
+static const struct msgstr_t {
+#define PATCH_INFO(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
+#include "patch-info.h"
+#undef PATCH_INFO
+} opstr = {
+#define PATCH_INFO(a,b) b,
+#include "patch-info.h"
+#undef PATCH_INFO
+};
+static const gint16 opidx [] = {
+#define PATCH_INFO(a,b) [MONO_PATCH_INFO_ ## a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
+#include "patch-info.h"
+#undef PATCH_INFO
+};
+
+static const char*
+get_patch_name (int info)
+{
+       return (const char*)&opstr + opidx [info];
+}
+
+#else
+#define PATCH_INFO(a,b) b,
+static const char* const
+patch_types [MONO_PATCH_INFO_NUM + 1] = {
+#include "patch-info.h"
+       NULL
 };
 
+static const char*
+get_patch_name (int info)
+{
+       return patch_types [info];
+}
+
+#endif
+
+static void
+emit_global (MonoAotCompile *acfg, const char *name, gboolean func);
+
 static gboolean 
 is_got_patch (MonoJumpInfoType patch_type)
 {
-#ifdef __x86_64__
        return TRUE;
-#elif defined(__i386__)
-       return TRUE;
-#else
-       return FALSE;
-#endif
 }
 
-#if defined(__ppc__) && defined(__MACH__)
-static int
+static G_GNUC_UNUSED int
 ilog2(register int value)
 {
        int count = -1;
@@ -190,7 +226,6 @@ ilog2(register int value)
        while (value) count++, value >>= 1;
        return count;
 }
-#endif
 
 #ifdef USE_BIN_WRITER
 
@@ -265,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);
@@ -353,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);
@@ -950,7 +989,7 @@ resolve_relocations (MonoAotCompile *acfg)
        return rr;
 }
 
-static void
+static int
 emit_writeout (MonoAotCompile *acfg)
 {
        char *outfile_name, *tmp_outfile_name;
@@ -1220,6 +1259,8 @@ emit_writeout (MonoAotCompile *acfg)
 
        g_free (tmp_outfile_name);
        g_free (outfile_name);
+
+       return 0;
 }
 
 #endif /* USE_ELF_WRITER */
@@ -1249,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(sparc)
-       /* For solaris as, GNU as should accept the same */
-       fprintf (acfg->fp, ".section \"%s\"\n", section_name);
-#elif defined(__ppc__) && defined(__MACH__)
+#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);
 #else
        fprintf (acfg->fp, "%s %d\n", section_name, subsection_index);
 #endif
@@ -1271,19 +1312,21 @@ emit_symbol_type (MonoAotCompile *acfg, const char *name, gboolean func)
                stype = "object";
 
        emit_unset_mode (acfg);
-#if defined(sparc)
+#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)
@@ -1341,7 +1384,9 @@ static void
 emit_alignment (MonoAotCompile *acfg, int size)
 {
        emit_unset_mode (acfg);
-#if defined(__ppc__) && defined(__MACH__)
+#if defined(__arm__)
+       fprintf (acfg->fp, "\t.align %d\n", ilog2 (size));
+#elif defined(__ppc__) && defined(__MACH__)
        // the mach-o assembler specifies alignments as powers of 2.
        fprintf (acfg->fp, "\t.align %d\t; ilog2\n", ilog2(size));
 #elif defined(__powerpc__)
@@ -1357,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
 }
 
@@ -1377,7 +1422,7 @@ emit_bytes (MonoAotCompile *acfg, const guint8* buf, int size)
                if ((acfg->col_count % 32) == 0)
                        fprintf (acfg->fp, "\n\t.byte ");
                else
-                       fprintf (acfg->fp, ", ");
+                       fprintf (acfg->fp, ",");
                fprintf (acfg->fp, "0x%x", buf [i]);
        }
 }
@@ -1390,7 +1435,14 @@ emit_int16 (MonoAotCompile *acfg, int value)
                acfg->col_count = 0;
        }
        if ((acfg->col_count++ % 8) == 0)
+#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
                fprintf (acfg->fp, "\n\t.word ");
+#endif
        else
                fprintf (acfg->fp, ", ");
        fprintf (acfg->fp, "%d", value);
@@ -1406,7 +1458,7 @@ emit_int32 (MonoAotCompile *acfg, int value)
        if ((acfg->col_count++ % 8) == 0)
                fprintf (acfg->fp, "\n\t.long ");
        else
-               fprintf (acfg->fp, ", ");
+               fprintf (acfg->fp, ",");
        fprintf (acfg->fp, "%d", value);
 }
 
@@ -1420,9 +1472,11 @@ emit_symbol_diff (MonoAotCompile *acfg, const char *end, const char* start, int
        if ((acfg->col_count++ % 8) == 0)
                fprintf (acfg->fp, "\n\t.long ");
        else
-               fprintf (acfg->fp, ", ");
-       if (offset)
-               fprintf (acfg->fp, "%s - %s %c %d", end, start, offset < 0? ' ': '+', offset);
+               fprintf (acfg->fp, ",");
+       if (offset > 0)
+               fprintf (acfg->fp, "%s - %s + %d", end, start, offset);
+       else if (offset < 0)
+               fprintf (acfg->fp, "%s - %s %d", end, start, offset);
        else
                fprintf (acfg->fp, "%s - %s", end, start);
 }
@@ -1431,10 +1485,14 @@ 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 void
+static int
 emit_writeout (MonoAotCompile *acfg)
 {
        char *command, *objfile;
@@ -1449,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);
-               return;
+               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
@@ -1472,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);
-               return;
+               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);
@@ -1495,16 +1576,28 @@ 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");
        else
                unlink (acfg->tmpfname);
 
+       return 0;
 }
 
 #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)
 {
@@ -1578,48 +1671,202 @@ get_image_index (MonoAotCompile *cfg, MonoImage *image)
        }
 }
 
+static guint32
+find_typespec_for_class (MonoAotCompile *acfg, MonoClass *klass)
+{
+       int i;
+       MonoClass *k = NULL;
+
+       /* FIXME: Search referenced images as well */
+       for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
+               k = mono_class_get_full (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL);
+               if (k == klass)
+                       break;
+       }
+
+       if (i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows)
+               return MONO_TOKEN_TYPE_SPEC | (i + 1);
+       else
+               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_info (MonoAotCompile *cfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
+encode_klass_ref (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
 {
-       if (!klass->type_token) {
+       guint8 *p = buf;
+
+       if (klass->generic_class) {
+               guint32 token;
+               g_assert (klass->type_token);
+
+               /* Find a typespec for a class if possible */
+               token = find_typespec_for_class (acfg, klass);
+               if (token) {
+                       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;
+                       int i;
+
+                       /* Encode it ourselves */
+                       /* Marker */
+                       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]), 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, 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);
-               g_assert (klass->element_class->type_token);
-               encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
-               encode_value (get_image_index (cfg, klass->image), buf, &buf);
-               g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
-               encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
-               encode_value (klass->rank, buf, &buf);
-       }
-       else {
-               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 (cfg, klass->image), 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_info (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
+static guint32
+find_methodspec_for_method (MonoAotCompile *acfg, MonoMethod *method)
+{
+       int i;
+       MonoMethod *m = NULL;
+
+       /* FIXME: Search referenced images as well */
+       for (i = 0; i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows; ++i) {
+               /* Since we don't compile generic methods, the context is empty */
+               m = mono_get_method_full (acfg->image, MONO_TOKEN_METHOD_SPEC | (i + 1), NULL, NULL);
+               if (m == method)
+                       break;
+       }
+
+       g_assert (i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows);
+
+       return MONO_TOKEN_METHOD_SPEC | (i + 1);
 }
+#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;
-       g_assert (image_index < 256);
-       g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
+       MonoJumpInfoToken *ji;
+       guint8 *p = buf;
+
+       g_assert (image_index < MAX_IMAGE_INDEX);
+
+       if (mono_method_signature (method)->is_inflated) {
+               /* 
+                * This is a generic method, find the original token which referenced it and
+                * encode that.
+                */
+               /* This doesn't work for some reason */
+               /*
+               image_index = get_image_index (acfg, acfg->image);
+               g_assert (image_index < 255);
+               token = find_methodspec_for_method (acfg, method);
+               */
+               /* Obtain the token from information recorded by the JIT */
+               ji = g_hash_table_lookup (acfg->token_info_hash, method);
+               if (!ji) {
+                       MonoMethod *declaring;
+
+                       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.
+                        */
 
-       encode_value ((image_index << 24) + (mono_metadata_token_index (token)), buf, &buf);
-       *endbuf = buf;
+                       /* 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 < 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 {
+               g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
+               encode_value ((image_index << 24) | mono_metadata_token_index (token), p, &p);
+       }
+       *endbuf = p;
 }
 
 static gint
@@ -1639,62 +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;
-
        switch (patch_info->type) {
        case MONO_PATCH_INFO_METHOD:
        case MONO_PATCH_INFO_WRAPPER:
        case MONO_PATCH_INFO_INTERNAL_METHOD:
-       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_JIT_ICALL_ADDR:
+       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:
-                       /* A bit ugly, but works */
-                       g_assert (patch_info->data.method->wrapper_type < sizeof (MonoMethod));
-                       patch_id = (gpointer)(((guint8*)patch_info->data.method) + patch_info->data.method->wrapper_type);
-                       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 (acfg->patch_to_plt_offset, patch_id));
-                       if (idx)
-                               res = idx;
-                       else
-                               g_hash_table_insert (acfg->patch_to_plt_offset, 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;
 }
 
 /**
@@ -1737,92 +2000,253 @@ get_shared_got_offset (MonoAotCompile *acfg, MonoJumpInfo *ji)
        return get_got_offset (acfg, ji);
 }
 
+/* Add a method to the list of methods which need to be emitted */
 static void
-emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
+add_method_with_index (MonoAotCompile *acfg, MonoMethod *method, int index)
 {
-       MonoMethod *method;
-       int i, pindex, method_index;
-       guint8 *code;
-       char *symbol;
-       int func_alignment = 16;
-       GPtrArray *patches;
-       MonoJumpInfo *patch_info;
-       MonoMethodHeader *header;
-       gboolean skip;
-       guint32 got_slot;
+       if (!g_hash_table_lookup (acfg->method_indexes, method)) {
+               g_ptr_array_add (acfg->methods, method);
+               g_hash_table_insert (acfg->method_indexes, method, GUINT_TO_POINTER (index + 1));
+       }
+}
 
-       method = cfg->method;
-       code = cfg->native_code;
-       header = mono_method_get_header (method);
+static guint32
+get_method_index (MonoAotCompile *acfg, MonoMethod *method)
+{
+       int index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_indexes, method));
+       
+       g_assert (index);
 
-       method_index = mono_metadata_token_index (method->token);
+       return index - 1;
+}
 
-       /* Make the labels local */
-       symbol = g_strdup_printf (".Lm_%x", method_index);
+static int
+add_method (MonoAotCompile *acfg, MonoMethod *method)
+{
+       int index = acfg->method_index;
 
-       emit_alignment (acfg, func_alignment);
-       emit_label (acfg, symbol);
-       if (acfg->aot_opts.write_symbols)
-               emit_global (acfg, symbol, TRUE);
+       add_method_with_index (acfg, method, index);
 
-       if (cfg->verbose_level > 0)
-               g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
+       /* FIXME: Fix quadratic behavior */
+       acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (index));
 
-       acfg->stats.code_size += cfg->code_len;
+       acfg->method_index ++;
 
-       /* Collect and sort relocations */
-       patches = g_ptr_array_new ();
-       for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
-               g_ptr_array_add (patches, patch_info);
-       g_ptr_array_sort (patches, compare_patches);
+       return index;
+}
 
-       acfg->method_got_offsets [method_index] = acfg->got_offset;
-       for (i = 0; i < cfg->code_len; i++) {
-               patch_info = NULL;
-               for (pindex = 0; pindex < patches->len; ++pindex) {
-                       patch_info = g_ptr_array_index (patches, pindex);
-                       if (patch_info->ip.i == i)
-                               break;
-               }
+static void
+add_jit_icall_wrapper (gpointer key, gpointer value, gpointer user_data)
+{
+       MonoAotCompile *acfg = user_data;
+       MonoJitICallInfo *callinfo = value;
+       MonoMethod *wrapper;
+       char *name;
 
-#ifdef MONO_ARCH_HAVE_PIC_AOT
+       if (!callinfo->sig)
+               return;
 
-               skip = FALSE;
-               if (patch_info && (pindex < patches->len)) {
-                       switch (patch_info->type) {
-                       case MONO_PATCH_INFO_LABEL:
-                       case MONO_PATCH_INFO_BB:
-                       case MONO_PATCH_INFO_NONE:
-                               break;
-                       case MONO_PATCH_INFO_GOT_OFFSET: {
-                               guint32 offset = mono_arch_get_patch_offset (code + i);
-                               emit_bytes (acfg, code + i, offset);
-                               emit_symbol_diff (acfg, "got", ".", offset);
+       name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
+       wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
+       g_free (name);
 
-                               i += offset + 4 - 1;
-                               skip = TRUE;
-                               break;
-                       }
-                       default: {
-                               int plt_index;
-                               char *direct_call_target;
+       add_method (acfg, wrapper);
+}
 
-                               if (!is_got_patch (patch_info->type))
-                                       break;
+static MonoMethod*
+get_runtime_invoke_sig (MonoMethodSignature *sig)
+{
+       MonoMethodBuilder *mb;
+       MonoMethod *m;
 
-                               /*
-                                * If this patch is a call, try emitting a direct call instead of
+       mb = mono_mb_new (mono_defaults.object_class, "FOO", MONO_WRAPPER_NONE);
+       m = mono_mb_create_method (mb, sig, 16);
+       return mono_marshal_get_runtime_invoke (m);
+}
+
+static void
+add_wrappers (MonoAotCompile *acfg)
+{
+       MonoMethod *m;
+       int i, nallocators;
+       MonoMethodSignature *csig;
+
+       /* 
+        * FIXME: Instead of AOTing all the wrappers, it might be better to redesign them
+        * so there is only one wrapper of a given type, or inlining their contents into their
+        * callers.
+        */
+
+       /* 
+        * FIXME: This depends on the fact that different wrappers have different 
+        * names.
+        */
+
+       /* FIXME: Collect these automatically */
+
+       /* Runtime invoke wrappers */
+
+       /* void runtime-invoke () [.cctor] */
+       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+       csig->ret = &mono_defaults.void_class->byval_arg;
+       add_method (acfg, get_runtime_invoke_sig (csig));
+
+       /* void runtime-invoke () [Finalize] */
+       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+       csig->hasthis = 1;
+       csig->ret = &mono_defaults.void_class->byval_arg;
+       add_method (acfg, get_runtime_invoke_sig (csig));
+
+       /* void runtime-invoke (string) [exception ctor] */
+       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
+       csig->hasthis = 1;
+       csig->ret = &mono_defaults.void_class->byval_arg;
+       csig->params [0] = &mono_defaults.string_class->byval_arg;
+       add_method (acfg, get_runtime_invoke_sig (csig));
+
+       /* void runtime-invoke (string, string) [exception ctor] */
+       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
+       csig->hasthis = 1;
+       csig->ret = &mono_defaults.void_class->byval_arg;
+       csig->params [0] = &mono_defaults.string_class->byval_arg;
+       csig->params [1] = &mono_defaults.string_class->byval_arg;
+       add_method (acfg, get_runtime_invoke_sig (csig));
+
+       /* string runtime-invoke () [Exception.ToString ()] */
+       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+       csig->hasthis = 1;
+       csig->ret = &mono_defaults.string_class->byval_arg;
+       add_method (acfg, get_runtime_invoke_sig (csig));
+
+       /* void runtime-invoke (string, Exception) [exception ctor] */
+       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
+       csig->hasthis = 1;
+       csig->ret = &mono_defaults.void_class->byval_arg;
+       csig->params [0] = &mono_defaults.string_class->byval_arg;
+       csig->params [1] = &mono_defaults.exception_class->byval_arg;
+       add_method (acfg, get_runtime_invoke_sig (csig));
+
+       /* Assembly runtime-invoke (string, bool) [DoAssemblyResolve] */
+       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
+       csig->hasthis = 1;
+       csig->ret = &(mono_class_from_name (
+                                                                               mono_defaults.corlib, "System.Reflection", "Assembly"))->byval_arg;
+       csig->params [0] = &mono_defaults.string_class->byval_arg;
+       csig->params [1] = &mono_defaults.boolean_class->byval_arg;
+       add_method (acfg, get_runtime_invoke_sig (csig));
+
+       for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoMethod *method;
+               guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+
+               method = mono_get_method (acfg->image, token, NULL);
+
+               if (!strcmp (method->name, "Main"))
+                       add_method (acfg, mono_marshal_get_runtime_invoke (method));
+       }
+
+       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);
+               }
+
+               /* 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;
+               MonoMethodSignature *sig;
+               guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+
+               method = mono_get_method (acfg->image, token, NULL);
+
+               sig = mono_method_signature (method);
+
+               if (sig->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
+                       !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+                       m = mono_marshal_get_remoting_invoke_with_check (method);
+
+                       add_method (acfg, m);
+               }
+       }
+}
+
+static void
+emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, guint32 code_len, MonoJumpInfo *relocs, gboolean got_only)
+{
+       int i, pindex, start_index, method_index;
+       GPtrArray *patches;
+       MonoJumpInfo *patch_info;
+       MonoMethodHeader *header;
+       gboolean skip;
+       guint32 got_slot;
+
+       if (method) {
+               header = mono_method_get_header (method);
+
+               method_index = get_method_index (acfg, method);
+       }
+
+       /* Collect and sort relocations */
+       patches = g_ptr_array_new ();
+       for (patch_info = relocs; patch_info; patch_info = patch_info->next)
+               g_ptr_array_add (patches, patch_info);
+       g_ptr_array_sort (patches, compare_patches);
+
+       start_index = 0;
+       for (i = 0; i < code_len; i++) {
+               patch_info = NULL;
+               for (pindex = start_index; pindex < patches->len; ++pindex) {
+                       patch_info = g_ptr_array_index (patches, pindex);
+                       if (patch_info->ip.i >= i)
+                               break;
+               }
+
+#ifdef MONO_ARCH_AOT_SUPPORTED
+               skip = FALSE;
+               if (patch_info && (patch_info->ip.i == i) && (pindex < patches->len)) {
+                       start_index = pindex;
+
+                       switch (patch_info->type) {
+                       case MONO_PATCH_INFO_NONE:
+                               break;
+                       case MONO_PATCH_INFO_GOT_OFFSET: {
+                               guint32 offset = mono_arch_get_patch_offset (code + i);
+                               emit_bytes (acfg, code + i, offset);
+                               emit_symbol_diff (acfg, "got", ".", offset);
+
+                               i += offset + 4 - 1;
+                               skip = TRUE;
+                               break;
+                       }
+                       default: {
+                               char *direct_call_target;
+
+                               if (!is_got_patch (patch_info->type))
+                                       break;
+
+                               /*
+                                * If this patch is a call, try emitting a direct call instead of
                                 * through a PLT entry. This is possible if the called method is in
                                 * the same assembly and requires no initialization.
                                 */
                                direct_call_target = NULL;
-                               if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == cfg->method->klass->image)) {
+                               if (!got_only && (patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == method->klass->image)) {
                                        MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
                                        if (callee_cfg) {
-                                               guint32 callee_idx = mono_metadata_token_index (callee_cfg->method->token);
-                                               if (!acfg->has_got_slots [callee_idx] && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)) {
+                                               if (!callee_cfg->has_got_slots && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)) {
                                                        //printf ("DIRECT: %s %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (callee_cfg->method, TRUE));
-                                                       direct_call_target = g_strdup_printf (".Lm_%x", mono_metadata_token_index (callee_cfg->method->token));
+                                                       direct_call_target = g_strdup_printf (".Lm_%x", get_method_index (acfg, callee_cfg->method));
                                                        patch_info->type = MONO_PATCH_INFO_NONE;
                                                        acfg->stats.direct_calls ++;
                                                }
@@ -1831,11 +2255,14 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
                                        acfg->stats.all_calls ++;
                                }
 
-                               if (!direct_call_target) {
-                                       plt_index = get_plt_index (acfg, patch_info);
-                                       if (plt_index != -1) {
+                               if (!got_only && !direct_call_target) {
+                                       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;
                                        }
                                }
 
@@ -1846,9 +2273,18 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
                                        emit_byte (acfg, '\xe8');
                                        emit_symbol_diff (acfg, direct_call_target, ".", -4);
                                        i += 4;
-#else
+#elif defined(__arm__)
+#ifdef USE_BIN_WRITER
+                                       /* FIXME: Can't encode this using the current symbol writer functions */
                                        g_assert_not_reached ();
+#else
+                                       emit_unset_mode (acfg);
+                                       fprintf (acfg->fp, "bl %s\n", direct_call_target);
+                                       i += 4 - 1;
+#endif
 #endif
+
+                                       g_free (direct_call_target);
                                } else {
                                        got_slot = get_got_offset (acfg, patch_info);
 
@@ -1857,6 +2293,10 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
                                        emit_symbol_diff (acfg, "got", ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
 #elif defined(__i386__)
                                        emit_int32 (acfg, (unsigned int) ((got_slot * sizeof (gpointer))));
+#elif defined(__arm__)
+                                       emit_symbol_diff (acfg, "got", ".", (unsigned int) ((got_slot * sizeof (gpointer))) - 12);
+#else
+                                       g_assert_not_reached ();
 #endif
                                        
                                        i += mono_arch_get_patch_offset (code + i) + 4 - 1;
@@ -1865,22 +2305,57 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
                        }
                        }
                }
-#endif /* MONO_ARCH_HAVE_PIC_AOT */
+#endif /* MONO_ARCH_AOT_SUPPORTED */
 
                if (!skip)
                        emit_bytes (acfg, code + i, 1);
        }
+}
+
+static void
+emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
+{
+       MonoMethod *method;
+       int method_index;
+       guint8 *code;
+       char *symbol;
+       int func_alignment = 16;
+       MonoMethodHeader *header;
+
+       method = cfg->orig_method;
+       code = cfg->native_code;
+       header = mono_method_get_header (method);
+
+       method_index = get_method_index (acfg, method);
+
+       /* Make the labels local */
+       symbol = g_strdup_printf (".Lm_%x", method_index);
+
+       emit_alignment (acfg, func_alignment);
+       emit_label (acfg, symbol);
+       if (acfg->aot_opts.write_symbols)
+               emit_global (acfg, symbol, TRUE);
+
+       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;
+
+       acfg->method_got_offsets [method_index] = acfg->got_offset;
+
+       emit_and_reloc_code (acfg, method, code, cfg->code_len, cfg->patch_info, FALSE);
+
        emit_line (acfg);
 }
 
 /**
  * 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;
 
@@ -1905,9 +2380,12 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        case MONO_PATCH_INFO_METHODCONST:
        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: {
+       case MONO_PATCH_INFO_INTERNAL_METHOD:
+       case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
                guint32 len = strlen (patch_info->data.name);
 
                encode_value (len, p, &p);
@@ -1921,24 +2399,16 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
                guint32 token = patch_info->data.token->token;
                g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
-               /* 
-                * An optimization would be to emit shared code for ldstr 
-                * statements followed by a throw.
-                */
                encode_value (image_index, p, &p);
                encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
                break;
        }
+       case MONO_PATCH_INFO_RVA:
        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;
@@ -1947,7 +2417,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                        mono_class_from_name (mono_defaults.exception_class->image,
                                                                  "System", patch_info->data.target);
                g_assert (ex_class);
-               encode_klass_info (acfg, ex_class, p, &p);
+               encode_klass_ref (acfg, ex_class, p, &p);
                break;
        }
        case MONO_PATCH_INFO_R4:
@@ -1961,30 +2431,25 @@ 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_info (acfg, patch_info->data.klass, p, &p);
-               }
+               encode_klass_ref (acfg, patch_info->data.klass, p, &p);
                break;
        case MONO_PATCH_INFO_CLASS_INIT:
-               encode_klass_info (acfg, patch_info->data.klass, p, &p);
+       case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
+               encode_klass_ref (acfg, patch_info->data.klass, p, &p);
                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_WRAPPER: {
+       case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
+               break;
+       case MONO_PATCH_INFO_WRAPPER:
                encode_value (patch_info->data.method->wrapper_type, p, &p);
 
                switch (patch_info->data.method->wrapper_type) {
-               case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
+               case MONO_WRAPPER_REMOTING_INVOKE:
+               case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
+               case MONO_WRAPPER_XDOMAIN_INVOKE: {
                        MonoMethod *m;
                        guint32 image_index;
                        guint32 token;
@@ -2002,11 +2467,18 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                case MONO_WRAPPER_LDFLD:
                case MONO_WRAPPER_LDFLDA:
                case MONO_WRAPPER_STFLD:
-               case MONO_WRAPPER_LDFLD_REMOTE:
-               case MONO_WRAPPER_STFLD_REMOTE:
                case MONO_WRAPPER_ISINST: {
                        MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
-                       encode_klass_info (acfg, proxy_class, p, &p);
+                       encode_klass_ref (acfg, proxy_class, p, &p);
+                       break;
+               }
+               case MONO_WRAPPER_LDFLD_REMOTE:
+               case MONO_WRAPPER_STFLD_REMOTE:
+                       break;
+               case MONO_WRAPPER_ALLOC: {
+                       int alloc_type = mono_gc_get_managed_allocator_type (patch_info->data.method);
+                       g_assert (alloc_type != -1);
+                       encode_value (alloc_type, p, &p);
                        break;
                }
                case MONO_WRAPPER_STELEMREF:
@@ -2015,7 +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 ();
@@ -2024,29 +2507,77 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        *endbuf = p;
 }
 
+static void
+encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, int first_got_offset, guint8 *buf, guint8 **endbuf)
+{
+       guint8 *p = buf;
+       guint32 last_offset, j, pindex;
+       MonoJumpInfo *patch_info;
+
+       encode_value (n_patches, p, &p);
+
+       if (n_patches)
+               encode_value (first_got_offset, p, &p);
+
+       /* First encode the type+position table */
+       last_offset = 0;
+       j = 0;
+       for (pindex = 0; pindex < patches->len; ++pindex) {
+               guint32 offset;
+               patch_info = g_ptr_array_index (patches, pindex);
+               
+               if (patch_info->type == MONO_PATCH_INFO_NONE)
+                       /* Nothing to do */
+                       continue;
+
+               j ++;
+               //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
+               offset = patch_info->ip.i - last_offset;
+               last_offset = patch_info->ip.i;
+
+               /* Only the type is needed */
+               *p = patch_info->type;
+               p++;
+       }
+
+       /* Then encode the other info */
+       for (pindex = 0; pindex < patches->len; ++pindex) {
+               patch_info = g_ptr_array_index (patches, pindex);
+
+               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;
+}
+
 static void
 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
 {
        MonoMethod *method;
        GList *l;
-       int j, pindex, buf_size, n_patches;
+       int pindex, buf_size, n_patches;
        guint8 *code;
        char *symbol;
        GPtrArray *patches;
        MonoJumpInfo *patch_info;
        MonoMethodHeader *header;
-       guint32 last_offset, method_idx;
+       guint32 method_index;
        guint8 *p, *buf;
        guint32 first_got_offset;
 
-       method = cfg->method;
+       method = cfg->orig_method;
        code = cfg->native_code;
        header = mono_method_get_header (method);
 
-       method_idx = mono_metadata_token_index (method->token);
+       method_index = get_method_index (acfg, method);
 
        /* Make the labels local */
-       symbol = g_strdup_printf (".Lm_%x_p", method_idx);
+       symbol = g_strdup_printf (".Lm_%x_p", method_index);
 
        /* Sort relocations */
        patches = g_ptr_array_new ();
@@ -2054,7 +2585,7 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
                g_ptr_array_add (patches, patch_info);
        g_ptr_array_sort (patches, compare_patches);
 
-       first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
+       first_got_offset = acfg->method_got_offsets [method_index];
 
        /**********************/
        /* Encode method info */
@@ -2064,7 +2595,7 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        p = buf = g_malloc (buf_size);
 
        if (mono_class_get_cctor (method->klass))
-               encode_klass_info (acfg, method->klass, p, &p);
+               encode_klass_ref (acfg, method->klass, p, &p);
        else
                /* Not needed when loading the method */
                encode_value (0, p, &p);
@@ -2084,9 +2615,7 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        for (pindex = 0; pindex < patches->len; ++pindex) {
                patch_info = g_ptr_array_index (patches, pindex);
                
-               if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
-                       (patch_info->type == MONO_PATCH_INFO_BB) ||
-                       (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
+               if ((patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
                        (patch_info->type == MONO_PATCH_INFO_NONE)) {
                        patch_info->type = MONO_PATCH_INFO_NONE;
                        /* Nothing to do */
@@ -2099,10 +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_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;
@@ -2112,89 +2638,45 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        }
 
        if (n_patches)
-               g_assert (acfg->has_got_slots [method_idx]);
+               g_assert (cfg->has_got_slots);
 
-       encode_value (n_patches, p, &p);
-
-       if (n_patches)
-               encode_value (first_got_offset, p, &p);
-
-       /* First encode the type+position table */
-       last_offset = 0;
-       j = 0;
-       for (pindex = 0; pindex < patches->len; ++pindex) {
-               guint32 offset;
-               patch_info = g_ptr_array_index (patches, pindex);
-               
-               if (patch_info->type == MONO_PATCH_INFO_NONE)
-                       /* Nothing to do */
-                       continue;
-
-               j ++;
-               //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
-               offset = patch_info->ip.i - last_offset;
-               last_offset = patch_info->ip.i;
-
-               /* Only the type is needed */
-               *p = patch_info->type;
-               p++;
-       }
-
-       /*
-       if (n_patches) {
-               printf ("%s:\n", mono_method_full_name (cfg->method, TRUE));
-               for (pindex = 0; pindex < patches->len; ++pindex) {
-                       patch_info = g_ptr_array_index (patches, pindex);
-                       if (patch_info->type != MONO_PATCH_INFO_NONE) {
-                               printf ("\t%s", patch_types [patch_info->type]);
-                               if (patch_info->type == MONO_PATCH_INFO_VTABLE)
-                                       printf (": %s\n", patch_info->data.klass->name);
-                               else
-                                       printf ("\n");
-                       }
-               }
-       }
-       */
-
-       /* Then encode the other info */
-       for (pindex = 0; pindex < patches->len; ++pindex) {
-               patch_info = g_ptr_array_index (patches, pindex);
-
-               encode_patch (acfg, patch_info, p, &p, TRUE);
-       }
+       encode_patch_list (acfg, patches, n_patches, first_got_offset, p, &p);
 
        acfg->stats.info_size += p - buf;
 
        /* 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
 emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 {
        MonoMethod *method;
-       int k, buf_size;
+       int k, buf_size, method_index;
        guint32 debug_info_size;
        guint8 *code;
        char *symbol;
        MonoMethodHeader *header;
        guint8 *p, *buf, *debug_info;
 
-       method = cfg->method;
+       method = cfg->orig_method;
        code = cfg->native_code;
        header = mono_method_get_header (method);
 
+       method_index = get_method_index (acfg, method);
+
        /* Make the labels local */
-       symbol = g_strdup_printf (".Le_%x_p", mono_metadata_token_index (method->token));
+       symbol = g_strdup_printf (".Le_%x_p", method_index);
+
+       mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
 
-       buf_size = header->num_clauses * 256 + 128;
+       buf_size = header->num_clauses * 256 + debug_info_size + 128;
        p = buf = g_malloc (buf_size);
 
        encode_value (cfg->code_len, p, &p);
@@ -2218,7 +2700,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                }
        }
 
-       mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
+       g_assert (debug_info_size < buf_size);
 
        encode_value (debug_info_size, p, &p);
        if (debug_info_size) {
@@ -2232,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
@@ -2246,16 +2727,18 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
        MonoClass *klass = mono_class_get (acfg->image, token);
        guint8 *p, *buf;
        int i, buf_size;
-       char *label;
-       gboolean no_special_static;
+       char *symbol;
+       gboolean no_special_static, cant_encode;
 
-       buf_size = 10240;
+       buf_size = 10240 + (klass->vtable_size * 16);
        p = buf = g_malloc (buf_size);
 
        g_assert (klass);
 
        mono_class_init (klass);
 
+       mono_class_setup_vtable (klass);
+
        /* 
         * Emit all the information which is required for creating vtables so
         * the runtime does not need to create the MonoMethod structures which
@@ -2264,7 +2747,18 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
 
        no_special_static = !mono_class_has_special_static_fields (klass);
 
-       if (1) {
+       /* Check whenever we have enough info to encode the vtable */
+       cant_encode = FALSE;
+       for (i = 0; i < klass->vtable_size; ++i) {
+               MonoMethod *cm = klass->vtable [i];
+
+               if (cm && mono_method_signature (cm)->is_inflated && !g_hash_table_lookup (acfg->token_info_hash, cm))
+                       cant_encode = TRUE;
+       }
+
+       if (klass->generic_container || cant_encode) {
+               encode_value (-1, p, &p);
+       } else {
                encode_value (klass->vtable_size, p, &p);
                encode_value ((no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (klass->nested_classes ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
                if (klass->has_cctor)
@@ -2290,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);
@@ -2304,7 +2799,7 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
  * - the ELF PLT entries make an indirect jump though the GOT so they expect the
  *   GOT pointer to be in EBX. We want to avoid this, so our table contains direct
  *   jumps. This means the jumps need to be patched when the address of the callee is
- *   known. Initially the PLT entries jump to code which transfer control to the
+ *   known. Initially the PLT entries jump to code which transfers control to the
  *   AOT runtime through the first PLT entry.
  */
 static void
@@ -2328,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);
@@ -2339,37 +2834,34 @@ emit_plt (MonoAotCompile *acfg)
        emit_global (acfg, symbol, TRUE);
        emit_alignment (acfg, PAGESIZE);
        emit_label (acfg, symbol);
+       g_free (symbol);
 
-       /* 
-        * The first plt entry is used to transfer code to the AOT loader. 
-        */
-       emit_label (acfg, ".Lp_0");
-#if defined(__i386__)
-       /* It is filled up during loading by the AOT loader. */
-       emit_zero_bytes (acfg, 16);
-#elif defined(__x86_64__)
-       /* This should be exactly 16 bytes long */
-       /* jmpq *<offset>(%rip) */
-       emit_byte (acfg, '\xff');
-       emit_byte (acfg, '\x25');
-       emit_symbol_diff (acfg, "plt_jump_table", ".", -4);
-       emit_zero_bytes (acfg, 10);
-#else
+#if defined(USE_BIN_WRITER) && defined(__arm__)
+       /* FIXME: */
        g_assert_not_reached ();
 #endif
 
-       for (i = 1; i < acfg->plt_offset; ++i) {
+       for (i = 0; i < acfg->plt_offset; ++i) {
                char *label;
 
                label = g_strdup_printf (".Lp_%d", i);
                emit_label (acfg, label);
                g_free (label);
+
+               /* 
+                * The first plt entry is used to transfer code to the AOT loader. 
+                */
+
 #if defined(__i386__)
-               /* Need to make sure this is 5 bytes long */
-               emit_byte (acfg, '\xe9');
-               label = g_strdup_printf (".Lpd_%d", i);
-               emit_symbol_diff (acfg, label, ".", -4);
-               g_free (label);
+               if (i == 0) {
+                       /* It is filled up during loading by the AOT loader. */
+                       emit_zero_bytes (acfg, 16);
+               } else {
+                       /* Need to make sure this is 9 bytes long */
+                       emit_byte (acfg, '\xe9');
+                       emit_symbol_diff (acfg, "plt", ".", -4);
+                       emit_int32 (acfg, plt_info_offsets [i]);
+               }
 #elif defined(__x86_64__)
                /*
                 * We can't emit jumps because they are 32 bits only so they can't be patched.
@@ -2377,87 +2869,342 @@ 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__)
+               /* FIXME:
+                * - optimize OP_AOTCONST implementation
+                * - optimize the PLT entries
+                * - optimize SWITCH AOT implementation
+                * - implement IMT support
+                */
+               emit_unset_mode (acfg);
+               fprintf (acfg->fp, "\tldr ip, [pc, #4]\n");
+               fprintf (acfg->fp, "\tadd ip, pc, ip\n");
+               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
        }
 
-       symbol = g_strdup_printf ("plt_end");
-       emit_global (acfg, symbol, TRUE);
-       emit_label (acfg, symbol);
+       g_free (plt_info_offsets);
+
+       symbol = g_strdup_printf ("plt_end");
+       emit_global (acfg, symbol, TRUE);
+       emit_label (acfg, symbol);
+       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);
+       g_free (buf);
+
+       symbol = g_strdup_printf ("plt_jump_table_addr");
+       emit_section_change (acfg, ".data", 0);
+       emit_global (acfg, symbol, FALSE);
+       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);
+       emit_global (acfg, symbol, FALSE);
+       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)));
+#endif 
+
+       symbol = g_strdup_printf ("plt_jump_table_end");
+       emit_label (acfg, symbol);
+       g_free (symbol);
+}
+
+static void
+emit_named_code (MonoAotCompile *acfg, const char *name, guint8 *code, 
+                                guint32 code_size, int got_offset, MonoJumpInfo *ji)
+{
+       char *symbol;
+       guint32 buf_size;
+       MonoJumpInfo *patch_info;
+       guint8 *buf, *p;
+       GPtrArray *patches;
+
+       /* Emit code */
+
+       symbol = g_strdup_printf ("%s", name);
+
+       emit_section_change (acfg, ".text", 0);
+       emit_global (acfg, symbol, TRUE);
+       emit_alignment (acfg, 16);
+       emit_label (acfg, symbol);
+       g_free (symbol);
+
+       /* 
+        * The code should access everything through the GOT, so we pass
+        * TRUE here.
+        */
+       emit_and_reloc_code (acfg, NULL, code, code_size, ji, TRUE);
+
+       /* Emit info */
+
+       /* Sort relocations */
+       patches = g_ptr_array_new ();
+       for (patch_info = ji; patch_info; patch_info = patch_info->next)
+               g_ptr_array_add (patches, patch_info);
+       g_ptr_array_sort (patches, compare_patches);
+
+       buf_size = patches->len * 128 + 128;
+       buf = g_malloc (buf_size);
+       p = buf;
+
+       encode_patch_list (acfg, patches, patches->len, got_offset, p, &p);
+       g_assert (p - buf < buf_size);
+
+       symbol = g_strdup_printf ("%s_p", name);
+
+       emit_section_change (acfg, ".text", 0);
+       emit_global (acfg, symbol, FALSE);
+       emit_label (acfg, symbol);
+       g_free (symbol);
+               
+       emit_bytes (acfg, buf, p - buf);
+}
+
+/*
+ * When running in aot-only mode, we can't create trampolines at runtime, so we create 
+ * a few, and save them in the AOT file. Normal trampolines embed their argument as a 
+ * literal inside the trampoline code, we can't do that here, so instead we embed an offset
+ * which needs to be added to the trampoline address to get the address of the GOT slot
+ * which contains the argument value.
+ * The generated trampolines jump to the generic trampolines using another GOT slot, which
+ * will be setup by the AOT loader to point to the generic trampoline code of the given 
+ * type.
+ */
+static void
+emit_trampolines (MonoAotCompile *acfg)
+{
+       char *symbol;
+       int tramp_type, i, offset;
+#ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
+       guint32 code_size;
+       MonoJumpInfo *ji;
+       guint8 *code;
+#endif
+
+       if (!acfg->aot_opts.full_aot)
+               return;
+       
+       g_assert (acfg->image->assembly);
+
+       /* 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
+               /*
+                * Emit the generic trampolines.
+                *
+                * We could save some code by treating the generic trampolines as a wrapper
+                * method, but that approach has its own complexities, so we choose the simpler
+                * method.
+                */
+               for (tramp_type = 0; tramp_type < MONO_TRAMPOLINE_NUM; ++tramp_type) {
+                       code = mono_arch_create_trampoline_code_full (tramp_type, &code_size, &ji, TRUE);
+
+                       /* Emit trampoline code */
+
+                       symbol = g_strdup_printf ("generic_trampoline_%d", tramp_type);
+
+                       emit_named_code (acfg, symbol, code, code_size, acfg->got_offset, ji);
+
+                       g_free (symbol);
+               }
+
+               code = mono_arch_get_nullified_class_init_trampoline (&code_size);
+               emit_named_code (acfg, "nullified_class_init_trampoline", code, code_size, acfg->got_offset, NULL);
+
+               /* Emit the exception related code pieces */
+               code = mono_arch_get_restore_context_full (&code_size, &ji, TRUE);
+               emit_named_code (acfg, "restore_context", code, code_size, acfg->got_offset, ji);
+               code = mono_arch_get_call_filter_full (&code_size, &ji, TRUE);
+               emit_named_code (acfg, "call_filter", code, code_size, acfg->got_offset, ji);
+               code = mono_arch_get_throw_exception_full (&code_size, &ji, TRUE);
+               emit_named_code (acfg, "throw_exception", code, code_size, acfg->got_offset, ji);
+               code = mono_arch_get_rethrow_exception_full (&code_size, &ji, TRUE);
+               emit_named_code (acfg, "rethrow_exception", code, code_size, acfg->got_offset, ji);
+               code = mono_arch_get_throw_exception_by_name_full (&code_size, &ji, TRUE);
+               emit_named_code (acfg, "throw_exception_by_name", code, code_size, acfg->got_offset, ji);
+               code = mono_arch_get_throw_corlib_exception_full (&code_size, &ji, TRUE);
+               emit_named_code (acfg, "throw_corlib_exception", code, code_size, acfg->got_offset, ji);
+#endif
+
+               /*
+                * FIXME: Maybe we should use more specific trampolines (i.e. one class init for
+                * each class).
+                */
+
+               /* Reserve some entries at the end of the GOT for our use */
+               acfg->num_trampoline_got_entries = acfg->num_aot_trampolines * 2;
+
+               symbol = g_strdup_printf ("trampolines");
+
+               emit_section_change (acfg, ".text", 0);
+               emit_global (acfg, symbol, TRUE);
+               emit_alignment (acfg, 16);
+               emit_label (acfg, symbol);
+
+               for (i = 0; i < acfg->num_aot_trampolines; ++i) {
+                       offset = acfg->got_offset + (i * 2);
+
+                       /*
+                        * The trampolines created here are variations of the specific 
+                        * trampolines created in mono_arch_create_specific_trampoline (). The 
+                        * differences are:
+                        * - the generic trampoline address is taken from a got slot.
+                        * - the offset of the got slot where the trampoline argument is stored
+                        *   is embedded in the instruction stream, and the generic trampoline
+                        *   can load the argument by loading the offset, adding it to the
+                        *   address of the trampoline to get the address of the got slot, and
+                        *   loading the argument from the there.
+                        */
+#if defined(__x86_64__)
+                       /* This should be exactly 16 bytes long */
+                       /* It should work together with the generic trampoline code in tramp-amd64.c */
+                       /* call *<offset>(%rip) */
+                       emit_byte (acfg, '\x41');
+                       emit_byte (acfg, '\xff');
+                       emit_byte (acfg, '\x15');
+                       emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4);
+                       /* This should be relative to the start of the trampoline */
+                       emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4 + 19);
+                       emit_zero_bytes (acfg, 5);
+#elif defined(__arm__)
+                       {
+                               guint8 buf [128];
+
+                               /* Generate the trampoline code */
+                               /* This should be exactly 28 bytes long */
+
+                               code = buf;
+                               ARM_PUSH (code, 0x5fff);
+                               ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 8);
+                               /* Load the value from the GOT */
+                               ARM_LDR_REG_REG (code, ARMREG_R1, ARMREG_PC, ARMREG_R1);
+                               /* Branch to it */
+                               ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
+                               ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_R1);
+
+                               g_assert (code - buf == 20);
+
+                               /* Emit it */
+                               emit_bytes (acfg, buf, code - buf);
+                               emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4 + 8);
+                               emit_symbol_diff (acfg, "got", ".", ((offset + 1) * sizeof (gpointer)) - 4 + 8);
+                       }
+#else
+                       g_assert_not_reached ();
+#endif
+               }
+       }
+
+       /* Unbox trampolines */
 
-       /* 
-        * 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;
+       for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoMethod *method;
+               guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+               MonoCompile *cfg;
+               char *call_target;
 
-               label = g_strdup_printf (".Lpd_%d", i);
-               emit_label (acfg, label);
-               g_free (label);
+               method = mono_get_method (acfg->image, token, NULL);
 
-               /* 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 */
-#else
-               g_assert_not_reached ();
-#endif
-       }
+               cfg = g_hash_table_lookup (acfg->method_to_cfg, method);
+               if (!cfg || !cfg->orig_method->klass->valuetype || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL))
+                       continue;
 
-       /* Emit PLT info */
-       symbol = g_strdup_printf ("plt_info");
-       emit_global (acfg, symbol, FALSE);
-       emit_label (acfg, symbol);
+               symbol = g_strdup_printf ("unbox_trampoline_%d", i);
 
-       g_assert (p - buf < buf_size);
-       emit_bytes (acfg, buf, p - buf);
-       g_free (buf);
+               emit_section_change (acfg, ".text", 0);
+               emit_global (acfg, symbol, TRUE);
+               emit_label (acfg, symbol);
 
-       symbol = g_strdup_printf ("plt_jump_table_addr");
-       emit_section_change (acfg, ".data", 0);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-       emit_pointer (acfg, "plt_jump_table");
+               call_target = g_strdup_printf (".Lm_%x", get_method_index (acfg, cfg->orig_method));
 
-       symbol = g_strdup_printf ("plt_jump_table_size");
-       emit_section_change (acfg, ".data", 0);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-       emit_symbol_diff (acfg, "plt_jump_table_end", "plt_jump_table", 0);
+#if defined(__x86_64__)
+               {
+                       guint8 buf [32];
+                       int this_reg;
+
+                       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));
+
+                       emit_bytes (acfg, buf, code - buf);
+                       /* jump <method> */
+                       emit_byte (acfg, '\xe9');
+                       emit_symbol_diff (acfg, call_target, ".", -4);
+               }
+#elif defined(__arm__)
+               {
+                       guint8 buf [128];
+                       int this_pos = 0;
 
-       /* 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);
+                       code = buf;
 
-#ifdef __x86_64__
-       emit_zero_bytes (acfg, (int)(acfg->plt_offset * sizeof (gpointer)));
-#endif 
+                       if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->orig_method)->ret))
+                               this_pos = 1;
 
-       symbol = g_strdup_printf ("plt_jump_table_end");
+                       ARM_ADD_REG_IMM8 (code, this_pos, this_pos, sizeof (MonoObject));
+
+                       emit_bytes (acfg, buf, code - buf);
+                       /* jump to method */
+#if defined(USE_BIN_WRITER)
+                       /* FIXME: */
+                       g_assert_not_reached ();
+#endif
+                       fprintf (acfg->fp, "\n\tb %s\n", call_target);
+               }
+#else
+               g_assert_not_reached ();
+#endif
+       }
+
+       symbol = g_strdup_printf ("trampolines_info");
+
+       emit_section_change (acfg, ".text", 0);
+       emit_global (acfg, symbol, TRUE);
+       emit_alignment (acfg, PAGESIZE);
        emit_label (acfg, symbol);
+
+       emit_int32 (acfg, acfg->num_aot_trampolines);
+       emit_int32 (acfg, acfg->got_offset);
 }
 
 static gboolean
@@ -2488,48 +3235,93 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->write_symbols = TRUE;
                } else if (str_begins_with (arg, "metadata-only")) {
                        opts->metadata_only = TRUE;
+               } else if (str_begins_with (arg, "bind-to-runtime-version")) {
+                       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
+add_token_info_hash (gpointer key, gpointer value, gpointer user_data)
+{
+       MonoMethod *method = (MonoMethod*)key;
+       MonoJumpInfoToken *ji = (MonoJumpInfoToken*)value;
+       MonoJumpInfoToken *new_ji = g_new0 (MonoJumpInfoToken, 1);
+       MonoAotCompile *acfg = user_data;
+
+       new_ji->image = ji->image;
+       new_ji->token = ji->token;
+       g_hash_table_insert (acfg->token_info_hash, method, new_ji);
 }
 
 static void
-compile_method (MonoAotCompile *acfg, int index)
+compile_method (MonoAotCompile *acfg, MonoMethod *method)
 {
        MonoCompile *cfg;
-       MonoMethod *method;
        MonoJumpInfo *patch_info;
        gboolean skip;
-       guint32 token = MONO_TOKEN_METHOD_DEF | (index + 1);
-       guint32 method_idx;
+       int index;
 
        if (acfg->aot_opts.metadata_only)
                return;
 
-       method = mono_get_method (acfg->image, token, NULL);
+       index = get_method_index (acfg, method);
 
-       method_idx = mono_metadata_token_index (method->token); 
-               
        /* fixme: maybe we can also precompile wrapper methods */
-       if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
-               (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+       if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
                (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
                (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
                //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
                return;
        }
 
+       if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
+               return;
+
        acfg->stats.mcount++;
 
-       /* fixme: we need to patch the IP for the LMF in that case */
-       if (method->save_lmf) {
-               //printf ("Skip (needs lmf):  %s\n", mono_method_full_name (method, TRUE));
-               acfg->stats.lmfcount++;
+       if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
+               /* 
+                * FIXME: Enabling this causes virtual-sync.exe to fail, since the trampoline
+                * code can't determine that it needs to insert a sync wrapper in the AOT case.
+                */
                return;
        }
 
+       //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;
+
        /*
         * Since these methods are the only ones which are compiled with
         * AOT support, and they are not used by runtime startup/shutdown code,
@@ -2537,6 +3329,11 @@ compile_method (MonoAotCompile *acfg, int index)
         * does not need to support them by creating a fake GOT etc.
         */
        cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), FALSE, TRUE, 0);
+       if (cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
+               //printf ("F: %s\n", mono_method_full_name (method, TRUE));
+               acfg->stats.genericcount ++;
+               return;
+       }
        if (cfg->exception_type != MONO_EXCEPTION_NONE) {
                /* Let the exception happen at runtime */
                return;
@@ -2549,52 +3346,49 @@ compile_method (MonoAotCompile *acfg, int index)
                return;
        }
 
-       skip = FALSE;
+       /* Nullify patches which need no aot processing */
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
-               if (patch_info->type == MONO_PATCH_INFO_ABS) {
-                       /* unable to handle this */
-                       //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
-                       skip = TRUE;    
+               switch (patch_info->type) {
+               case MONO_PATCH_INFO_LABEL:
+               case MONO_PATCH_INFO_BB:
+                       patch_info->type = MONO_PATCH_INFO_NONE;
+                       break;
+               default:
                        break;
                }
        }
 
-       if (skip) {
-               acfg->stats.abscount++;
-               mono_destroy_compile (cfg);
-               return;
-       }
+       /* Collect method->token associations from the cfg */
+       g_hash_table_foreach (cfg->token_info_hash, add_token_info_hash, acfg);
 
        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;
+               switch (patch_info->type) {
+               case MONO_PATCH_INFO_ABS:
+                       /* unable to handle this */
+                       //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
+                       skip = TRUE;    
+                       break;
+               default:
                        break;
                }
        }
 
        if (skip) {
-               acfg->stats.ocount++;
+               acfg->stats.abscount++;
                mono_destroy_compile (cfg);
                return;
        }
 
-       /* some wrappers are very common */
+       /* 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_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:
                        case MONO_WRAPPER_LDFLD:
                        case MONO_WRAPPER_LDFLDA:
@@ -2603,39 +3397,55 @@ compile_method (MonoAotCompile *acfg, int index)
                        case MONO_WRAPPER_STELEMREF:
                        case MONO_WRAPPER_ISINST:
                        case MONO_WRAPPER_PROXY_ISINST:
+                       case MONO_WRAPPER_ALLOC:
+                       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->token)
-                               /*
-                                * The method is part of a constructed type like Int[,].Set (). It doesn't
-                                * have a token, and we can't make one, since the parent type is part of
-                                * assembly which contains the element type, and not the assembly which
-                                * referenced this type.
+                       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.
                                 */
-                               skip = TRUE;
+                               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:
+               case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
                case MONO_PATCH_INFO_CLASS:
                case MONO_PATCH_INFO_IID:
                case MONO_PATCH_INFO_ADJUSTED_IID:
                        if (!patch_info->data.klass->type_token)
-                               if (!patch_info->data.klass->element_class->type_token)
+                               if (!patch_info->data.klass->element_class->type_token && !(patch_info->data.klass->element_class->rank && patch_info->data.klass->element_class->element_class->type_token))
                                        skip = TRUE;
                        break;
                default:
@@ -2644,7 +3454,7 @@ compile_method (MonoAotCompile *acfg, int index)
        }
 
        if (skip) {
-               acfg->stats.wrappercount++;
+               acfg->stats.ocount++;
                mono_destroy_compile (cfg);
                return;
        }
@@ -2652,26 +3462,22 @@ compile_method (MonoAotCompile *acfg, int index)
        /* Determine whenever the method has GOT slots */
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                switch (patch_info->type) {
-               case MONO_PATCH_INFO_LABEL:
-               case MONO_PATCH_INFO_BB:
                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_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:
-                       acfg->has_got_slots [method_idx] = TRUE;
+                       if (!is_plt_patch (patch_info))
+                               cfg->has_got_slots = TRUE;
                        break;
                }
        }
 
-       if (!acfg->has_got_slots [method_idx])
+       if (!cfg->has_got_slots)
                acfg->stats.methods_without_got_slots ++;
 
        /* Make a copy of the patch info which is in the mempool */
@@ -2706,7 +3512,7 @@ compile_method (MonoAotCompile *acfg, int index)
 
        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++;
 }
@@ -2719,18 +3525,22 @@ load_profile_files (MonoAotCompile *acfg)
        int file_index, res, method_index, i;
        char ver [256];
        guint32 token;
+       GList *unordered;
 
        file_index = 0;
        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 ++;
 
@@ -2755,10 +3565,16 @@ load_profile_files (MonoAotCompile *acfg)
        }
 
        /* Add missing methods */
+       unordered = NULL;
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
                if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (i)))
-                       acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (i));
-       }               
+                       unordered = g_list_prepend (unordered, GUINT_TO_POINTER (i));
+       }
+       unordered = g_list_reverse (unordered);
+       if (acfg->method_order)
+               g_list_last (acfg->method_order)->next = unordered;
+       else
+               acfg->method_order = unordered;
 }
 
 /**
@@ -2788,21 +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:
+                               if (is_shared_got_patch (ji))
                                        get_shared_got_offset (acfg, ji);
-                                       break;
-                               default:
-                                       break;
-                               }
                        }
                }
        }
@@ -2820,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);
@@ -2833,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->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+       for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
-                       symbol = g_strdup_printf (".Lm_%x", i + 1);
+                       symbol = g_strdup_printf (".Lm_%x", i);
                        emit_symbol_diff (acfg, symbol, "methods", 0);
+                       g_free (symbol);
                } else {
                        emit_int32 (acfg, 0xffffffff);
                }
@@ -2864,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);
@@ -2881,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->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+       for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
-                       symbol = g_strdup_printf (".Lm_%x_p", i + 1);
+                       symbol = g_strdup_printf (".Lm_%x_p", i);
                        emit_symbol_diff (acfg, symbol, "mi", 0);
+                       g_free (symbol);
                } else {
                        emit_int32 (acfg, 0);
                }
@@ -2893,6 +3704,44 @@ emit_info (MonoAotCompile *acfg)
        emit_line (acfg);
 }
 
+static void
+emit_wrapper_info (MonoAotCompile *acfg)
+{
+       int i, index;
+       char *symbol;
+       char *name;
+
+       /* Emit method info */
+       symbol = g_strdup_printf ("wrapper_info");
+       emit_section_change (acfg, ".text", 1);
+       emit_global (acfg, symbol, FALSE);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+       g_free (symbol);
+
+       if (!acfg->aot_opts.full_aot)
+               return;
+
+       for (i = 0; i < acfg->nmethods; ++i) {
+               MonoCompile *cfg = acfg->cfgs [i];
+
+               if (!cfg || !cfg->orig_method->wrapper_type)
+                       continue;
+
+               index = get_method_index (acfg, cfg->orig_method);
+
+               // FIXME: Optimize disk usage and lookup speed
+               name = mono_method_full_name (cfg->orig_method, TRUE);
+               emit_string (acfg, name);
+               emit_alignment (acfg, 4);
+               emit_int32 (acfg, index);
+       }
+
+       emit_byte (acfg, 0);
+
+       emit_line (acfg);
+}      
+
 static void
 emit_method_order (MonoAotCompile *acfg)
 {
@@ -2905,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;
@@ -2938,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
@@ -2951,12 +3802,14 @@ 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 generate assembly */
+       /* To reduce size of generated assembly */
        symbol = g_strdup_printf ("ex");
        emit_label (acfg, symbol);
+       g_free (symbol);
 
-       for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+       for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i])
                        emit_exception_debug_info (acfg, acfg->cfgs [i]);
        }
@@ -2966,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->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+       for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
-                       symbol = g_strdup_printf (".Le_%x_p", i + 1);
+                       symbol = g_strdup_printf (".Le_%x_p", i);
                        emit_symbol_diff (acfg, symbol, "ex", 0);
+                       g_free (symbol);
                } else {
                        emit_int32 (acfg, 0);
                }
@@ -2989,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));
@@ -2998,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);
 }
@@ -3032,10 +3890,9 @@ emit_class_name_table (MonoAotCompile *acfg)
        for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
                token = MONO_TOKEN_TYPE_DEF | (i + 1);
                klass = mono_class_get (acfg->image, token);
-               full_name = mono_type_get_full_name (klass);
+               full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
                hash = g_str_hash (full_name) % table_size;
-
-               //printf ("A: '%s' %d %d\n", full_name, g_str_hash (full_name), hash);
+               g_free (full_name);
 
                /* FIXME: Allocate from the mempool */
                new_entry = g_new0 (ClassNameTableEntry, 1);
@@ -3061,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);
@@ -3098,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);
@@ -3148,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);
@@ -3161,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);
 
@@ -3170,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]);
@@ -3187,8 +4049,9 @@ emit_got (MonoAotCompile *acfg)
        emit_section_change (acfg, ".bss", 1);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
-       if (acfg->got_offset > 0)
-               emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
+       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);
@@ -3196,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);
@@ -3203,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
@@ -3217,6 +4082,142 @@ emit_globals (MonoAotCompile *acfg)
        opts_str = g_strdup_printf ("%d", acfg->opts);
        emit_string_symbol (acfg, "mono_aot_opt_flags", opts_str);
        g_free (opts_str);
+
+       emit_string_symbol (acfg, "mono_aot_full_aot", acfg->aot_opts.full_aot ? "TRUE" : "FALSE");
+
+       if (acfg->aot_opts.bind_to_runtime_version)
+               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
@@ -3224,20 +4225,23 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 {
        MonoImage *image = ass->image;
        char *symbol;
-       int i;
+       int i, res;
        MonoAotCompile *acfg;
-       MonoCompile **cfgs;
 
        printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
 
        acfg = g_new0 (MonoAotCompile, 1);
+       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 = 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_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 ();
@@ -3246,28 +4250,45 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        load_profile_files (acfg);
 
-       if (mono_defaults.generic_nullable_class) {
-               /* 
-                * FIXME: Its hard to skip generic methods or methods which use generics.
-                */
-               printf ("Error: Can't AOT Net 2.0 assemblies.\n");
-               return 1;
+       emit_start (acfg);
+
+       acfg->num_aot_trampolines = acfg->aot_opts.full_aot ? 10240 : 0;
+
+       acfg->method_index = 1;
+
+       /* Collect methods */
+       for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoMethod *method;
+               guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+
+               method = mono_get_method (acfg->image, token, NULL);
+
+               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, TRUE);
+                       method = wrapper;
+               }
+
+               /* Since we add the normal methods first, their index will be equal to their zero based token index */
+               add_method_with_index (acfg, method, i);
+               acfg->method_index ++;
        }
 
-       emit_start (acfg);
+       if (acfg->aot_opts.full_aot)
+               add_wrappers (acfg);
 
-       cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
-       acfg->cfgs = cfgs;
-       acfg->nmethods = image->tables [MONO_TABLE_METHOD].rows;
-       acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
-       acfg->has_got_slots = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows + 32);
+       acfg->nmethods = acfg->methods->len + 1;
+       acfg->cfgs = g_new0 (MonoCompile*, acfg->nmethods + 32);
+       acfg->method_got_offsets = g_new0 (guint32, acfg->nmethods + 32);
 
        /* PLT offset 0 is reserved for the PLT trampoline */
        acfg->plt_offset = 1;
 
        /* Compile methods */
-       for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i)
-               compile_method (acfg, i);
+       for (i = 0; i < acfg->methods->len; ++i) {
+               compile_method (acfg, g_ptr_array_index (acfg->methods, i));
+       }
 
        alloc_got_slots (acfg);
 
@@ -3275,8 +4296,12 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        emit_info (acfg);
 
+       emit_wrapper_info (acfg);
+
        emit_method_order (acfg);
 
+       emit_trampolines (acfg);
+
        emit_class_name_table (acfg);
 
        emit_got_info (acfg);
@@ -3298,24 +4323,37 @@ 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)));
 
-       emit_writeout (acfg);
+       res = emit_writeout (acfg);
+       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 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);
 
        printf ("GOT slot distribution:\n");
        for (i = 0; i < MONO_PATCH_INFO_NONE; ++i)
                if (acfg->stats.got_slot_types [i])
-                       printf ("\t%s: %d\n", patch_types [i], 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;
 }