2010-01-18 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-compiler.c
index 41cacebd6f4f6799a29850520a4efa614de4a6ad..cb1fc0e368fe3344632c5ef0d9ddc5fd7c158e25 100644 (file)
@@ -9,8 +9,6 @@
  */
 
 /* Remaining AOT-only work:
- * - reduce the length of the wrapper names.
- * - 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.
@@ -23,7 +21,6 @@
  *   - every shared method has a MonoGenericJitInfo structure which is only really
  *     used for handling catch clauses with open types, not a very common use case.
  */
-
 #include "config.h"
 #include <sys/types.h>
 #ifdef HAVE_UNISTD_H
@@ -35,7 +32,7 @@
 #include <fcntl.h>
 #include <ctype.h>
 #include <string.h>
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
 #include <sys/time.h>
 #else
 #include <winsock2.h>
@@ -45,6 +42,7 @@
 #include <errno.h>
 #include <sys/stat.h>
 
+
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/class.h>
 #include <mono/metadata/object.h>
@@ -74,7 +72,7 @@
 #define TV_GETTIME(tv) tv = mono_100ns_ticks ()
 #define TV_ELAPSED(start,end) (((end) - (start)) / 10)
 
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
 #define SHARED_EXT ".dll"
 #elif defined(__ppc__) && defined(__MACH__)
 #define SHARED_EXT ".dylib"
@@ -98,16 +96,21 @@ typedef struct MonoAotOptions {
        gboolean asm_only;
        gboolean asm_writer;
        gboolean nodebug;
+       gboolean soft_debug;
        int nthreads;
        int ntrampolines;
+       int nrgctx_trampolines;
        gboolean print_skipped_methods;
+       gboolean stats;
+       char *tool_prefix;
+       gboolean autoreg;
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
        int ccount, mcount, lmfcount, abscount, gcount, ocount, genericcount;
-       int code_size, info_size, ex_info_size, unwind_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;
+       int code_size, info_size, ex_info_size, unwind_info_size, got_size, class_info_size, got_info_size;
+       int methods_without_got_slots, direct_calls, all_calls, llvm_count;
+       int got_slots, offsets_size;
        int got_slot_types [MONO_PATCH_INFO_NONE];
        int jit_time, gen_time, link_time;
 } MonoAotStats;
@@ -116,11 +119,13 @@ typedef struct MonoAotCompile {
        MonoImage *image;
        GPtrArray *methods;
        GHashTable *method_indexes;
+       GHashTable *method_depth;
        MonoCompile **cfgs;
        int cfgs_size;
        GHashTable *patch_to_plt_offset;
        GHashTable *plt_offset_to_patch;
        GHashTable *patch_to_got_offset;
+       GHashTable **patch_to_got_offset_by_type;
        GPtrArray *got_patches;
        GHashTable *image_hash;
        GHashTable *method_to_cfg;
@@ -131,6 +136,7 @@ typedef struct MonoAotCompile {
        GList *method_order;
        guint32 *plt_got_info_offsets;
        guint32 got_offset, plt_offset, plt_got_offset_base;
+       guint32 final_got_size;
        /* Number of GOT entries reserved for trampolines */
        guint32 num_trampoline_got_entries;
 
@@ -156,13 +162,21 @@ typedef struct MonoAotCompile {
        GPtrArray *unwind_ops;
        guint32 unwind_info_offset;
        char *got_symbol;
+       char *plt_symbol;
        GHashTable *method_label_hash;
        const char *temp_prefix;
+       guint32 label_generator;
+       gboolean llvm;
+       MonoAotFileFlags flags;
+       MonoDynamicStream blob;
 } MonoAotCompile;
 
 #define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
 #define mono_acfg_unlock(acfg) LeaveCriticalSection (&((acfg)->mutex))
 
+/* This points to the current acfg in LLVM mode */
+static MonoAotCompile *llvm_acfg;
+
 #ifdef HAVE_ARRAY_ELEM_INIT
 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
 #define MSGSTRFIELD1(line) str##line
@@ -312,11 +326,18 @@ emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
 {
        if (acfg->aot_opts.no_dlsym) {
                g_ptr_array_add (acfg->globals, g_strdup (name));
+               img_writer_emit_local_symbol (acfg->w, name, NULL, func);
        } else {
                img_writer_emit_global (acfg->w, name, func);
        }
 }
 
+static void
+emit_symbol_size (MonoAotCompile *acfg, const char *name, const char *end_label)
+{
+       img_writer_emit_symbol_size (acfg->w, name, end_label);
+}
+
 static void
 emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
 {
@@ -415,7 +436,7 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 
 /* ARCHITECTURE SPECIFIC CODE */
 
-#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM)
+#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_POWERPC)
 #define EMIT_DWARF_INFO 1
 #endif
 
@@ -424,6 +445,14 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #else
 #define AOT_FUNC_ALIGNMENT 16
 #endif
+#if defined(TARGET_POWERPC64) && !defined(__mono_ilp32__)
+#define PPC_LD_OP "ld"
+#define PPC_LDX_OP "ldx"
+#else
+#define PPC_LD_OP "lwz"
+#define PPC_LDX_OP "lwzx"
+#endif
 
 /*
  * arch_emit_direct_call:
@@ -454,11 +483,45 @@ arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size)
                fprintf (acfg->fp, "bl %s\n", target);
        }
        *call_size = 4;
+#elif defined(TARGET_POWERPC)
+       if (acfg->use_bin_writer) {
+               g_assert_not_reached ();
+       } else {
+               img_writer_emit_unset_mode (acfg->w);
+               fprintf (acfg->fp, "bl %s\n", target);
+               *call_size = 4;
+       }
 #else
        g_assert_not_reached ();
 #endif
 }
 
+/*
+ * PPC32 design:
+ * - we use an approach similar to the x86 abi: reserve a register (r30) to hold 
+ *   the GOT pointer.
+ * - The full-aot trampolines need access to the GOT of mscorlib, so we store
+ *   in in the 2. slot of every GOT, and require every method to place the GOT
+ *   address in r30, even when it doesn't access the GOT otherwise. This way,
+ *   the trampolines can compute the mscorlib GOT address by loading 4(r30).
+ */
+
+/*
+ * PPC64 design:
+ * PPC64 uses function descriptors which greatly complicate all code, since
+ * these are used very inconsistently in the runtime. Some functions like 
+ * mono_compile_method () return ftn descriptors, while others like the
+ * trampoline creation functions do not.
+ * We assume that all GOT slots contain function descriptors, and create 
+ * descriptors in aot-runtime.c when needed.
+ * The ppc64 abi uses r2 to hold the address of the TOC/GOT, which is loaded
+ * from function descriptors, we could do the same, but it would require 
+ * rewriting all the ppc/aot code to handle function descriptors properly.
+ * So instead, we use the same approach as on PPC32.
+ * This is a horrible mess, but fixing it would probably lead to an even bigger
+ * one.
+ */
+
 #ifdef MONO_ARCH_AOT_SUPPORTED
 /*
  * arch_emit_got_offset:
@@ -470,11 +533,36 @@ arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size)
 static void
 arch_emit_got_offset (MonoAotCompile *acfg, guint8 *code, int *code_size)
 {
+#if defined(TARGET_POWERPC64)
+       g_assert (!acfg->use_bin_writer);
+       img_writer_emit_unset_mode (acfg->w);
+       /* 
+        * The ppc32 code doesn't seem to work on ppc64, the assembler complains about
+        * unsupported relocations. So we store the got address into the .Lgot_addr
+        * symbol which is in the text segment, compute its address, and load it.
+        */
+       fprintf (acfg->fp, ".L%d:\n", acfg->label_generator);
+       fprintf (acfg->fp, "lis 0, (.Lgot_addr + 4 - .L%d)@h\n", acfg->label_generator);
+       fprintf (acfg->fp, "ori 0, 0, (.Lgot_addr + 4 - .L%d)@l\n", acfg->label_generator);
+       fprintf (acfg->fp, "add 30, 30, 0\n");
+       fprintf (acfg->fp, "%s 30, 0(30)\n", PPC_LD_OP);
+       acfg->label_generator ++;
+       *code_size = 16;
+#elif defined(TARGET_POWERPC)
+       g_assert (!acfg->use_bin_writer);
+       img_writer_emit_unset_mode (acfg->w);
+       fprintf (acfg->fp, ".L%d:\n", acfg->label_generator);
+       fprintf (acfg->fp, "lis 0, (%s + 4 - .L%d)@h\n", acfg->got_symbol, acfg->label_generator);
+       fprintf (acfg->fp, "ori 0, 0, (%s + 4 - .L%d)@l\n", acfg->got_symbol, acfg->label_generator);
+       acfg->label_generator ++;
+       *code_size = 8;
+#else
        guint32 offset = mono_arch_get_patch_offset (code);
        emit_bytes (acfg, code, offset);
        emit_symbol_diff (acfg, acfg->got_symbol, ".", offset);
 
        *code_size = offset + 4;
+#endif
 }
 
 /*
@@ -493,15 +581,27 @@ arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *cod
        /* Emit the offset */
 #ifdef TARGET_AMD64
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
+       *code_size = mono_arch_get_patch_offset (code) + 4;
 #elif defined(TARGET_X86)
        emit_int32 (acfg, (unsigned int) ((got_slot * sizeof (gpointer))));
+       *code_size = mono_arch_get_patch_offset (code) + 4;
 #elif defined(TARGET_ARM)
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer))) - 12);
+       *code_size = mono_arch_get_patch_offset (code) + 4;
+#elif defined(TARGET_POWERPC)
+       {
+               guint8 buf [32];
+               guint8 *code;
+
+               code = buf;
+               ppc_load32 (code, ppc_r0, got_slot * sizeof (gpointer));
+               g_assert (code - buf == 8);
+               emit_bytes (acfg, buf, code - buf);
+               *code_size = code - buf;
+       }
 #else
        g_assert_not_reached ();
 #endif
-
-       *code_size = mono_arch_get_patch_offset (code) + 4;
 }
 
 #endif
@@ -521,7 +621,7 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                } else {
                        /* Need to make sure this is 9 bytes long */
                        emit_byte (acfg, '\xe9');
-                       emit_symbol_diff (acfg, "plt", ".", -4);
+                       emit_symbol_diff (acfg, acfg->plt_symbol, ".", -4);
                        emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
                }
 #elif defined(TARGET_AMD64)
@@ -529,7 +629,6 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                 * We can't emit jumps because they are 32 bits only so they can't be patched.
                 * So we make indirect calls through GOT entries which are patched by the AOT 
                 * loader to point to .Lpd entries. 
-                * An x86_64 plt entry is 10 bytes long, init_plt () depends on this.
                 */
                /* jmpq *<offset>(%rip) */
                emit_byte (acfg, '\xff');
@@ -545,7 +644,6 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                 * - optimize OP_AOTCONST implementation
                 * - optimize the PLT entries
                 * - optimize SWITCH AOT implementation
-                * - implement IMT support
                 */
                code = buf;
                if (acfg->use_bin_writer && FALSE) {
@@ -571,6 +669,23 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                 * The plt_got_info_offset is computed automatically by 
                 * mono_aot_get_plt_info_offset (), so no need to save it here.
                 */
+#elif defined(TARGET_POWERPC)
+               guint32 offset = (acfg->plt_got_offset_base + index) * sizeof (gpointer);
+
+               /* The GOT address is guaranteed to be in r30 by OP_LOAD_GOTADDR */
+               g_assert (!acfg->use_bin_writer);
+               img_writer_emit_unset_mode (acfg->w);
+               fprintf (acfg->fp, "lis 11, %d@h\n", offset);
+               fprintf (acfg->fp, "ori 11, 11, %d@l\n", offset);
+               fprintf (acfg->fp, "add 11, 11, 30\n");
+               fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+               fprintf (acfg->fp, "%s 2, %d(11)\n", PPC_LD_OP, (int)sizeof (gpointer));
+               fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
+#endif
+               fprintf (acfg->fp, "mtctr 11\n");
+               fprintf (acfg->fp, "bctr\n");
+               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
 #else
                g_assert_not_reached ();
 #endif
@@ -633,6 +748,45 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
         */
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4 + 4);
        //emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4 + 8);
+#elif defined(TARGET_POWERPC)
+       guint8 buf [128];
+       guint8 *code;
+
+       *tramp_size = 4;
+       code = buf;
+
+       g_assert (!acfg->use_bin_writer);
+
+       /*
+        * PPC has no ip relative addressing, so we need to compute the address
+        * of the mscorlib got. That is slow and complex, so instead, we store it
+        * in the second got slot of every aot image. The caller already computed
+        * the address of its got and placed it into r30.
+        */
+       img_writer_emit_unset_mode (acfg->w);
+       /* Load mscorlib got address */
+       fprintf (acfg->fp, "%s 0, %d(30)\n", PPC_LD_OP, (int)sizeof (gpointer));
+       /* Load generic trampoline address */
+       fprintf (acfg->fp, "lis 11, %d@h\n", (int)(offset * sizeof (gpointer)));
+       fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)(offset * sizeof (gpointer)));
+       fprintf (acfg->fp, "%s 11, 11, 0\n", PPC_LDX_OP);
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+       fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
+#endif
+       fprintf (acfg->fp, "mtctr 11\n");
+       /* Load trampoline argument */
+       /* On ppc, we pass it normally to the generic trampoline */
+       fprintf (acfg->fp, "lis 11, %d@h\n", (int)((offset + 1) * sizeof (gpointer)));
+       fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)((offset + 1) * sizeof (gpointer)));
+       fprintf (acfg->fp, "%s 0, 11, 0\n", PPC_LDX_OP);
+       /* Branch to generic trampoline */
+       fprintf (acfg->fp, "bctr\n");
+
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+       *tramp_size = 10 * 4;
+#else
+       *tramp_size = 9 * 4;
+#endif
 #else
        g_assert_not_reached ();
 #endif
@@ -686,6 +840,16 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGeneri
        } else {
                fprintf (acfg->fp, "\n\tb %s\n", call_target);
        }
+#elif defined(TARGET_POWERPC)
+       int this_pos = 3;
+
+       if (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret))
+               this_pos = 4;
+
+       g_assert (!acfg->use_bin_writer);
+
+       fprintf (acfg->fp, "\n\taddi %d, %d, %d\n", this_pos, this_pos, (int)sizeof (MonoObject));
+       fprintf (acfg->fp, "\n\tb %s\n", call_target);
 #else
        g_assert_not_reached ();
 #endif
@@ -726,11 +890,11 @@ arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_
        *tramp_size = 24;
        code = buf;
        /* Load rgctx value */
-       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 8);
-       ARM_LDR_REG_REG (code, MONO_ARCH_RGCTX_REG, ARMREG_PC, ARMREG_R1);
+       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 8);
+       ARM_LDR_REG_REG (code, MONO_ARCH_RGCTX_REG, ARMREG_PC, ARMREG_IP);
        /* Load branch addr + branch */
-       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 4);
-       ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_R1);
+       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 4);
+       ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
 
        g_assert (code - buf == 16);
 
@@ -738,6 +902,46 @@ arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_
        emit_bytes (acfg, buf, code - buf);
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4 + 8);
        emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4 + 4);
+#elif defined(TARGET_POWERPC)
+       guint8 buf [128];
+       guint8 *code;
+
+       *tramp_size = 4;
+       code = buf;
+
+       g_assert (!acfg->use_bin_writer);
+
+       /*
+        * PPC has no ip relative addressing, so we need to compute the address
+        * of the mscorlib got. That is slow and complex, so instead, we store it
+        * in the second got slot of every aot image. The caller already computed
+        * the address of its got and placed it into r30.
+        */
+       img_writer_emit_unset_mode (acfg->w);
+       /* Load mscorlib got address */
+       fprintf (acfg->fp, "%s 0, %d(30)\n", PPC_LD_OP, (int)sizeof (gpointer));
+       /* Load rgctx */
+       fprintf (acfg->fp, "lis 11, %d@h\n", (int)(offset * sizeof (gpointer)));
+       fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)(offset * sizeof (gpointer)));
+       fprintf (acfg->fp, "%s %d, 11, 0\n", PPC_LDX_OP, MONO_ARCH_RGCTX_REG);
+       /* Load target address */
+       fprintf (acfg->fp, "lis 11, %d@h\n", (int)((offset + 1) * sizeof (gpointer)));
+       fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)((offset + 1) * sizeof (gpointer)));
+       fprintf (acfg->fp, "%s 11, 11, 0\n", PPC_LDX_OP);
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+       fprintf (acfg->fp, "%s 2, %d(11)\n", PPC_LD_OP, (int)sizeof (gpointer));
+       fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
+#endif
+       fprintf (acfg->fp, "mtctr 11\n");
+       /* Branch to the target address */
+       fprintf (acfg->fp, "bctr\n");
+
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+       *tramp_size = 11 * 4;
+#else
+       *tramp_size = 9 * 4;
+#endif
+
 #else
        g_assert_not_reached ();
 #endif
@@ -809,15 +1013,15 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
 
        /* The IMT method is in v5 */
 
-       /* Only IP is available, but we need at least two free registers */
-       ARM_PUSH1 (code, ARMREG_R1);
+       /* Need at least two free registers, plus a slot for storing the pc */
+       ARM_PUSH (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_R2));
        labels [0] = code;
        /* Load the parameter from the GOT */
-       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
-       ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_PC, ARMREG_IP);
+       ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
+       ARM_LDR_REG_REG (code, ARMREG_R0, ARMREG_PC, ARMREG_R0);
 
        labels [1] = code;
-       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_IP, 0);
+       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_R0, 0);
        ARM_CMP_REG_REG (code, ARMREG_R1, ARMREG_V5);
        labels [2] = code;
        ARM_B_COND (code, ARMCOND_EQ, 0);
@@ -828,16 +1032,19 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
        ARM_B_COND (code, ARMCOND_EQ, 0);
 
        /* Loop footer */
-       ARM_ADD_REG_IMM8 (code, ARMREG_IP, ARMREG_IP, sizeof (gpointer) * 2);
+       ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (gpointer) * 2);
        labels [4] = code;
        ARM_B (code, 0);
        arm_patch (labels [4], labels [1]);
 
        /* Match */
        arm_patch (labels [2], code);
-       ARM_POP1 (code, ARMREG_R1);
-       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, 4);
-       ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, 0);
+       ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 4);
+       ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 0);
+       /* Save it to the third stack slot */
+       ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, 8);
+       /* Restore the registers and branch */
+       ARM_POP (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_PC));
 
        /* No match */
        arm_patch (labels [3], code);
@@ -845,17 +1052,131 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
 
        /* Fixup offset */
        code2 = labels [0];
-       ARM_LDR_IMM (code2, ARMREG_IP, ARMREG_PC, (code - (labels [0] + 8)));
+       ARM_LDR_IMM (code2, ARMREG_R0, ARMREG_PC, (code - (labels [0] + 8)));
 
        emit_bytes (acfg, buf, code - buf);
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) + (code - (labels [0] + 8)) - 4);
 
        *tramp_size = code - buf + 4;
+#elif defined(TARGET_POWERPC)
+       guint8 buf [128];
+       guint8 *code, *labels [16];
+
+       code = buf;
+
+       /* Load the mscorlib got address */
+       ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
+       /* Load the parameter from the GOT */
+       ppc_load (code, ppc_r0, offset * sizeof (gpointer));
+       ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
+
+       /* Load and check key */
+       labels [1] = code;
+       ppc_ldptr (code, ppc_r0, 0, ppc_r11);
+       ppc_cmp (code, 0, sizeof (gpointer) == 8 ? 1 : 0, ppc_r0, MONO_ARCH_IMT_REG);
+       labels [2] = code;
+       ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
+
+       /* End-of-loop check */
+       ppc_cmpi (code, 0, sizeof (gpointer) == 8 ? 1 : 0, ppc_r0, 0);
+       labels [3] = code;
+       ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
+
+       /* Loop footer */
+       ppc_addi (code, ppc_r11, ppc_r11, 2 * sizeof (gpointer));
+       labels [4] = code;
+       ppc_b (code, 0);
+       mono_ppc_patch (labels [4], labels [1]);
+
+       /* Match */
+       mono_ppc_patch (labels [2], code);
+       ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r11);
+       /* r11 now contains the value of the vtable slot */
+       /* this is not a function descriptor on ppc64 */
+       ppc_ldptr (code, ppc_r11, 0, ppc_r11);
+       ppc_mtctr (code, ppc_r11);
+       ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+
+       /* Fail */
+       mono_ppc_patch (labels [3], code);
+       /* FIXME: */
+       ppc_break (code);
+
+       *tramp_size = code - buf;
+
+       emit_bytes (acfg, buf, code - buf);
 #else
        g_assert_not_reached ();
 #endif
 }
 
+static void
+arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
+{
+#if defined(TARGET_POWERPC) && defined(__mono_ilp32__)
+       /* Based on code generated by gcc */
+       img_writer_emit_unset_mode (acfg->w);
+
+       fprintf (acfg->fp,
+#if defined(_MSC_VER) || defined(MONO_CROSS_COMPILE) 
+                        ".section      .ctors,\"aw\",@progbits\n"
+                        ".align 2\n"
+                        ".globl        %s\n"
+                        ".long %s\n"
+                        ".section      .opd,\"aw\"\n"
+                        ".align 2\n"
+                        "%s:\n"
+                        ".long .%s,.TOC.@tocbase32\n"
+                        ".size %s,.-%s\n"
+                        ".section .text\n"
+                        ".type .%s,@function\n"
+                        ".align 2\n"
+                        ".%s:\n", symbol, symbol, symbol, symbol, symbol, symbol, symbol, symbol);
+#else
+                        ".section      .ctors,\"aw\",@progbits\n"
+                        ".align 2\n"
+                        ".globl        %1$s\n"
+                        ".long %1$s\n"
+                        ".section      .opd,\"aw\"\n"
+                        ".align 2\n"
+                        "%1$s:\n"
+                        ".long .%1$s,.TOC.@tocbase32\n"
+                        ".size %1$s,.-%1$s\n"
+                        ".section .text\n"
+                        ".type .%1$s,@function\n"
+                        ".align 2\n"
+                        ".%1$s:\n", symbol);
+#endif
+
+
+       fprintf (acfg->fp,
+                        "stdu 1,-128(1)\n"
+                        "mflr 0\n"
+                        "std 31,120(1)\n"
+                        "std 0,144(1)\n"
+
+                        ".Lautoreg:\n"
+                        "lis 3, .Lglobals@h\n"
+                        "ori 3, 3, .Lglobals@l\n"
+                        "bl .mono_aot_register_module\n"
+                        "ld 11,0(1)\n"
+                        "ld 0,16(11)\n"
+                        "mtlr 0\n"
+                        "ld 31,-8(11)\n"
+                        "mr 1,11\n"
+                        "blr\n"
+                        );
+#if defined(_MSC_VER) || defined(MONO_CROSS_COMPILE) 
+               fprintf (acfg->fp,
+                        ".size .%s,.-.%s\n", symbol, symbol);
+#else
+       fprintf (acfg->fp,
+                        ".size .%1$s,.-.%1$s\n", symbol);
+#endif
+#else
+#endif
+}
+
 /*
  * arch_get_cie_program:
  *
@@ -870,6 +1191,12 @@ arch_get_cie_program (void)
        mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, AMD64_RSP, 8);
        mono_add_unwind_op_offset (l, (guint8*)NULL, (guint8*)NULL, AMD64_RIP, -8);
 
+       return l;
+#elif defined(TARGET_POWERPC)
+       GSList *l = NULL;
+
+       mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
+
        return l;
 #else
        return NULL;
@@ -929,6 +1256,123 @@ encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
                *endbuf = p;
 }
 
+static void
+stream_init (MonoDynamicStream *sh)
+{
+       sh->index = 0;
+       sh->alloc_size = 4096;
+       sh->data = g_malloc (4096);
+
+       /* So offsets are > 0 */
+       sh->index ++;
+}
+
+static void
+make_room_in_stream (MonoDynamicStream *stream, int size)
+{
+       if (size <= stream->alloc_size)
+               return;
+       
+       while (stream->alloc_size <= size) {
+               if (stream->alloc_size < 4096)
+                       stream->alloc_size = 4096;
+               else
+                       stream->alloc_size *= 2;
+       }
+       
+       stream->data = g_realloc (stream->data, stream->alloc_size);
+}
+
+static guint32
+add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
+{
+       guint32 idx;
+       
+       make_room_in_stream (stream, stream->index + len);
+       memcpy (stream->data + stream->index, data, len);
+       idx = stream->index;
+       stream->index += len;
+       return idx;
+}
+
+/*
+ * add_to_blob:
+ *
+ *   Add data to the binary blob inside the aot image. Returns the offset inside the
+ * blob where the data was stored.
+ */
+static guint32
+add_to_blob (MonoAotCompile *acfg, guint8 *data, guint32 data_len)
+{
+       if (acfg->blob.alloc_size == 0)
+               stream_init (&acfg->blob);
+
+       return add_stream_data (&acfg->blob, (char*)data, data_len);
+}
+
+/*
+ * emit_offset_table:
+ *
+ *   Emit a table of increasing offsets in a compact form using differential encoding.
+ * There is an index entry for each GROUP_SIZE number of entries. The greater the
+ * group size, the more compact the table becomes, but the slower it becomes to compute
+ * a given entry. Returns the size of the table.
+ */
+static guint32
+emit_offset_table (MonoAotCompile *acfg, int noffsets, int group_size, gint32 *offsets)
+{
+       gint32 current_offset;
+       int i, buf_size, ngroups, index_entry_size;
+       guint8 *p, *buf;
+       guint32 *index_offsets;
+
+       ngroups = (noffsets + (group_size - 1)) / group_size;
+
+       index_offsets = g_new0 (guint32, ngroups);
+
+       buf_size = noffsets * 4;
+       p = buf = g_malloc0 (buf_size);
+
+       current_offset = 0;
+       for (i = 0; i < noffsets; ++i) {
+               //printf ("D: %d -> %d\n", i, offsets [i]);
+               if ((i % group_size) == 0) {
+                       index_offsets [i / group_size] = p - buf;
+                       /* Emit the full value for these entries */
+                       encode_value (offsets [i], p, &p);
+               } else {
+                       /* The offsets are allowed to be non-increasing */
+                       //g_assert (offsets [i] >= current_offset);
+                       encode_value (offsets [i] - current_offset, p, &p);
+               }
+               current_offset = offsets [i];
+       }
+
+       if (ngroups && index_offsets [ngroups - 1] < 65000)
+               index_entry_size = 2;
+       else
+               index_entry_size = 4;
+
+       /* Emit the header */
+       emit_int32 (acfg, noffsets);
+       emit_int32 (acfg, group_size);
+       emit_int32 (acfg, ngroups);
+       emit_int32 (acfg, index_entry_size);
+
+       /* Emit the index */
+       for (i = 0; i < ngroups; ++i) {
+               if (index_entry_size == 2)
+                       emit_int16 (acfg, index_offsets [i]);
+               else
+                       emit_int32 (acfg, index_offsets [i]);
+       }
+
+       /* Emit the data */
+       emit_bytes (acfg, buf, p - buf);
+
+    return (int)(p - buf) + (ngroups * 4);
+}
+
 static guint32
 get_image_index (MonoAotCompile *cfg, MonoImage *image)
 {
@@ -1106,7 +1550,9 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
        if (method->wrapper_type) {
                if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
                        char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
-                       if (mono_marshal_method_from_wrapper (method) != method) {
+                       if (strcmp (method->name, "runtime_invoke_dynamic")) {
+                               name = mono_aot_wrapper_name (method);
+                       } else if (mono_marshal_method_from_wrapper (method) != method) {
                                /* Direct wrapper, encode it normally */
                        } else {
                                name = g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method->name, tmpsig);
@@ -1306,6 +1752,7 @@ is_plt_patch (MonoJumpInfo *patch_info)
        case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
        case MONO_PATCH_INFO_MONITOR_ENTER:
        case MONO_PATCH_INFO_MONITOR_EXIT:
+       case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
                return TRUE;
        default:
                return FALSE;
@@ -1320,10 +1767,11 @@ get_plt_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
        if (is_plt_patch (patch_info)) {
                int idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info));
 
-               if (patch_info->type == MONO_PATCH_INFO_METHOD && (patch_info->data.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) {
+               // FIXME: This breaks the calculation of final_got_size         
+               if (!acfg->llvm && patch_info->type == MONO_PATCH_INFO_METHOD && (patch_info->data.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) {
                        /* 
                         * Allocate a separate PLT slot for each such patch, since some plt
-                        * entries will refer to the method itself, and some will refer to
+                        * entries will refer to the method itself, and some will refer to the
                         * wrapper.
                         */
                        idx = 0;
@@ -1334,6 +1782,8 @@ get_plt_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
                } else {
                        MonoJumpInfo *new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
 
+                       g_assert (!acfg->final_got_size);
+
                        res = acfg->plt_offset;
                        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));
@@ -1355,10 +1805,12 @@ get_got_offset (MonoAotCompile *acfg, MonoJumpInfo *ji)
 {
        guint32 got_offset;
 
-       got_offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_got_offset, ji));
+       got_offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_got_offset_by_type [ji->type], ji));
        if (got_offset)
                return got_offset - 1;
 
+       g_assert (!acfg->final_got_size);
+
        got_offset = acfg->got_offset;
        acfg->got_offset ++;
 
@@ -1366,6 +1818,7 @@ get_got_offset (MonoAotCompile *acfg, MonoJumpInfo *ji)
        acfg->stats.got_slot_types [ji->type] ++;
 
        g_hash_table_insert (acfg->patch_to_got_offset, ji, GUINT_TO_POINTER (got_offset + 1));
+       g_hash_table_insert (acfg->patch_to_got_offset_by_type [ji->type], ji, GUINT_TO_POINTER (got_offset + 1));
        g_ptr_array_add (acfg->got_patches, ji);
 
        return got_offset;
@@ -1397,7 +1850,7 @@ get_method_index (MonoAotCompile *acfg, MonoMethod *method)
 }
 
 static int
-add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra)
+add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra, int depth)
 {
        int index;
 
@@ -1411,6 +1864,8 @@ add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra)
        /* FIXME: Fix quadratic behavior */
        acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (index));
 
+       g_hash_table_insert (acfg->method_depth, method, GUINT_TO_POINTER (depth));
+
        acfg->method_index ++;
 
        return index;
@@ -1419,13 +1874,19 @@ add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra)
 static int
 add_method (MonoAotCompile *acfg, MonoMethod *method)
 {
-       return add_method_full (acfg, method, FALSE);
+       return add_method_full (acfg, method, FALSE, 0);
 }
 
 static void
 add_extra_method (MonoAotCompile *acfg, MonoMethod *method)
 {
-       add_method_full (acfg, method, TRUE);
+       add_method_full (acfg, method, TRUE, 0);
+}
+
+static void
+add_extra_method_with_depth (MonoAotCompile *acfg, MonoMethod *method, int depth)
+{
+       add_method_full (acfg, method, TRUE, depth);
 }
 
 static void
@@ -1457,11 +1918,62 @@ get_runtime_invoke_sig (MonoMethodSignature *sig)
        return mono_marshal_get_runtime_invoke (m, FALSE);
 }
 
+static gboolean
+can_marshal_struct (MonoClass *klass)
+{
+       MonoClassField *field;
+       gboolean can_marshal = TRUE;
+       gpointer iter = NULL;
+
+       if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
+               return FALSE;
+
+       /* Only allow a few field types to avoid asserts in the marshalling code */
+       while ((field = mono_class_get_fields (klass, &iter))) {
+               if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+                       continue;
+
+               switch (field->type->type) {
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
+               case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+               case MONO_TYPE_CHAR:
+               case MONO_TYPE_I8:
+               case MONO_TYPE_U8:
+               case MONO_TYPE_I:
+               case MONO_TYPE_U:
+               case MONO_TYPE_PTR:
+               case MONO_TYPE_R4:
+               case MONO_TYPE_R8:
+               case MONO_TYPE_STRING:
+                       break;
+               case MONO_TYPE_VALUETYPE:
+                       if (!can_marshal_struct (mono_class_from_mono_type (field->type)))
+                               can_marshal = FALSE;
+                       break;
+               default:
+                       can_marshal = FALSE;
+                       break;
+               }
+       }
+
+       /* Special cases */
+       /* Its hard to compute whenever these can be marshalled or not */
+       if (!strcmp (klass->name_space, "System.Net.NetworkInformation.MacOsStructs"))
+               return TRUE;
+
+       return can_marshal;
+}
+
 static void
 add_wrappers (MonoAotCompile *acfg)
 {
        MonoMethod *method, *m;
-       int i, j, nallocators;
+       int i, j;
        MonoMethodSignature *sig, *csig;
        guint32 token;
 
@@ -1476,62 +1988,6 @@ add_wrappers (MonoAotCompile *acfg)
         * 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));
-
-       /* runtime-invoke used by finalizers */
-       add_method (acfg, mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE));
-
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
                MonoMethod *method;
                guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
@@ -1558,18 +2014,108 @@ add_wrappers (MonoAotCompile *acfg)
                                skip = TRUE;
                }
 
-               if (!skip)
+#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
+               if (!method->klass->contextbound) {
+                       MonoDynCallInfo *info = mono_arch_dyn_call_prepare (sig);
+                       gboolean has_nullable = FALSE;
+
+                       for (j = 0; j < sig->param_count; j++) {
+                               if (sig->params [j]->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (sig->params [j])))
+                                       has_nullable = TRUE;
+                       }
+
+                       if (info && !has_nullable) {
+                               /* Supported by the dynamic runtime-invoke wrapper */
+                               skip = TRUE;
+                               g_free (info);
+                       }
+               }
+#endif
+
+               if (!skip) {
+                       //printf ("%s\n", mono_method_full_name (method, TRUE));
                        add_method (acfg, mono_marshal_get_runtime_invoke (method, FALSE));
-       }
+               }
+       }
 
        if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
+#ifdef MONO_ARCH_HAVE_TLS_GET
                MonoMethodDesc *desc;
                MonoMethod *orig_method;
+               int nallocators;
+#endif
+
+               /* 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));
+
+               /* runtime-invoke used by finalizers */
+               add_method (acfg, mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE));
+
+               /* This is used by mono_runtime_capture_context () */
+               method = mono_get_context_capture_method ();
+               if (method)
+                       add_method (acfg, mono_marshal_get_runtime_invoke (method, FALSE));
+
+#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
+               add_method (acfg, mono_marshal_get_runtime_invoke_dynamic ());
+#endif
 
                /* JIT icall wrappers */
                /* FIXME: locking */
                g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper, acfg);
 
+               /* stelemref */
+               add_method (acfg, mono_marshal_get_stelemref ());
+
+#ifdef MONO_ARCH_HAVE_TLS_GET
                /* Managed Allocators */
                nallocators = mono_gc_get_managed_allocator_types ();
                for (i = 0; i < nallocators; ++i) {
@@ -1578,9 +2124,6 @@ add_wrappers (MonoAotCompile *acfg)
                                add_method (acfg, m);
                }
 
-               /* stelemref */
-               add_method (acfg, mono_marshal_get_stelemref ());
-
                /* Monitor Enter/Exit */
                desc = mono_method_desc_new ("Monitor:Enter", FALSE);
                orig_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
@@ -1597,6 +2140,7 @@ add_wrappers (MonoAotCompile *acfg)
                method = mono_monitor_get_fast_path (orig_method);
                if (method)
                        add_method (acfg, method);
+#endif
        }
 
        /* 
@@ -1649,7 +2193,7 @@ add_wrappers (MonoAotCompile *acfg)
                token = MONO_TOKEN_METHOD_DEF | (i + 1);
                method = mono_get_method (acfg->image, token, NULL);
 
-               if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+               if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED && !method->is_generic)
                        add_method (acfg, mono_marshal_get_synchronized_wrapper (method));
        }
 
@@ -1673,40 +2217,9 @@ add_wrappers (MonoAotCompile *acfg)
                token = MONO_TOKEN_TYPE_DEF | (i + 1);
                klass = mono_class_get (acfg->image, token);
 
-               if (klass->valuetype && !klass->generic_container && ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)) {
-                       MonoMarshalType *info;
-                       gboolean can_marshal = TRUE;
-                       int j;
-
-                       info = mono_marshal_load_type_info (klass);
-
-                       /* Only allow a few field types to avoid asserts in the marshalling code */
-                       for (j = 0; j < info->num_fields; j++) {
-                               switch (info->fields [j].field->type->type) {
-                               case MONO_TYPE_I4:
-                               case MONO_TYPE_U4:
-                               case MONO_TYPE_I1:
-                               case MONO_TYPE_U1:
-                               case MONO_TYPE_BOOLEAN:
-                               case MONO_TYPE_I2:
-                               case MONO_TYPE_U2:
-                               case MONO_TYPE_CHAR:
-                               case MONO_TYPE_I8:
-                               case MONO_TYPE_U8:
-                               case MONO_TYPE_PTR:
-                               case MONO_TYPE_R4:
-                               case MONO_TYPE_R8:
-                                       break;
-                               default:
-                                       can_marshal = FALSE;
-                                       break;
-                               }
-                       }
-
-                       if (can_marshal) {
-                               add_method (acfg, mono_marshal_get_struct_to_ptr (klass));
-                               add_method (acfg, mono_marshal_get_ptr_to_struct (klass));
-                       }
+               if (klass->valuetype && !klass->generic_container && can_marshal_struct (klass)) {
+                       add_method (acfg, mono_marshal_get_struct_to_ptr (klass));
+                       add_method (acfg, mono_marshal_get_ptr_to_struct (klass));
                }
        }
 }
@@ -1789,13 +2302,20 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
                add_extra_method (acfg, method);
        }
 
+       if (klass->delegate) {
+               method = mono_get_delegate_invoke (klass);
+
+               method = mono_marshal_get_delegate_invoke (method, NULL);
+
+               add_method (acfg, method);
+       }
+
        /* 
-        * For ICollection<T>, where T is a vtype, add instances of the helper methods
+        * For ICollection<T>, add instances of the helper methods
         * in Array, since a T[] could be cast to ICollection<T>.
         */
        if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") &&
-               (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1")) &&
-               MONO_TYPE_ISSTRUCT (klass->generic_class->context.class_inst->type_argv [0])) {
+               (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1"))) {
                MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
                MonoClass *array_class = mono_bounded_array_class_get (tclass, 1, FALSE);
                gpointer iter;
@@ -1822,12 +2342,51 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
 
                iter = NULL;
                while ((method = mono_class_get_methods (array_class, &iter))) {
-                       if (strstr (method->name, name_prefix))
-                               add_extra_method (acfg, method);
+                       if (strstr (method->name, name_prefix)) {
+                               MonoMethod *m = mono_aot_get_array_helper_from_wrapper (method);
+                               add_extra_method (acfg, m);
+                       }
                }
 
                g_free (name_prefix);
        }
+
+       /* Add an instance of GenericComparer<T> which is created dynamically by Comparer<T> */
+       if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "Comparer`1")) {
+               MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+               MonoClass *icomparable, *gcomparer;
+               MonoGenericContext ctx;
+               MonoType *args [16];
+
+               memset (&ctx, 0, sizeof (ctx));
+
+               icomparable = mono_class_from_name (mono_defaults.corlib, "System", "IComparable`1");
+               g_assert (icomparable);
+               args [0] = &tclass->byval_arg;
+               ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+
+               if (mono_class_is_assignable_from (mono_class_inflate_generic_class (icomparable, &ctx), tclass)) {
+                       gcomparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "GenericComparer`1");
+                       g_assert (gcomparer);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (gcomparer, &ctx));
+               }
+       }
+}
+
+static void
+add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int ninsts)
+{
+       int i;
+       MonoGenericContext ctx;
+       MonoType *args [16];
+
+       memset (&ctx, 0, sizeof (ctx));
+
+       for (i = 0; i < ninsts; ++i) {
+               args [0] = insts [i];
+               ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+               add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+       }
 }
 
 /*
@@ -1898,6 +2457,93 @@ add_generic_instances (MonoAotCompile *acfg)
                                        add_generic_class (acfg, mono_class_from_mono_type (header->locals [j]));
                }
        }
+
+       if (acfg->image == mono_defaults.corlib) {
+               MonoClass *klass;
+               MonoType *insts [256];
+               int ninsts = 0;
+
+               insts [ninsts ++] = &mono_defaults.byte_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.sbyte_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.int16_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.uint16_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.int32_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.uint32_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.int64_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.uint64_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.single_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.double_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.char_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.boolean_class->byval_arg;
+
+               /* Add GenericComparer<T> instances for primitive types for Enum.ToString () */
+               klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
+               if (klass)
+                       add_instances_of (acfg, klass, insts, ninsts);
+               klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericEqualityComparer`1");
+               if (klass)
+                       add_instances_of (acfg, klass, insts, ninsts);
+
+               /* Add instances of the array generic interfaces for primitive types */
+               /* This will add instances of the InternalArray_ helper methods in Array too */
+               klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "ICollection`1");
+               if (klass)
+                       add_instances_of (acfg, klass, insts, ninsts);
+               klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "IList`1");
+               if (klass)
+                       add_instances_of (acfg, klass, insts, ninsts);
+               klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "IEnumerable`1");
+               if (klass)
+                       add_instances_of (acfg, klass, insts, ninsts);
+
+               /* 
+                * Add a managed-to-native wrapper of Array.GetGenericValueImpl<object>, which is
+                * used for all instances of GetGenericValueImpl by the AOT runtime.
+                */
+               {
+                       MonoGenericContext ctx;
+                       MonoType *args [16];
+                       MonoMethod *get_method;
+                       MonoClass *array_klass = mono_array_class_get (mono_defaults.object_class, 1)->parent;
+
+                       get_method = mono_class_get_method_from_name (array_klass, "GetGenericValueImpl", 2);
+
+                       if (get_method) {
+                               memset (&ctx, 0, sizeof (ctx));
+                               args [0] = &mono_defaults.object_class->byval_arg;
+                               ctx.method_inst = mono_metadata_get_generic_inst (1, args);
+                               add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (get_method, &ctx), TRUE, TRUE));
+                       }
+               }
+       }
+}
+
+/*
+ * is_direct_callable:
+ *
+ *   Return whenever the method identified by JI is directly callable without 
+ * going through the PLT.
+ */
+static gboolean
+is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patch_info)
+{
+       if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == acfg->image)) {
+               MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
+               if (callee_cfg) {
+                       gboolean direct_callable = TRUE;
+
+                       if (direct_callable && !(!callee_cfg->has_got_slots && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
+                               direct_callable = FALSE;
+                       if ((callee_cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) && (!method || method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED))
+                               // FIXME: Maybe call the wrapper directly ?
+                               direct_callable = FALSE;
+
+                       if (direct_callable)
+                               return TRUE;
+               }
+       }
+
+       return FALSE;
 }
 
 /*
@@ -1954,6 +2600,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                arch_emit_got_offset (acfg, code + i, &code_size);
                                i += code_size - 1;
                                skip = TRUE;
+                               patch_info->type = MONO_PATCH_INFO_NONE;
                                break;
                        }
                        default: {
@@ -1963,23 +2610,14 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                 * the same assembly and requires no initialization.
                                 */
                                direct_call = FALSE;
-                               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) {
-                                               gboolean direct_callable = TRUE;
-
-                                               if (direct_callable && !(!callee_cfg->has_got_slots && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
-                                                       direct_callable = FALSE;
-                                               if ((callee_cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) && method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
-                                                       // FIXME: Maybe call the wrapper directly ?
-                                                       direct_callable = FALSE;
-                                               if (direct_callable) {
-                                                       //printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
-                                                       direct_call = TRUE;
-                                                       sprintf (direct_call_target, "%sm_%x", acfg->temp_prefix, get_method_index (acfg, callee_cfg->orig_method));
-                                                       patch_info->type = MONO_PATCH_INFO_NONE;
-                                                       acfg->stats.direct_calls ++;
-                                               }
+                               if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == acfg->image)) {
+                                       if (!got_only && is_direct_callable (acfg, method, patch_info)) {
+                                               MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
+                                               //printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
+                                               direct_call = TRUE;
+                                               sprintf (direct_call_target, "%sm_%x", acfg->temp_prefix, get_method_index (acfg, callee_cfg->orig_method));
+                                               patch_info->type = MONO_PATCH_INFO_NONE;
+                                               acfg->stats.direct_calls ++;
                                        }
 
                                        acfg->stats.all_calls ++;
@@ -2036,12 +2674,67 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
        }
 }
 
+/*
+ * sanitize_symbol:
+ *
+ *   Modify SYMBOL so it only includes characters permissible in symbols.
+ */
+static void
+sanitize_symbol (char *symbol)
+{
+       int i, len = strlen (symbol);
+
+       for (i = 0; i < len; ++i)
+               if (!isalnum (symbol [i]) && (symbol [i] != '_'))
+                       symbol [i] = '_';
+}
+
+static char*
+get_debug_sym (MonoMethod *method, const char *prefix, GHashTable *cache)
+{
+       char *name1, *name2, *cached;
+       int i, j, len, count;
+               
+       name1 = mono_method_full_name (method, TRUE);
+       len = strlen (name1);
+       name2 = malloc (strlen (prefix) + len + 16);
+       memcpy (name2, prefix, strlen (prefix));
+       j = strlen (prefix);
+       for (i = 0; i < len; ++i) {
+               if (isalnum (name1 [i])) {
+                       name2 [j ++] = name1 [i];
+               } else if (name1 [i] == ' ' && name1 [i + 1] == '(' && name1 [i + 2] == ')') {
+                       i += 2;
+               } else if (name1 [i] == ',' && name1 [i + 1] == ' ') {
+                       name2 [j ++] = '_';
+                       i++;
+               } else if (name1 [i] == '(' || name1 [i] == ')' || name1 [i] == '>') {
+               } else
+                       name2 [j ++] = '_';
+       }
+       name2 [j] = '\0';
+
+       g_free (name1);
+
+       count = 0;
+       while (g_hash_table_lookup (cache, name2)) {
+               sprintf (name2 + j, "_%d", count);
+               count ++;
+       }
+
+       cached = g_strdup (name2);
+       g_hash_table_insert (cache, cached, cached);
+
+       return name2;
+}
+
 static void
 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
 {
        MonoMethod *method;
        int method_index;
        guint8 *code;
+       char *debug_sym = NULL;
        char symbol [128];
        int func_alignment = AOT_FUNC_ALIGNMENT;
        MonoMethodHeader *header;
@@ -2075,51 +2768,22 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        /* Make the labels local */
        sprintf (symbol, "%sm_%x", acfg->temp_prefix, method_index);
 
+       emit_section_change (acfg, ".text", 0);
        emit_alignment (acfg, func_alignment);
        emit_label (acfg, symbol);
 
        if (acfg->aot_opts.write_symbols) {
-               char *name1, *name2, *cached;
-               int i, j, len, count;
-
                /* 
                 * Write a C style symbol for every method, this has two uses:
                 * - it works on platforms where the dwarf debugging info is not
                 *   yet supported.
                 * - it allows the setting of breakpoints of aot-ed methods.
                 */
-               name1 = mono_method_full_name (method, TRUE);
-               len = strlen (name1);
-               name2 = malloc (len + 1);
-               j = 0;
-               for (i = 0; i < len; ++i) {
-                       if (isalnum (name1 [i])) {
-                               name2 [j ++] = name1 [i];
-                       } else if (name1 [i] == ' ' && name1 [i + 1] == '(' && name1 [i + 2] == ')') {
-                               i += 2;
-                       } else if (name1 [i] == ',' && name1 [i + 1] == ' ') {
-                               name2 [j ++] = '_';
-                               i++;
-                       } else if (name1 [i] == '(' || name1 [i] == ')' || name1 [i] == '>') {
-                       } else
-                               name2 [j ++] = '_';
-               }
-               name2 [j] = '\0';
-
-               count = 0;
-               while (g_hash_table_lookup (acfg->method_label_hash, name2)) {
-                       sprintf (name2 + j, "_%d", count);
-                       count ++;
-               }
-
-               cached = g_strdup (name2);
-               g_hash_table_insert (acfg->method_label_hash, cached, cached);
+               debug_sym = get_debug_sym (method, "", acfg->method_label_hash);
 
                sprintf (symbol, "%sme_%x", acfg->temp_prefix, method_index);
-               emit_local_symbol (acfg, name2, symbol, TRUE);
-               emit_label (acfg, name2);
-               g_free (name1);
-               g_free (name2);
+               emit_local_symbol (acfg, debug_sym, symbol, TRUE);
+               emit_label (acfg, debug_sym);
        }
 
        if (cfg->verbose_level > 0)
@@ -2133,6 +2797,11 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
 
        emit_line (acfg);
 
+       if (acfg->aot_opts.write_symbols) {
+               emit_symbol_size (acfg, debug_sym, ".");
+               g_free (debug_sym);
+       }
+
        sprintf (symbol, "%sme_%x", acfg->temp_prefix, method_index);
        emit_label (acfg, symbol);
 }
@@ -2153,6 +2822,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        case MONO_PATCH_INFO_IMAGE:
                encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
                break;
+       case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
+               break;
        case MONO_PATCH_INFO_METHOD_REL:
                encode_value ((gint)patch_info->data.offset, p, &p);
                break;
@@ -2215,8 +2886,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                encode_value (*((guint32 *)patch_info->data.target), p, &p);
                break;
        case MONO_PATCH_INFO_R8:
-               encode_value (*((guint32 *)patch_info->data.target), p, &p);
-               encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
+               encode_value (((guint32 *)patch_info->data.target) [MINI_LS_WORD_IDX], p, &p);
+               encode_value (((guint32 *)patch_info->data.target) [MINI_MS_WORD_IDX], p, &p);
                break;
        case MONO_PATCH_INFO_VTABLE:
        case MONO_PATCH_INFO_CLASS:
@@ -2247,6 +2918,11 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
        case MONO_PATCH_INFO_MONITOR_ENTER:
        case MONO_PATCH_INFO_MONITOR_EXIT:
+       case MONO_PATCH_INFO_SEQ_POINT_INFO:
+               break;
+       case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
+               encode_method_ref (acfg, patch_info->data.imt_tramp->method, p, &p);
+               encode_value (patch_info->data.imt_tramp->vt_offset, p, &p);
                break;
        default:
                g_warning ("unable to handle jump info %d", patch_info->type);
@@ -2268,7 +2944,7 @@ encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, int
        for (pindex = 0; pindex < patches->len; ++pindex) {
                patch_info = g_ptr_array_index (patches, pindex);
 
-               if (patch_info->type == MONO_PATCH_INFO_NONE)
+               if (patch_info->type == MONO_PATCH_INFO_NONE || patch_info->type == MONO_PATCH_INFO_BB)
                        /* Nothing to do */
                        continue;
 
@@ -2286,7 +2962,6 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        GList *l;
        int pindex, buf_size, n_patches;
        guint8 *code;
-       char symbol [128];
        GPtrArray *patches;
        MonoJumpInfo *patch_info;
        MonoMethodHeader *header;
@@ -2300,9 +2975,6 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        method_index = get_method_index (acfg, method);
 
-       /* Make the labels local */
-       sprintf (symbol, "%sm_%x_p", acfg->temp_prefix, method_index);
-
        /* Sort relocations */
        patches = g_ptr_array_new ();
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
@@ -2368,12 +3040,9 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        acfg->stats.info_size += p - buf;
 
-       /* Emit method info */
-
-       emit_label (acfg, symbol);
-
        g_assert (p - buf < buf_size);
-       emit_bytes (acfg, buf, p - buf);
+
+       cfg->method_info_offset = add_to_blob (acfg, buf, p - buf);
        g_free (buf);
 }
 
@@ -2414,15 +3083,15 @@ static void
 emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 {
        MonoMethod *method;
-       int k, buf_size, method_index;
+       int i, k, buf_size, method_index;
        guint32 debug_info_size;
        guint8 *code;
-       char symbol [128];
        MonoMethodHeader *header;
        guint8 *p, *buf, *debug_info;
        MonoJitInfo *jinfo = cfg->jit_info;
        guint32 flags;
        gboolean use_unwind_ops = FALSE;
+       MonoSeqPointInfo *seq_points;
 
        method = cfg->orig_method;
        code = cfg->native_code;
@@ -2430,9 +3099,6 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        method_index = get_method_index (acfg, method);
 
-       /* Make the labels local */
-       sprintf (symbol, "%se_%x_p", acfg->temp_prefix, method_index);
-
        if (!acfg->aot_opts.nodebug) {
                mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
        } else {
@@ -2440,16 +3106,17 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                debug_info_size = 0;
        }
 
-       buf_size = header->num_clauses * 256 + debug_info_size + 1024;
+       seq_points = cfg->seq_point_info;
+
+       buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (seq_points ? (seq_points->len * 64) : 0);
        p = buf = g_malloc (buf_size);
 
 #ifdef MONO_ARCH_HAVE_XP_UNWIND
        use_unwind_ops = cfg->unwind_ops != NULL;
 #endif
 
-       flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0);
+       flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points ? 8 : 0) | (cfg->compile_llvm ? 16 : 0);
 
-       encode_value (jinfo->code_size, p, &p);
        encode_value (flags, p, &p);
 
        if (use_unwind_ops) {
@@ -2468,19 +3135,29 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        }
 
        /* Exception table */
-       if (header->num_clauses) {
-               for (k = 0; k < header->num_clauses; ++k) {
-                       MonoJitExceptionInfo *ei = &jinfo->clauses [k];
+       if (jinfo->num_clauses)
+               encode_value (jinfo->num_clauses, p, &p);
 
-                       encode_value (ei->exvar_offset, p, &p);
+       for (k = 0; k < jinfo->num_clauses; ++k) {
+               MonoJitExceptionInfo *ei = &jinfo->clauses [k];
 
-                       if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
-                               encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+               encode_value (ei->flags, p, &p);
+               encode_value (ei->exvar_offset, p, &p);
 
-                       encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
-                       encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
-                       encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
+               if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
+                       encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+               else {
+                       if (ei->data.catch_class) {
+                               encode_value (1, p, &p);
+                               encode_klass_ref (acfg, ei->data.catch_class, p, &p);
+                       } else {
+                               encode_value (0, p, &p);
+                       }
                }
+
+               encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
+               encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
+               encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
        }
 
        if (jinfo->has_generic_jit_info) {
@@ -2497,6 +3174,27 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                encode_method_ref (acfg, jinfo->method, p, &p);
        }
 
+       if (seq_points) {
+               int il_offset, native_offset, last_il_offset, last_native_offset, j;
+
+               encode_value (seq_points->len, p, &p);
+               last_il_offset = last_native_offset = 0;
+               for (i = 0; i < seq_points->len; ++i) {
+                       SeqPoint *sp = &seq_points->seq_points [i];
+                       il_offset = sp->il_offset;
+                       native_offset = sp->native_offset;
+                       encode_value (il_offset - last_il_offset, p, &p);
+                       encode_value (native_offset - last_native_offset, p, &p);
+                       last_il_offset = il_offset;
+                       last_native_offset = native_offset;
+
+                       encode_value (sp->next_len, p, &p);
+                       for (j = 0; j < sp->next_len; ++j)
+                               encode_value (sp->next [j], p, &p);
+               }
+       }
+               
+
        g_assert (debug_info_size < buf_size);
 
        encode_value (debug_info_size, p, &p);
@@ -2508,22 +3206,19 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        acfg->stats.ex_info_size += p - buf;
 
-       /* Emit info */
-
-       emit_label (acfg, symbol);
-
        g_assert (p - buf < buf_size);
-       emit_bytes (acfg, buf, p - buf);
+
+       /* Emit info */
+       cfg->ex_info_offset = add_to_blob (acfg, buf, p - buf);
        g_free (buf);
 }
 
-static void
+static guint32
 emit_klass_info (MonoAotCompile *acfg, guint32 token)
 {
        MonoClass *klass = mono_class_get (acfg->image, token);
        guint8 *p, *buf;
-       int i, buf_size;
-       char symbol [128];
+       int i, buf_size, res;
        gboolean no_special_static, cant_encode;
        gpointer iter = NULL;
 
@@ -2560,7 +3255,7 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
                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->ext && klass->ext->nested_classes) ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
+               encode_value ((klass->generic_container ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | ((klass->ext && klass->ext->nested_classes) ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
                if (klass->has_cctor)
                        encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
                if (klass->has_finalize)
@@ -2583,13 +3278,11 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
 
        acfg->stats.class_info_size += p - buf;
 
-       /* Emit the info */
-       sprintf (symbol, "%sK_I_%x", acfg->temp_prefix, token - MONO_TOKEN_TYPE_DEF - 1);
-       emit_label (acfg, symbol);
-
        g_assert (p - buf < buf_size);
-       emit_bytes (acfg, buf, p - buf);
+       res = add_to_blob (acfg, buf, p - buf);
        g_free (buf);
+
+       return res;
 }
 
 /*
@@ -2606,6 +3299,9 @@ emit_plt (MonoAotCompile *acfg)
 {
        char symbol [128];
        int i;
+       GHashTable *cache;
+
+       cache = g_hash_table_new (g_str_hash, g_str_equal);
 
        emit_line (acfg);
        sprintf (symbol, "plt");
@@ -2619,42 +3315,114 @@ emit_plt (MonoAotCompile *acfg)
        emit_alignment (acfg, 16);
 #endif
        emit_label (acfg, symbol);
+       emit_label (acfg, acfg->plt_symbol);
 
        for (i = 0; i < acfg->plt_offset; ++i) {
                char label [128];
+               char *debug_sym = NULL;
+               MonoJumpInfo *ji;
 
                sprintf (label, "%sp_%d", acfg->temp_prefix, i);
+
+               if (acfg->llvm) {
+                       /*
+                        * If the target is directly callable, alias the plt symbol to point to
+                        * the method code.
+                        * FIXME: Use this to simplify emit_and_reloc_code ().
+                        * FIXME: Avoid the got slot.
+                        * FIXME: Add support to the binary writer.
+                        */
+                       ji = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
+                       if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer) {
+                               MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, ji->data.method);
+                               fprintf (acfg->fp, "\n.set %s, .Lm_%x\n", label, get_method_index (acfg, callee_cfg->orig_method));
+                               continue;
+                       }
+               }
+
                emit_label (acfg, label);
 
+               if (acfg->aot_opts.write_symbols) {
+                       MonoJumpInfo *ji = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
+
+                       if (ji) {
+                               switch (ji->type) {
+                               case MONO_PATCH_INFO_METHOD:
+                                       debug_sym = get_debug_sym (ji->data.method, "plt_", cache);
+                                       break;
+                               case MONO_PATCH_INFO_INTERNAL_METHOD:
+                                       debug_sym = g_strdup_printf ("plt__jit_icall_%s", ji->data.name);
+                                       break;
+                               case MONO_PATCH_INFO_CLASS_INIT:
+                                       debug_sym = g_strdup_printf ("plt__class_init_%s", mono_type_get_name (&ji->data.klass->byval_arg));
+                                       sanitize_symbol (debug_sym);
+                                       break;
+                               case MONO_PATCH_INFO_RGCTX_FETCH:
+                                       debug_sym = g_strdup_printf ("plt__rgctx_fetch_%d", acfg->label_generator ++);
+                                       break;
+                               case MONO_PATCH_INFO_ICALL_ADDR: {
+                                       char *s = get_debug_sym (ji->data.method, "", cache);
+                                       
+                                       debug_sym = g_strdup_printf ("plt__icall_native_%s", s);
+                                       g_free (s);
+                                       break;
+                               }
+                               case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+                                       debug_sym = g_strdup_printf ("plt__jit_icall_native_%s", ji->data.name);
+                                       break;
+                               case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
+                                       debug_sym = g_strdup_printf ("plt__generic_class_init");
+                                       break;
+                               default:
+                                       break;
+                               }
+
+                               if (debug_sym) {
+                                       emit_local_symbol (acfg, debug_sym, NULL, TRUE);
+                                       emit_label (acfg, debug_sym);
+                               }
+                       }
+               }
+
                /* 
                 * The first plt entry is used to transfer code to the AOT loader. 
                 */
                arch_emit_plt_entry (acfg, i);
+
+               if (debug_sym) {
+                       emit_symbol_size (acfg, debug_sym, ".");
+                       g_free (debug_sym);
+               }
        }
 
+       emit_symbol_size (acfg, acfg->plt_symbol, ".");
+
        sprintf (symbol, "plt_end");
        emit_global (acfg, symbol, TRUE);
        emit_label (acfg, symbol);
+
+       g_hash_table_destroy (cache);
 }
 
 static G_GNUC_UNUSED void
 emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code, 
                                 guint32 code_size, int got_offset, MonoJumpInfo *ji, GSList *unwind_ops)
 {
+       char start_symbol [256];
        char symbol [256];
-       guint32 buf_size;
+       guint32 buf_size, info_offset;
        MonoJumpInfo *patch_info;
        guint8 *buf, *p;
        GPtrArray *patches;
 
        /* Emit code */
 
-       sprintf (symbol, "%s", name);
+       sprintf (start_symbol, "%s", name);
 
        emit_section_change (acfg, ".text", 0);
-       emit_global (acfg, symbol, TRUE);
+       emit_global (acfg, start_symbol, TRUE);
        emit_alignment (acfg, 16);
-       emit_label (acfg, symbol);
+       emit_label (acfg, start_symbol);
 
        sprintf (symbol, "%snamed_%s", acfg->temp_prefix, name);
        emit_label (acfg, symbol);
@@ -2665,12 +3433,15 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
         */
        emit_and_reloc_code (acfg, NULL, code, code_size, ji, TRUE);
 
+       emit_symbol_size (acfg, start_symbol, ".");
+
        /* 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);
+               if (patch_info->type != MONO_PATCH_INFO_NONE)
+                       g_ptr_array_add (patches, patch_info);
        g_ptr_array_sort (patches, compare_patches);
 
        buf_size = patches->len * 128 + 128;
@@ -2682,11 +3453,13 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
 
        sprintf (symbol, "%s_p", name);
 
+       info_offset = add_to_blob (acfg, buf, p - buf);
+
        emit_section_change (acfg, ".text", 0);
        emit_global (acfg, symbol, FALSE);
        emit_label (acfg, symbol);
-               
-       emit_bytes (acfg, buf, p - buf);
+
+       emit_int32 (acfg, info_offset);
 
        /* Emit debug info */
        if (unwind_ops) {
@@ -2770,7 +3543,6 @@ emit_trampolines (MonoAotCompile *acfg)
                emit_trampoline (acfg, "throw_pending_exception", code, code_size, acfg->got_offset, ji, NULL);
 #endif
 
-#if defined(TARGET_AMD64) || defined(TARGET_ARM)
                for (i = 0; i < 128; ++i) {
                        int offset;
 
@@ -2784,9 +3556,7 @@ emit_trampolines (MonoAotCompile *acfg)
                        sprintf (symbol, "rgctx_fetch_trampoline_%u", offset);
                        emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
                }
-#endif
 
-#if defined(TARGET_AMD64) || defined(TARGET_ARM)
                {
                        GSList *l;
 
@@ -2799,7 +3569,6 @@ emit_trampolines (MonoAotCompile *acfg)
                                l = l->next;
                        }
                }
-#endif
 
 #endif /* #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES */
 
@@ -2935,6 +3704,18 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->nodebug = TRUE;
                } else if (str_begins_with (arg, "ntrampolines=")) {
                        opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
+               } else if (str_begins_with (arg, "nrgctx-trampolines=")) {
+                       opts->nrgctx_trampolines = atoi (arg + strlen ("nrgctx-trampolines="));
+               } else if (str_begins_with (arg, "autoreg")) {
+                       opts->autoreg = TRUE;
+               } else if (str_begins_with (arg, "tool-prefix=")) {
+                       opts->tool_prefix = g_strdup (arg + strlen ("tool-prefix="));
+               } else if (str_begins_with (arg, "soft-debug")) {
+                       opts->soft_debug = TRUE;
+               } else if (str_begins_with (arg, "print-skipped")) {
+                       opts->print_skipped_methods = TRUE;
+               } else if (str_begins_with (arg, "stats")) {
+                       opts->stats = TRUE;
                } else {
                        fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
                        exit (1);
@@ -3050,7 +3831,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
        MonoCompile *cfg;
        MonoJumpInfo *patch_info;
        gboolean skip;
-       int index;
+       int index, depth;
        MonoMethod *wrapped;
 
        if (acfg->aot_opts.metadata_only)
@@ -3174,27 +3955,41 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
        }
 
        /* Adds generic instances referenced by this method */
-       for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
-               switch (patch_info->type) {
-               case MONO_PATCH_INFO_METHOD: {
-                       MonoMethod *m = patch_info->data.method;
-                       if (m->is_inflated) {
-                               if (!(mono_class_generic_sharing_enabled (m->klass) &&
-                                         mono_method_is_generic_sharable_impl (m, FALSE)) &&
-                                       !method_has_type_vars (m)) {
-                                       if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
-                                               if (acfg->aot_opts.full_aot)
-                                                       add_extra_method (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE));
-                                       } else {
-                                               add_extra_method (acfg, m);
+       /* 
+        * The depth is used to avoid infinite loops when generic virtual recursion is 
+        * encountered.
+        */
+       depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method));
+       if (depth < 32) {
+               for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
+                       switch (patch_info->type) {
+                       case MONO_PATCH_INFO_METHOD: {
+                               MonoMethod *m = patch_info->data.method;
+                               if (m->is_inflated) {
+                                       if (!(mono_class_generic_sharing_enabled (m->klass) &&
+                                                 mono_method_is_generic_sharable_impl (m, FALSE)) &&
+                                               !method_has_type_vars (m)) {
+                                               if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
+                                                       if (acfg->aot_opts.full_aot)
+                                                               add_extra_method_with_depth (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE), depth + 1);
+                                               } else {
+                                                       add_extra_method_with_depth (acfg, m, depth + 1);
+                                               }
                                        }
+                                       add_generic_class (acfg, m->klass);
                                }
-                               add_generic_class (acfg, m->klass);
+                               break;
+                       }
+                       case MONO_PATCH_INFO_VTABLE: {
+                               MonoClass *klass = patch_info->data.klass;
+
+                               if (klass->generic_class && !mono_generic_context_is_sharable (&klass->generic_class->context, FALSE))
+                                       add_generic_class (acfg, klass);
+                               break;
+                       }
+                       default:
+                               break;
                        }
-                       break;
-               }
-               default:
-                       break;
                }
        }
 
@@ -3219,6 +4014,9 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
        if (!cfg->has_got_slots)
                InterlockedIncrement (&acfg->stats.methods_without_got_slots);
 
+       /* 
+        * FIXME: Instead of this mess, allocate the patches from the aot mempool.
+        */
        /* Make a copy of the patch info which is in the mempool */
        {
                MonoJumpInfo *patches = NULL, *patches_end = NULL;
@@ -3383,6 +4181,120 @@ load_profile_files (MonoAotCompile *acfg)
        else
                acfg->method_order = unordered;
 }
+/* Used by the LLVM backend */
+guint32
+mono_aot_get_got_offset (MonoJumpInfo *ji)
+{
+       return get_got_offset (llvm_acfg, ji);
+}
+
+char*
+mono_aot_get_method_name (MonoCompile *cfg)
+{
+       guint32 method_index = get_method_index (llvm_acfg, cfg->orig_method);
+
+       /* LLVM converts these to .Lm_%x */
+       return g_strdup_printf ("m_%x", method_index);
+}
+
+char*
+mono_aot_get_method_debug_name (MonoCompile *cfg)
+{
+       return get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash);
+}
+
+char*
+mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
+{
+       MonoJumpInfo *ji = mono_mempool_alloc (llvm_acfg->mempool, sizeof (MonoJumpInfo));
+       int offset;
+
+       ji->type = type;
+       ji->data.target = data;
+
+       if (!can_encode_patch (llvm_acfg, ji))
+               return NULL;
+
+       offset = get_plt_offset (llvm_acfg, ji);
+
+       return g_strdup_printf (".Lp_%d", offset);
+}
+
+MonoJumpInfo*
+mono_aot_patch_info_dup (MonoJumpInfo* ji)
+{
+       MonoJumpInfo *res;
+
+       mono_acfg_lock (llvm_acfg);
+       res = mono_patch_info_dup_mp (llvm_acfg->mempool, ji);
+       mono_acfg_unlock (llvm_acfg);
+
+       return res;
+}
+
+#ifdef ENABLE_LLVM
+
+/*
+ * emit_llvm_file:
+ *
+ *   Emit the LLVM code into an LLVM bytecode file, and compile it using the LLVM
+ * tools.
+ */
+static void
+emit_llvm_file (MonoAotCompile *acfg)
+{
+       char *command, *opts;
+       int i;
+       MonoJumpInfo *patch_info;
+
+       /*
+        * When using LLVM, we let llvm emit the got since the LLVM IL needs to refer
+        * to it.
+        */
+
+       /* Compute the final size of the got */
+       for (i = 0; i < acfg->nmethods; ++i) {
+               if (acfg->cfgs [i]) {
+                       for (patch_info = acfg->cfgs [i]->patch_info; patch_info; patch_info = patch_info->next) {
+                               if (patch_info->type != MONO_PATCH_INFO_NONE) {
+                                       if (!is_plt_patch (patch_info))
+                                               get_got_offset (acfg, patch_info);
+                                       else
+                                               get_plt_offset (acfg, patch_info);
+                               }
+                       }
+               }
+       }
+       acfg->final_got_size = acfg->got_offset + acfg->plt_offset;
+
+       mono_llvm_emit_aot_module ("temp.bc", acfg->final_got_size);
+
+       /*
+        * FIXME: Experiment with adding optimizations, the -std-compile-opts set takes
+        * a lot of time, and doesn't seem to save much space.
+        * The following optimizations cannot be enabled:
+        * - 'tailcallelim'
+        */
+       opts = g_strdup ("-instcombine -simplifycfg");
+#if 1
+       command = g_strdup_printf ("opt -f %s -o temp.opt.bc temp.bc", opts);
+       printf ("Executing opt: %s\n", command);
+       if (system (command) != 0) {
+               exit (1);
+       }
+#endif
+       g_free (opts);
+
+       //command = g_strdup_printf ("llc -march=arm -mtriple=arm-linux-gnueabi -f -relocation-model=pic -unwind-tables temp.bc");
+       command = g_strdup_printf ("llc -f -relocation-model=pic -unwind-tables -o temp.s temp.opt.bc");
+       printf ("Executing llc: %s\n", command);
+
+       if (system (command) != 0) {
+               exit (1);
+       }
+}
+#endif
 
 static void
 emit_code (MonoAotCompile *acfg)
@@ -3391,11 +4303,21 @@ emit_code (MonoAotCompile *acfg)
        char symbol [256];
        GList *l;
 
-       sprintf (symbol, "methods");
+#if defined(TARGET_POWERPC64)
+       sprintf (symbol, ".Lgot_addr");
        emit_section_change (acfg, ".text", 0);
-       emit_global (acfg, symbol, TRUE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
+       emit_pointer (acfg, acfg->got_symbol);
+#endif
+
+       if (!acfg->llvm) {
+               sprintf (symbol, "methods");
+               emit_section_change (acfg, ".text", 0);
+               emit_global (acfg, symbol, TRUE);
+               emit_alignment (acfg, 8);
+               emit_label (acfg, symbol);
+       }
 
        /* 
         * Emit some padding so the local symbol for the first method doesn't have the
@@ -3406,8 +4328,12 @@ emit_code (MonoAotCompile *acfg)
        for (l = acfg->method_order; l != NULL; l = l->next) {
                i = GPOINTER_TO_UINT (l->data);
 
-               if (acfg->cfgs [i])
-                       emit_method_code (acfg, acfg->cfgs [i]);
+               if (acfg->cfgs [i]) {
+                       if (acfg->cfgs [i]->compile_llvm)
+                               acfg->stats.llvm_count ++;
+                       else
+                               emit_method_code (acfg, acfg->cfgs [i]);
+               }
        }
 
        sprintf (symbol, "methods_end");
@@ -3416,12 +4342,14 @@ emit_code (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
-       sprintf (symbol, "method_offsets");
+       sprintf (symbol, "code_offsets");
        emit_section_change (acfg, ".text", 1);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
+       acfg->stats.offsets_size += acfg->nmethods * 4;
+
        for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
                        sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
@@ -3439,23 +4367,19 @@ emit_info (MonoAotCompile *acfg)
        int i;
        char symbol [256];
        GList *l;
+       gint32 *offsets;
 
-       /* Emit method info */
-       sprintf (symbol, "method_info");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
-       /* To reduce size of generated assembly code */
-       sprintf (symbol, "mi");
-       emit_label (acfg, symbol);
+       offsets = g_new0 (gint32, acfg->nmethods);
 
        for (l = acfg->method_order; l != NULL; l = l->next) {
                i = GPOINTER_TO_UINT (l->data);
 
-               if (acfg->cfgs [i])
+               if (acfg->cfgs [i]) {
                        emit_method_info (acfg, acfg->cfgs [i]);
+                       offsets [i] = acfg->cfgs [i]->method_info_offset;
+               } else {
+                       offsets [i] = 0;
+               }
        }
 
        sprintf (symbol, "method_info_offsets");
@@ -3464,40 +4388,13 @@ emit_info (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
-       for (i = 0; i < acfg->nmethods; ++i) {
-               if (acfg->cfgs [i]) {
-                       sprintf (symbol, "%sm_%x_p", acfg->temp_prefix, i);
-                       emit_symbol_diff (acfg, symbol, "mi", 0);
-               } else {
-                       emit_int32 (acfg, 0);
-               }
-       }
-       emit_line (acfg);
+       acfg->stats.offsets_size += emit_offset_table (acfg, acfg->nmethods, 10, offsets);
+
+       g_free (offsets);
 }
 
 #endif /* #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */
 
-/*
- * mono_aot_str_hash:
- *
- * Hash function for strings which we use to hash strings for things which are
- * saved in the AOT image, since g_str_hash () can change.
- */
-guint
-mono_aot_str_hash (gconstpointer v1)
-{
-       /* Same as g_str_hash () in glib */
-       char *p = (char *) v1;
-       guint hash = *p;
-
-       while (*p++) {
-               if (*p)
-                       hash = (hash << 5) - hash + *p;
-       }
-
-       return hash;
-} 
-
 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
 #define mix(a,b,c) { \
        a -= c;  a ^= rot(c, 4);  c += b; \
@@ -3528,11 +4425,11 @@ mono_aot_type_hash (MonoType *t1)
        case MONO_TYPE_CLASS:
        case MONO_TYPE_SZARRAY:
                /* check if the distribution is good enough */
-               return ((hash << 5) - hash) ^ mono_aot_str_hash (t1->data.klass->name);
+               return ((hash << 5) - hash) ^ mono_metadata_str_hash (t1->data.klass->name);
        case MONO_TYPE_PTR:
-               return ((hash << 5) - hash) ^ mono_aot_type_hash (t1->data.type);
+               return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
        case MONO_TYPE_ARRAY:
-               return ((hash << 5) - hash) ^ mono_aot_type_hash (&t1->data.array->eklass->byval_arg);
+               return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg);
        case MONO_TYPE_GENERICINST:
                return ((hash << 5) - hash) ^ 0;
        }
@@ -3571,14 +4468,18 @@ mono_aot_method_hash (MonoMethod *method)
        if (!method->wrapper_type) {
                char *full_name = mono_type_full_name (&klass->byval_arg);
 
-               hashes [0] = mono_aot_str_hash (full_name);
+               hashes [0] = mono_metadata_str_hash (full_name);
                hashes [1] = 0;
                g_free (full_name);
        } else {
-               hashes [0] = mono_aot_str_hash (klass->name);
-               hashes [1] = mono_aot_str_hash (klass->name_space);
+               hashes [0] = mono_metadata_str_hash (klass->name);
+               hashes [1] = mono_metadata_str_hash (klass->name_space);
        }
-       hashes [2] = mono_aot_str_hash (method->name);
+       if (method->wrapper_type == MONO_WRAPPER_STFLD || method->wrapper_type == MONO_WRAPPER_LDFLD || method->wrapper_type == MONO_WRAPPER_LDFLDA)
+               /* The method name includes a stringified pointer */
+               hashes [2] = 0;
+       else
+               hashes [2] = mono_metadata_str_hash (method->name);
        hashes [3] = method->wrapper_type;
        hashes [4] = mono_aot_type_hash (sig->ret);
        for (i = 0; i < sig->param_count; i++) {
@@ -3630,16 +4531,21 @@ mono_aot_wrapper_name (MonoMethod *method)
 
        switch (method->wrapper_type) {
        case MONO_WRAPPER_RUNTIME_INVOKE:
+               if (!strcmp (method->name, "runtime_invoke_dynamic"))
+                       name = g_strdup_printf ("(wrapper runtime-invoke-dynamic)");
+               else
+                       name = g_strdup_printf ("%s (%s)", method->name, tmpsig);
+               break;
        case MONO_WRAPPER_DELEGATE_INVOKE:
        case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
        case MONO_WRAPPER_DELEGATE_END_INVOKE:
-               /* This is a hack to work around the fact that runtime invoke wrappers get assigned to some random class */
+               /* This is a hack to work around the fact that these wrappers get assigned to some random class */
                name = g_strdup_printf ("%s (%s)", method->name, tmpsig);
                break;
        default:
                klass_desc = mono_type_full_name (&method->klass->byval_arg);
-
                name = g_strdup_printf ("%s:%s (%s)", klass_desc, method->name, tmpsig);
+               g_free (klass_desc);
                break;
        }
 
@@ -3648,6 +4554,49 @@ mono_aot_wrapper_name (MonoMethod *method)
        return name;
 }
 
+/*
+ * mono_aot_get_array_helper_from_wrapper;
+ *
+ * Get the helper method in Array called by an array wrapper method.
+ */
+MonoMethod*
+mono_aot_get_array_helper_from_wrapper (MonoMethod *method)
+{
+       MonoMethod *m;
+       const char *prefix;
+       MonoGenericContext ctx;
+       MonoType *args [16];
+       char *mname, *iname, *s, *s2, *helper_name = NULL;
+
+       prefix = "System.Collections.Generic";
+       s = g_strdup_printf ("%s", method->name + strlen (prefix) + 1);
+       s2 = strstr (s, "`1.");
+       g_assert (s2);
+       s2 [0] = '\0';
+       iname = s;
+       mname = s2 + 3;
+
+       //printf ("X: %s %s\n", iname, mname);
+
+       if (!strcmp (iname, "IList"))
+               helper_name = g_strdup_printf ("InternalArray__%s", mname);
+       else
+               helper_name = g_strdup_printf ("InternalArray__%s_%s", iname, mname);
+       m = mono_class_get_method_from_name (mono_defaults.array_class, helper_name, mono_method_signature (method)->param_count);
+       g_assert (m);
+       g_free (helper_name);
+       g_free (s);
+
+       if (m->is_generic) {
+               memset (&ctx, 0, sizeof (ctx));
+               args [0] = &method->klass->element_class->byval_arg;
+               ctx.method_inst = mono_metadata_get_generic_inst (1, args);
+               m = mono_class_inflate_generic_method (m, &ctx);
+       }
+
+       return m;
+}
+
 /*
  * mono_aot_tramp_info_create:
  *
@@ -3692,14 +4641,8 @@ emit_extra_methods (MonoAotCompile *acfg)
 
        info_offsets = g_new0 (guint32, acfg->extra_methods->len);
 
-       buf_size = acfg->extra_methods->len * 256 + 256;
-       p = buf = g_malloc (buf_size);
-
-       /* Encode method info */
+       /* Emit method info */
        nmethods = 0;
-       /* So offsets are > 0 */
-       *p = 0;
-       p++;
        for (i = 0; i < acfg->extra_methods->len; ++i) {
                MonoMethod *method = g_ptr_array_index (acfg->extra_methods, i);
                MonoCompile *cfg = g_hash_table_lookup (acfg->method_to_cfg, method);
@@ -3708,8 +4651,10 @@ emit_extra_methods (MonoAotCompile *acfg)
                if (!cfg)
                        continue;
 
+               buf_size = 512;
+               p = buf = g_malloc (buf_size);
+
                nmethods ++;
-               info_offsets [i] = p - buf;
 
                name = NULL;
                if (method->wrapper_type) {
@@ -3746,20 +4691,10 @@ emit_extra_methods (MonoAotCompile *acfg)
                }
 
                g_assert ((p - buf) < buf_size);
-       }
 
-       g_assert ((p - buf) < buf_size);
-
-       /* Emit method info */
-       sprintf (symbol, "extra_method_info");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
-       emit_bytes (acfg, buf, p - buf);
-
-       emit_line (acfg);
+               info_offsets [i] = add_to_blob (acfg, buf, p - buf);
+               g_free (buf);
+       }
 
        /*
         * Construct a chained hash table for mapping indexes in extra_method_info to
@@ -3787,8 +4722,7 @@ emit_extra_methods (MonoAotCompile *acfg)
                chain_lengths [hash] ++;
                max_chain_length = MAX (max_chain_length, chain_lengths [hash]);
 
-               /* FIXME: Allocate from the mempool */
-               new_entry = g_new0 (HashEntry, 1);
+               new_entry = mono_mempool_alloc0 (acfg->mempool, sizeof (HashEntry));
                new_entry->key = key;
                new_entry->value = value;
 
@@ -3815,9 +4749,7 @@ emit_extra_methods (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
-       g_assert (table_size < 65000);
        emit_int32 (acfg, table_size);
-       g_assert (table->len < 65000);
        for (i = 0; i < table->len; ++i) {
                HashEntry *entry = g_ptr_array_index (table, i);
 
@@ -3826,7 +4758,7 @@ emit_extra_methods (MonoAotCompile *acfg)
                        emit_int32 (acfg, 0);
                        emit_int32 (acfg, 0);
                } else {
-                       g_assert (entry->key > 0);
+                       //g_assert (entry->key > 0);
                        emit_int32 (acfg, entry->key);
                        emit_int32 (acfg, entry->value);
                        if (entry->next)
@@ -3855,72 +4787,21 @@ emit_extra_methods (MonoAotCompile *acfg)
        }
 }      
 
-static void
-emit_method_order (MonoAotCompile *acfg)
-{
-       int i, index, len;
-       char symbol [256];
-       GList *l;
-
-       sprintf (symbol, "method_order");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
-       /* First emit an index table */
-       index = 0;
-       len = 0;
-       for (l = acfg->method_order; l != NULL; l = l->next) {
-               i = GPOINTER_TO_UINT (l->data);
-
-               if (acfg->cfgs [i]) {
-                       if ((index % 1024) == 0) {
-                               emit_int32 (acfg, i);
-                       }
-
-                       index ++;
-               }
-
-               len ++;
-       }
-       emit_int32 (acfg, 0xffffff);
-
-       /* Then emit the whole method order */
-       for (l = acfg->method_order; l != NULL; l = l->next) {
-               i = GPOINTER_TO_UINT (l->data);
-
-               if (acfg->cfgs [i]) {
-                       emit_int32 (acfg, i);
-               }
-       }       
-       emit_line (acfg);
-
-       sprintf (symbol, "method_order_end");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_label (acfg, symbol);
-}
-
 static void
 emit_exception_info (MonoAotCompile *acfg)
 {
        int i;
        char symbol [256];
+       gint32 *offsets;
 
-       sprintf (symbol, "ex_info");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
-       /* To reduce size of generated assembly */
-       sprintf (symbol, "ex");
-       emit_label (acfg, symbol);
-
+       offsets = g_new0 (gint32, acfg->nmethods);
        for (i = 0; i < acfg->nmethods; ++i) {
-               if (acfg->cfgs [i])
+               if (acfg->cfgs [i]) {
                        emit_exception_debug_info (acfg, acfg->cfgs [i]);
+                       offsets [i] = acfg->cfgs [i]->ex_info_offset;
+               } else {
+                       offsets [i] = 0;
+               }
        }
 
        sprintf (symbol, "ex_info_offsets");
@@ -3929,15 +4810,8 @@ emit_exception_info (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
-       for (i = 0; i < acfg->nmethods; ++i) {
-               if (acfg->cfgs [i]) {
-                       sprintf (symbol, "%se_%x_p", acfg->temp_prefix, i);
-                       emit_symbol_diff (acfg, symbol, "ex", 0);
-               } else {
-                       emit_int32 (acfg, 0);
-               }
-       }
-       emit_line (acfg);
+       acfg->stats.offsets_size += emit_offset_table (acfg, acfg->nmethods, 10, offsets);
+       g_free (offsets);
 }
 
 static void
@@ -3981,15 +4855,11 @@ emit_class_info (MonoAotCompile *acfg)
 {
        int i;
        char symbol [256];
+       gint32 *offsets;
 
-       sprintf (symbol, "class_info");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
+       offsets = g_new0 (gint32, acfg->image->tables [MONO_TABLE_TYPEDEF].rows);
        for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
-               emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
+               offsets [i] = emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
 
        sprintf (symbol, "class_info_offsets");
        emit_section_change (acfg, ".text", 1);
@@ -3997,11 +4867,8 @@ emit_class_info (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
-       for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
-               sprintf (symbol, "%sK_I_%x", acfg->temp_prefix, i);
-               emit_symbol_diff (acfg, symbol, "class_info", 0);
-       }
-       emit_line (acfg);
+       acfg->stats.offsets_size += emit_offset_table (acfg, acfg->image->tables [MONO_TABLE_TYPEDEF].rows, 10, offsets);
+       g_free (offsets);
 }
 
 typedef struct ClassNameTableEntry {
@@ -4031,7 +4898,7 @@ emit_class_name_table (MonoAotCompile *acfg)
                token = MONO_TOKEN_TYPE_DEF | (i + 1);
                klass = mono_class_get (acfg->image, token);
                full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
-               hash = mono_aot_str_hash (full_name) % table_size;
+               hash = mono_metadata_str_hash (full_name) % table_size;
                g_free (full_name);
 
                /* FIXME: Allocate from the mempool */
@@ -4153,28 +5020,24 @@ emit_got_info (MonoAotCompile *acfg)
        p = buf = mono_mempool_alloc (acfg->mempool, buf_size);
        got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->got_patches->len * sizeof (guint32));
        acfg->plt_got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->plt_offset * sizeof (guint32));
+       /* Unused */
+       if (acfg->plt_offset)
+               acfg->plt_got_info_offsets [0] = 0;
        for (i = 0; i < acfg->got_patches->len; ++i) {
                MonoJumpInfo *ji = g_ptr_array_index (acfg->got_patches, i);
 
-               got_info_offsets [i] = p - buf;
-               if (i >= first_plt_got_patch)
-                       acfg->plt_got_info_offsets [i - first_plt_got_patch + 1] = got_info_offsets [i];
+               p = buf;
+
                encode_value (ji->type, p, &p);
                encode_patch (acfg, ji, p, &p);
-       }
-
-       g_assert (p - buf <= buf_size);
 
-       acfg->stats.got_info_size = p - buf;
+               g_assert (p - buf <= buf_size);
+               got_info_offsets [i] = add_to_blob (acfg, buf, p - buf);
 
-       /* Emit got_info table */
-       sprintf (symbol, "got_info");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
-       emit_bytes (acfg, buf, p - buf);
+               if (i >= first_plt_got_patch)
+                       acfg->plt_got_info_offsets [i - first_plt_got_patch + 1] = got_info_offsets [i];
+               acfg->stats.got_info_size += p - buf;
+       }
 
        /* Emit got_info_offsets table */
        sprintf (symbol, "got_info_offsets");
@@ -4184,10 +5047,7 @@ emit_got_info (MonoAotCompile *acfg)
        emit_label (acfg, symbol);
 
        /* No need to emit offsets for the got plt entries, the plt embeds them directly */
-       for (i = 0; i < first_plt_got_patch; ++i)
-               emit_int32 (acfg, got_info_offsets [i]);
-
-       acfg->stats.got_info_offsets_size = acfg->got_patches->len * 4;
+       acfg->stats.offsets_size += emit_offset_table (acfg, first_plt_got_patch, 10, (gint32*)got_info_offsets);
 }
 
 static void
@@ -4195,17 +5055,19 @@ emit_got (MonoAotCompile *acfg)
 {
        char symbol [256];
 
-       /* Don't make GOT global so accesses to it don't need relocations */
-       sprintf (symbol, acfg->got_symbol);
-       emit_section_change (acfg, ".bss", 0);
-       emit_alignment (acfg, 8);
-       emit_local_symbol (acfg, symbol, "got_end", FALSE);
-       emit_label (acfg, symbol);
-       if (acfg->got_offset > 0)
-               emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
+       if (!acfg->llvm) {
+               /* Don't make GOT global so accesses to it don't need relocations */
+               sprintf (symbol, "%s", acfg->got_symbol);
+               emit_section_change (acfg, ".bss", 0);
+               emit_alignment (acfg, 8);
+               emit_local_symbol (acfg, symbol, "got_end", FALSE);
+               emit_label (acfg, symbol);
+               if (acfg->got_offset > 0)
+                       emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
 
-       sprintf (symbol, "got_end");
-       emit_label (acfg, symbol);
+               sprintf (symbol, "got_end");
+               emit_label (acfg, symbol);
+       }
 
        sprintf (symbol, "mono_aot_got_addr");
        emit_section_change (acfg, ".data", 0);
@@ -4215,22 +5077,118 @@ emit_got (MonoAotCompile *acfg)
        emit_pointer (acfg, acfg->got_symbol);
 }
 
+typedef struct GlobalsTableEntry {
+       guint32 value, index;
+       struct GlobalsTableEntry *next;
+} GlobalsTableEntry;
+
+static void
+emit_globals_table (MonoAotCompile *acfg)
+{
+       int i, table_size;
+       guint32 hash;
+       GPtrArray *table;
+       char symbol [256];
+       GlobalsTableEntry *entry, *new_entry;
+
+       /*
+        * Construct a chained hash table for mapping global names to their index in
+        * the globals table.
+        */
+       table_size = g_spaced_primes_closest ((int)(acfg->globals->len * 1.5));
+       table = g_ptr_array_sized_new (table_size);
+       for (i = 0; i < table_size; ++i)
+               g_ptr_array_add (table, NULL);
+       for (i = 0; i < acfg->globals->len; ++i) {
+               char *name = g_ptr_array_index (acfg->globals, i);
+
+               hash = mono_metadata_str_hash (name) % table_size;
+
+               /* FIXME: Allocate from the mempool */
+               new_entry = g_new0 (GlobalsTableEntry, 1);
+               new_entry->value = i;
+
+               entry = g_ptr_array_index (table, hash);
+               if (entry == NULL) {
+                       new_entry->index = hash;
+                       g_ptr_array_index (table, hash) = new_entry;
+               } else {
+                       while (entry->next)
+                               entry = entry->next;
+                       
+                       entry->next = new_entry;
+                       new_entry->index = table->len;
+                       g_ptr_array_add (table, new_entry);
+               }
+       }
+
+       /* Emit the table */
+       sprintf (symbol, ".Lglobals_hash");
+       emit_section_change (acfg, ".text", 0);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+
+       /* FIXME: Optimize memory usage */
+       g_assert (table_size < 65000);
+       emit_int16 (acfg, table_size);
+       for (i = 0; i < table->len; ++i) {
+               GlobalsTableEntry *entry = g_ptr_array_index (table, i);
+
+               if (entry == NULL) {
+                       emit_int16 (acfg, 0);
+                       emit_int16 (acfg, 0);
+               } else {
+                       emit_int16 (acfg, entry->value + 1);
+                       if (entry->next)
+                               emit_int16 (acfg, entry->next->index);
+                       else
+                               emit_int16 (acfg, 0);
+               }
+       }
+
+       /* Emit the names */
+       for (i = 0; i < acfg->globals->len; ++i) {
+               char *name = g_ptr_array_index (acfg->globals, i);
+
+               sprintf (symbol, "name_%d", i);
+               emit_section_change (acfg, ".text", 1);
+               emit_label (acfg, symbol);
+               emit_string (acfg, name);
+       }
+
+       /* Emit the globals table */
+       sprintf (symbol, ".Lglobals");
+       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);
+
+       sprintf (symbol, "%sglobals_hash", acfg->temp_prefix);
+       emit_pointer (acfg, symbol);
+
+       for (i = 0; i < acfg->globals->len; ++i) {
+               char *name = g_ptr_array_index (acfg->globals, i);
+
+               sprintf (symbol, "name_%d", i);
+               emit_pointer (acfg, symbol);
+
+               sprintf (symbol, "%s", name);
+               emit_pointer (acfg, symbol);
+       }
+       /* Null terminate the table */
+       emit_int32 (acfg, 0);
+       emit_int32 (acfg, 0);
+}
+
 static void
 emit_globals (MonoAotCompile *acfg)
 {
-       char *opts_str;
        char *build_info;
 
        emit_string_symbol (acfg, "mono_assembly_guid" , acfg->image->guid);
 
        emit_string_symbol (acfg, "mono_aot_version", MONO_AOT_FILE_VERSION);
 
-       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) {
                build_info = mono_get_runtime_build_info ();
                emit_string_symbol (acfg, "mono_runtime_version", build_info);
@@ -4243,42 +5201,13 @@ emit_globals (MonoAotCompile *acfg)
         * When static linking, we emit a global which will point to the symbol table.
         */
        if (acfg->aot_opts.static_link) {
-               int i;
                char symbol [256];
                char *p;
 
                /* 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);
-
-                       sprintf (symbol, "name_%d", i);
-                       emit_section_change (acfg, ".text", 1);
-                       emit_label (acfg, symbol);
-                       emit_string (acfg, name);
-               }
-
-               /* Emit the globals table */
-               sprintf (symbol, "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);
-
-                       sprintf (symbol, "name_%d", i);
-                       emit_pointer (acfg, symbol);
-
-                       sprintf (symbol, "%s", name);
-                       emit_pointer (acfg, symbol);
-               }
-               /* Null terminate the table */
-               emit_int32 (acfg, 0);
-               emit_int32 (acfg, 0);
+               emit_globals_table (acfg);
 
                /* 
                 * Emit a global symbol which can be passed by an embedding app to
@@ -4300,10 +5229,30 @@ emit_globals (MonoAotCompile *acfg)
                emit_global_inner (acfg, symbol, FALSE);
                emit_alignment (acfg, 8);
                emit_label (acfg, symbol);
-               emit_pointer (acfg, "globals");
+               sprintf (symbol, "%sglobals", acfg->temp_prefix);
+               emit_pointer (acfg, symbol);
        }
 }
 
+static void
+emit_autoreg (MonoAotCompile *acfg)
+{
+       char *symbol;
+
+       /*
+        * Emit a function into the .ctor section which will be called by the ELF
+        * loader to register this module with the runtime.
+        */
+       if (! (!acfg->use_bin_writer && acfg->aot_opts.static_link && acfg->aot_opts.autoreg))
+               return;
+
+       symbol = g_strdup_printf ("_%s_autoreg", acfg->static_linking_symbol);
+
+       arch_emit_autoreg (acfg, symbol);
+
+       g_free (symbol);
+}      
+
 static void
 emit_mem_end (MonoAotCompile *acfg)
 {
@@ -4335,6 +5284,9 @@ emit_file_info (MonoAotCompile *acfg)
        emit_int32 (acfg, acfg->plt_got_offset_base);
        emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
        emit_int32 (acfg, acfg->plt_offset);
+       emit_int32 (acfg, acfg->nmethods);
+       emit_int32 (acfg, acfg->flags);
+       emit_int32 (acfg, acfg->opts);
 
        for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
                emit_int32 (acfg, acfg->num_trampolines [i]);
@@ -4344,6 +5296,20 @@ emit_file_info (MonoAotCompile *acfg)
                emit_int32 (acfg, acfg->trampoline_size [i]);
 }
 
+static void
+emit_blob (MonoAotCompile *acfg)
+{
+       char symbol [128];
+
+       sprintf (symbol, "blob");
+       emit_section_change (acfg, ".text", 1);
+       emit_global (acfg, symbol, FALSE);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+
+       emit_bytes (acfg, (guint8*)acfg->blob.data, acfg->blob.index);
+}
+
 static void
 emit_dwarf_info (MonoAotCompile *acfg)
 {
@@ -4358,6 +5324,10 @@ emit_dwarf_info (MonoAotCompile *acfg)
                if (!cfg)
                        continue;
 
+               // FIXME: LLVM doesn't define .Lme_...
+               if (cfg->compile_llvm)
+                       continue;
+
                sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
                sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
 
@@ -4394,6 +5364,21 @@ collect_methods (MonoAotCompile *acfg)
                        method = wrapper;
                }
 
+               /* FIXME: Some mscorlib methods don't have debug info */
+               /*
+               if (acfg->aot_opts.soft_debug && !method->wrapper_type) {
+                       if (!((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+                                 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
+                                 (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
+                                 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))) {
+                               if (!mono_debug_lookup_method (method)) {
+                                       fprintf (stderr, "Method %s has no debug info, probably the .mdb file for the assembly is missing.\n", mono_method_full_name (method, TRUE));
+                                       exit (1);
+                               }
+                       }
+               }
+               */
+
                /* 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, FALSE);
                acfg->method_index ++;
@@ -4471,13 +5456,27 @@ compile_asm (MonoAotCompile *acfg)
 {
        char *command, *objfile;
        char *outfile_name, *tmp_outfile_name;
+       const char *tool_prefix = acfg->aot_opts.tool_prefix ? acfg->aot_opts.tool_prefix : "";
 
 #if defined(TARGET_AMD64)
 #define AS_OPTIONS "--64"
+#elif defined(TARGET_POWERPC64)
+#define AS_OPTIONS "-a64 -mppc64"
+#define LD_OPTIONS "-m elf64ppc"
 #elif defined(sparc) && SIZEOF_VOID_P == 8
 #define AS_OPTIONS "-xarch=v9"
 #else
 #define AS_OPTIONS ""
+#endif
+
+#ifndef LD_OPTIONS
+#define LD_OPTIONS ""
+#endif
+
+#ifdef ENABLE_LLVM
+#define EH_LD_OPTIONS "--eh-frame-hdr"
+#else
+#define EH_LD_OPTIONS ""
 #endif
 
        if (acfg->aot_opts.asm_only) {
@@ -4495,7 +5494,7 @@ compile_asm (MonoAotCompile *acfg)
        } else {
                objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
        }
-       command = g_strdup_printf ("as %s %s -o %s", AS_OPTIONS, acfg->tmpfname, objfile);
+       command = g_strdup_printf ("%sas %s %s -o %s", tool_prefix, AS_OPTIONS, acfg->tmpfname, objfile);
        printf ("Executing the native assembler: %s\n", command);
        if (system (command) != 0) {
                g_free (command);
@@ -4523,10 +5522,10 @@ compile_asm (MonoAotCompile *acfg)
        command = g_strdup_printf ("ld -shared -G -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
 #elif defined(__ppc__) && defined(__MACH__)
        command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
-#elif defined(PLATFORM_WIN32)
+#elif defined(HOST_WIN32)
        command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
 #else
-       command = g_strdup_printf ("ld -shared -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
+       command = g_strdup_printf ("%sld %s %s -shared -o %s %s.o", tool_prefix, EH_LD_OPTIONS, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
 #endif
        printf ("Executing the native linker: %s\n", command);
        if (system (command) != 0) {
@@ -4549,7 +5548,7 @@ compile_asm (MonoAotCompile *acfg)
         * gas generates 'mapping symbols' each time code and data is mixed, which 
         * happens a lot in emit_and_reloc_code (), so we need to get rid of them.
         */
-       command = g_strdup_printf ("strip --strip-symbol=\\$a --strip-symbol=\\$d %s", tmp_outfile_name);
+       command = g_strdup_printf ("%sstrip --strip-symbol=\\$a --strip-symbol=\\$d %s", tool_prefix, tmp_outfile_name);
        printf ("Stripping the binary: %s\n", command);
        if (system (command) != 0) {
                g_free (tmp_outfile_name);
@@ -4579,13 +5578,18 @@ acfg_create (MonoAssembly *ass, guint32 opts)
 {
        MonoImage *image = ass->image;
        MonoAotCompile *acfg;
+       int i;
 
        acfg = g_new0 (MonoAotCompile, 1);
        acfg->methods = g_ptr_array_new ();
        acfg->method_indexes = g_hash_table_new (NULL, NULL);
+       acfg->method_depth = 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 (mono_patch_info_hash, mono_patch_info_equal);
        acfg->patch_to_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
+       acfg->patch_to_got_offset_by_type = g_new0 (GHashTable*, MONO_PATCH_INFO_NUM);
+       for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
+               acfg->patch_to_got_offset_by_type [i] = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
        acfg->got_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);
@@ -4615,12 +5619,15 @@ acfg_free (MonoAotCompile *acfg)
                        g_free (acfg->cfgs [i]);
        g_free (acfg->cfgs);
        g_free (acfg->static_linking_symbol);
+       g_free (acfg->got_symbol);
+       g_free (acfg->plt_symbol);
        g_ptr_array_free (acfg->methods, TRUE);
        g_ptr_array_free (acfg->got_patches, TRUE);
        g_ptr_array_free (acfg->image_table, TRUE);
        g_ptr_array_free (acfg->globals, TRUE);
        g_ptr_array_free (acfg->unwind_ops, TRUE);
        g_hash_table_destroy (acfg->method_indexes);
+       g_hash_table_destroy (acfg->method_depth);
        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_got_offset);
@@ -4629,6 +5636,9 @@ acfg_free (MonoAotCompile *acfg)
        g_hash_table_destroy (acfg->image_hash);
        g_hash_table_destroy (acfg->unwind_info_offsets);
        g_hash_table_destroy (acfg->method_label_hash);
+       for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
+               g_hash_table_destroy (acfg->patch_to_got_offset_by_type [i]);
+       g_free (acfg->patch_to_got_offset_by_type);
        mono_mempool_destroy (acfg->mempool);
        g_free (acfg);
 }
@@ -4650,9 +5660,13 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts));
        acfg->aot_opts.write_symbols = TRUE;
        acfg->aot_opts.ntrampolines = 1024;
+       acfg->aot_opts.nrgctx_trampolines = 1024;
 
        mono_aot_parse_options (aot_options, &acfg->aot_opts);
 
+       if (acfg->aot_opts.static_link)
+               acfg->aot_opts.autoreg = TRUE;
+
        //acfg->aot_opts.print_skipped_methods = TRUE;
 
 #ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
@@ -4665,22 +5679,47 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        if (acfg->aot_opts.static_link)
                acfg->aot_opts.asm_writer = TRUE;
 
+       if (acfg->aot_opts.soft_debug) {
+               MonoDebugOptions *opt = mini_get_debug_options ();
+
+               opt->mdb_optimizations = TRUE;
+               opt->gen_seq_points = TRUE;
+
+               if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) {
+                       fprintf (stderr, "The soft-debug AOT option requires the --debug option.\n");
+                       return 1;
+               }
+       }
+
+#ifdef ENABLE_LLVM
+       acfg->llvm = TRUE;
+       acfg->aot_opts.asm_writer = TRUE;
+       acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM;
+#endif
+
+       if (acfg->aot_opts.full_aot)
+               acfg->flags |= MONO_AOT_FILE_FLAG_FULL_AOT;
+
        load_profile_files (acfg);
 
        acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = acfg->aot_opts.full_aot ? acfg->aot_opts.ntrampolines : 0;
 #ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
-       acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? 1024 : 0;
+       acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? acfg->aot_opts.nrgctx_trampolines : 0;
 #endif
        acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? 128 : 0;
 
        acfg->got_symbol = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
+       acfg->plt_symbol = g_strdup_printf ("mono_aot_%s_plt", acfg->image->assembly->aname.name);
 
        /* Get rid of characters which cannot occur in symbols */
-       p = acfg->got_symbol;
        for (p = acfg->got_symbol; *p; ++p) {
                if (!(isalnum (*p) || *p == '_'))
                        *p = '_';
        }
+       for (p = acfg->plt_symbol; *p; ++p) {
+               if (!(isalnum (*p) || *p == '_'))
+                       *p = '_';
+       }
 
        acfg->method_index = 1;
 
@@ -4692,6 +5731,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        /* PLT offset 0 is reserved for the PLT trampoline */
        acfg->plt_offset = 1;
 
+#ifdef ENABLE_LLVM
+       llvm_acfg = acfg;
+       mono_llvm_create_aot_module (acfg->got_symbol);
+#endif
+
        /* GOT offset 0 is reserved for the address of the current assembly */
        {
                MonoJumpInfo *ji;
@@ -4701,6 +5745,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                ji->data.image = acfg->image;
 
                get_got_offset (acfg, ji);
+
+               /* Slot 1 is reserved for the mscorlib got addr */
+               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
+               ji->type = MONO_PATCH_INFO_MSCORLIB_GOT_ADDR;
+               get_got_offset (acfg, ji);
        }
 
        TV_GETTIME (atv);
@@ -4713,6 +5762,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        TV_GETTIME (atv);
 
+#ifdef ENABLE_LLVM
+       emit_llvm_file (acfg);
+#endif
+
        if (!acfg->aot_opts.asm_only && !acfg->aot_opts.asm_writer && bin_writer_supported ()) {
                if (acfg->aot_opts.outfile)
                        outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
@@ -4734,18 +5787,24 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                acfg->w = img_writer_create (acfg->fp, TRUE);
                acfg->use_bin_writer = TRUE;
        } else {
-               if (acfg->aot_opts.asm_only) {
-                       if (acfg->aot_opts.outfile)
-                               acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
-                       else
-                               acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
-                       acfg->fp = fopen (acfg->tmpfname, "w+");
+               if (acfg->llvm) {
+                       /* Append to the .s file created by llvm */
+                       /* FIXME: Use multiple files instead */
+                       acfg->tmpfname = g_strdup ("temp.s");
+                       acfg->fp = fopen (acfg->tmpfname, "a");
                } else {
-                       int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL);
-                       acfg->fp = fdopen (i, "w+");
+                       if (acfg->aot_opts.asm_only) {
+                               if (acfg->aot_opts.outfile)
+                                       acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+                               else
+                                       acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
+                               acfg->fp = fopen (acfg->tmpfname, "w+");
+                       } else {
+                               int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL);
+                               acfg->fp = fdopen (i, "w+");
+                       }
+                       g_assert (acfg->fp);
                }
-               g_assert (acfg->fp);
-
                acfg->w = img_writer_create (acfg->fp, FALSE);
                
                tmp_outfile_name = NULL;
@@ -4755,7 +5814,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->temp_prefix = img_writer_get_temp_label_prefix (acfg->w);
 
        if (!acfg->aot_opts.nodebug)
-               acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL);
+               acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE);
 
        img_writer_emit_start (acfg->w);
 
@@ -4768,8 +5827,6 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        emit_extra_methods (acfg);
 
-       emit_method_order (acfg);
-
        emit_trampolines (acfg);
 
        emit_class_name_table (acfg);
@@ -4790,10 +5847,16 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        emit_file_info (acfg);
 
+       emit_blob (acfg);
+
        emit_globals (acfg);
 
-       if (acfg->dwarf)
+       emit_autoreg (acfg);
+
+       if (acfg->dwarf) {
                emit_dwarf_info (acfg);
+               mono_dwarf_writer_close (acfg->dwarf);
+       }
 
        emit_mem_end (acfg);
 
@@ -4801,7 +5864,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        acfg->stats.gen_time = TV_ELAPSED (atv, btv);
 
-       printf ("Code: %d Info: %d Ex Info: %d Unwind Info: %d Class Info: %d PLT: %d GOT Info: %d GOT Info Offsets: %d GOT: %d Offsets: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.unwind_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)), (int)(acfg->nmethods * 3 * sizeof (gpointer)));
+       if (acfg->llvm)
+               g_assert (acfg->got_offset == acfg->final_got_size);
+
+       printf ("Code: %d Info: %d Ex Info: %d Unwind Info: %d Class Info: %d PLT: %d GOT Info: %d GOT: %d Offsets: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.unwind_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, (int)(acfg->got_offset * sizeof (gpointer)), acfg->stats.offsets_size);
 
        TV_GETTIME (atv);
        res = img_writer_emit_writeout (acfg->w);
@@ -4835,15 +5901,19 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                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);
+       if (acfg->llvm)
+               printf ("Methods compiled with LLVM: %d (%d%%)\n", acfg->stats.llvm_count, acfg->stats.mcount ? (acfg->stats.llvm_count * 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", get_patch_name (i), acfg->stats.got_slot_types [i]);
-       */
+       if (acfg->aot_opts.stats) {
+               int i;
+
+               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", get_patch_name (i), acfg->stats.got_slot_types [i]);
+       }
 
        printf ("JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000);
 
@@ -4867,8 +5937,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
  * into the runtime to emit the shared library, which would cause all kinds of
  * complications, like threading issues, and the fact that the ELF writer's
  * emit_writeout () function cannot be called more than once.
+ * GDB 7.0 and later has a JIT interface.
  */
 
+#define USE_GDB_JIT_INTERFACE
+
 /* The recommended gdb macro is: */
 /*
   define xdb
@@ -4877,26 +5950,95 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
   end
 */
 
+/*
+ * GDB JIT interface definitions.
+ *
+ *     http://sources.redhat.com/gdb/onlinedocs/gdb_30.html
+ */
+typedef enum
+{
+  JIT_NOACTION = 0,
+  JIT_REGISTER_FN,
+  JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry
+{
+  struct jit_code_entry *next_entry;
+  struct jit_code_entry *prev_entry;
+  const char *symfile_addr;
+  guint64 symfile_size;
+};
+
+struct jit_descriptor
+{
+  guint32 version;
+  /* This type should be jit_actions_t, but we use guint32
+     to be explicit about the bitwidth.  */
+  guint32 action_flag;
+  struct jit_code_entry *relevant_entry;
+  struct jit_code_entry *first_entry;
+};
+
+
+#ifdef _MSC_VER
+#define MONO_NOINLINE __declspec (noinline)
+#else
+#define MONO_NOINLINE __attribute__((noinline))
+#endif
+
+/* GDB puts a breakpoint in this function.  */
+void MONO_NOINLINE __jit_debug_register_code(void);
+
+#if defined(ENABLE_LLVM) && ((LLVM_MAJOR_VERSION == 2 && LLVM_MINOR_VERSION >= 7) || LLVM_MAJOR_VERSION > 2)
+/* LLVM already defines these */
+extern struct jit_descriptor __jit_debug_descriptor;
+#else
+
+/* Make sure to specify the version statically, because the
+   debugger may check the version before we can set it.  */
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+void MONO_NOINLINE __jit_debug_register_code(void) { };
+#endif
+
+static MonoImageWriter *xdebug_w;
 static MonoDwarfWriter *xdebug_writer;
-static FILE *xdebug_fp;
+static FILE *xdebug_fp, *il_file;
+static gboolean use_gdb_interface, save_symfiles;
+static int il_file_line_index;
+static GHashTable *xdebug_syms;
 
 void
-mono_xdebug_init (void)
+mono_xdebug_init (char *options)
 {
-       FILE *il_file;
        MonoImageWriter *w;
+       char **args, **ptr;
+
+       args = g_strsplit (options, ",", -1);
+       for (ptr = args; ptr && *ptr; ptr ++) {
+               char *arg = *ptr;
+
+               if (!strcmp (arg, "gdb"))
+                       use_gdb_interface = TRUE;
+               if (!strcmp (arg, "save-symfiles"))
+                       save_symfiles = TRUE;
+       }
+
+       /* This file will contain the IL code for methods which don't have debug info */
+       il_file = fopen ("xdb.il", "w");
+
+       if (use_gdb_interface)
+               return;
 
        unlink ("xdb.s");
        xdebug_fp = fopen ("xdb.s", "w");
-
+       
        w = img_writer_create (xdebug_fp, FALSE);
 
        img_writer_emit_start (w);
 
-       /* This file will contain the IL code for methods which don't have debug info */
-       il_file = fopen ("xdb.il", "w");
-
-       xdebug_writer = mono_dwarf_writer_create (w, il_file);
+       xdebug_writer = mono_dwarf_writer_create (w, il_file, 0, TRUE);
 
        /* Emit something so the file has a text segment */
        img_writer_emit_section_change (w, ".text", 0);
@@ -4905,6 +6047,95 @@ mono_xdebug_init (void)
        mono_dwarf_writer_emit_base_info (xdebug_writer, arch_get_cie_program ());
 }
 
+static void
+xdebug_begin_emit (MonoImageWriter **out_w, MonoDwarfWriter **out_dw)
+{
+       MonoImageWriter *w;
+       MonoDwarfWriter *dw;
+
+       w = img_writer_create (NULL, TRUE);
+
+       img_writer_emit_start (w);
+
+       /* This file will contain the IL code for methods which don't have debug info */
+       if (!il_file)
+               il_file = fopen ("xdb.il", "w");
+
+       dw = mono_dwarf_writer_create (w, il_file, il_file_line_index, FALSE);
+
+       mono_dwarf_writer_emit_base_info (dw, arch_get_cie_program ());
+
+       *out_w = w;
+       *out_dw = dw;
+}
+
+static void
+xdebug_end_emit (MonoImageWriter *w, MonoDwarfWriter *dw, MonoMethod *method)
+{
+       guint8 *img;
+       guint32 img_size;
+       struct jit_code_entry *entry;
+
+       il_file_line_index = mono_dwarf_writer_get_il_file_line_index (dw);
+       mono_dwarf_writer_close (dw);
+
+       img_writer_emit_writeout (w);
+
+       img = img_writer_get_output (w, &img_size);
+
+       img_writer_destroy (w);
+
+       if (FALSE) {
+               /* Save the symbol files to help debugging */
+               FILE *fp;
+               char *file_name;
+               static int file_counter;
+
+               file_counter ++;
+               file_name = g_strdup_printf ("xdb-%d.o", file_counter);
+               //printf ("%s -> %s\n", mono_method_full_name (method, TRUE), file_name);
+
+               fp = fopen (file_name, "w");
+               fwrite (img, img_size, 1, fp);
+               fclose (fp);
+               g_free (file_name);
+       }
+
+       /* Register the image with GDB */
+
+       entry = g_malloc (sizeof (struct jit_code_entry));
+
+       entry->symfile_addr = (const char*)img;
+       entry->symfile_size = img_size;
+
+       entry->next_entry = __jit_debug_descriptor.first_entry;
+       if (__jit_debug_descriptor.first_entry)
+               __jit_debug_descriptor.first_entry->prev_entry = entry;
+       __jit_debug_descriptor.first_entry = entry;
+       
+       __jit_debug_descriptor.relevant_entry = entry;
+       __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+
+       __jit_debug_register_code ();
+}
+
+/*
+ * mono_xdebug_flush:
+ *
+ *   This could be called from inside gdb to flush the debugging information not yet
+ * registered with gdb.
+ */
+void
+mono_xdebug_flush (void)
+{
+       if (xdebug_w)
+               xdebug_end_emit (xdebug_w, xdebug_writer, NULL);
+
+       xdebug_begin_emit (&xdebug_w, &xdebug_writer);
+}
+
+static int xdebug_method_count;
+
 /*
  * mono_save_xdebug_info:
  *
@@ -4915,13 +6146,52 @@ mono_xdebug_init (void)
 void
 mono_save_xdebug_info (MonoCompile *cfg)
 {
-       if (!xdebug_writer)
-               return;
+       if (use_gdb_interface) {
+               mono_loader_lock ();
+
+               if (!xdebug_syms)
+                       xdebug_syms = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+               /*
+                * gdb is not designed to handle 1000s of symbol files (one per method). So we
+                * group them into groups of 100.
+                */
+               if ((xdebug_method_count % 100) == 0)
+                       mono_xdebug_flush ();
+
+               xdebug_method_count ++;
 
-       mono_loader_lock ();
-       mono_dwarf_writer_emit_method (xdebug_writer, cfg, cfg->jit_info->method, NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ()));
-       fflush (xdebug_fp);
-       mono_loader_unlock ();
+               mono_dwarf_writer_emit_method (xdebug_writer, cfg, cfg->jit_info->method, NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ()));
+
+#if 0
+               /* 
+                * Emit a symbol for the code by emitting it at the beginning of the text 
+                * segment, and setting the text segment to have an absolute address.
+                * This symbol can be used to set breakpoints in gdb.
+                * FIXME: This doesn't work when multiple methods are emitted into the same file.
+                */
+               sym = get_debug_sym (cfg->jit_info->method, "", xdebug_syms);
+               img_writer_emit_section_change (w, ".text", 0);
+               if (!xdebug_text_addr) {
+                       xdebug_text_addr = cfg->jit_info->code_start;
+                       img_writer_set_section_addr (w, (gssize)xdebug_text_addr);
+               }
+               img_writer_emit_global_with_size (w, sym, cfg->jit_info->code_size, TRUE);
+               img_writer_emit_label (w, sym);
+               img_writer_emit_bytes (w, cfg->jit_info->code_start, cfg->jit_info->code_size);
+               g_free (sym);
+#endif
+               
+               mono_loader_unlock ();
+       } else {
+               if (!xdebug_writer)
+                       return;
+
+               mono_loader_lock ();
+               mono_dwarf_writer_emit_method (xdebug_writer, cfg, cfg->jit_info->method, NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ()));
+               fflush (xdebug_fp);
+               mono_loader_unlock ();
+       }
 }
 
 /*
@@ -4933,13 +6203,28 @@ mono_save_xdebug_info (MonoCompile *cfg)
 void
 mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info)
 {
-       if (!xdebug_writer)
-               return;
+       if (use_gdb_interface) {
+               MonoImageWriter *w;
+               MonoDwarfWriter *dw;
+
+               mono_loader_lock ();
+
+               xdebug_begin_emit (&w, &dw);
 
-       mono_loader_lock ();
-       mono_dwarf_writer_emit_trampoline (xdebug_writer, tramp_name, NULL, NULL, code, code_size, unwind_info);
-       fflush (xdebug_fp);
-       mono_loader_unlock ();
+               mono_dwarf_writer_emit_trampoline (dw, tramp_name, NULL, NULL, code, code_size, unwind_info);
+
+               xdebug_end_emit (w, dw, NULL);
+               
+               mono_loader_unlock ();
+       } else {
+               if (!xdebug_writer)
+                       return;
+
+               mono_loader_lock ();
+               mono_dwarf_writer_emit_trampoline (xdebug_writer, tramp_name, NULL, NULL, code, code_size, unwind_info);
+               fflush (xdebug_fp);
+               mono_loader_unlock ();
+       }
 }
 
 #else
@@ -4953,7 +6238,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 }
 
 void
-mono_xdebug_init (void)
+mono_xdebug_init (char *options)
 {
 }