New test.
[mono.git] / mono / mini / aot-compiler.c
index 46c45e45a69ce41fed133b141b6db31b6f7769fb..0afd5ba593f32b784d7f93d424757d18e01bd034 100644 (file)
@@ -21,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
@@ -33,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>
@@ -43,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>
@@ -57,7 +57,7 @@
 #include <mono/metadata/mempool-internals.h>
 #include <mono/metadata/mono-endian.h>
 #include <mono/metadata/threads-types.h>
-#include <mono/utils/mono-logger.h>
+#include <mono/utils/mono-logger-internal.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-time.h>
 #include <mono/utils/mono-mmap.h>
@@ -72,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"
@@ -96,17 +96,22 @@ typedef struct MonoAotOptions {
        gboolean asm_only;
        gboolean asm_writer;
        gboolean nodebug;
+       gboolean soft_debug;
        int nthreads;
        int ntrampolines;
+       int nrgctx_trampolines;
+       int nimt_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;
@@ -115,11 +120,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;
@@ -130,6 +137,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;
 
@@ -154,16 +162,24 @@ typedef struct MonoAotCompile {
        GHashTable *unwind_info_offsets;
        GPtrArray *unwind_ops;
        guint32 unwind_info_offset;
+       char *got_symbol_base;
        char *got_symbol;
        char *plt_symbol;
        GHashTable *method_label_hash;
        const char *temp_prefix;
+       const char *llvm_label_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
@@ -441,6 +457,23 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #define PPC_LDX_OP "lwzx"
 #endif
 
+//#define TARGET_ARM
+
+#ifdef TARGET_ARM
+#define LLVM_LABEL_PREFIX "_"
+#else
+#define LLVM_LABEL_PREFIX ""
+#endif
+
+#ifdef TARGET_ARM
+/* iphone */
+#define LLC_TARGET_ARGS "-march=arm -mattr=+v6 -mtriple=arm-apple-darwin"
+/* ELF */
+//#define LLC_TARGET_ARGS "-march=arm -mtriple=arm-linux-gnueabi -soft-float"
+#else
+#define LLC_TARGET_ARGS ""
+#endif
+
 /*
  * arch_emit_direct_call:
  *
@@ -616,7 +649,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');
@@ -632,7 +664,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) {
@@ -879,11 +910,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);
 
@@ -1099,29 +1130,70 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
 #endif
 }
 
-/*
- * arch_get_cie_program:
- *
- *   Get the unwind bytecode for the DWARF CIE.
- */
-static GSList*
-arch_get_cie_program (void)
+static void
+arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
 {
-#ifdef TARGET_AMD64
-       GSList *l = NULL;
-
-       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);
+#if defined(TARGET_POWERPC) && defined(__mono_ilp32__)
+       /* Based on code generated by gcc */
+       img_writer_emit_unset_mode (acfg->w);
 
-       return l;
-#elif defined(TARGET_POWERPC)
-       GSList *l = NULL;
+       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
 
-       mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
 
-       return l;
+       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
-       return NULL;
 #endif
 }
 
@@ -1178,6 +1250,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)
 {
@@ -1355,7 +1544,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);
@@ -1402,7 +1593,7 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                case MONO_WRAPPER_LDFLDA:
                case MONO_WRAPPER_STFLD:
                case MONO_WRAPPER_ISINST: {
-                       MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (method);
+                       MonoClass *proxy_class = mono_marshal_get_wrapper_info (method);
                        encode_klass_ref (acfg, proxy_class, p, &p);
                        break;
                }
@@ -1410,11 +1601,14 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                case MONO_WRAPPER_STFLD_REMOTE:
                        break;
                case MONO_WRAPPER_ALLOC: {
-                       int alloc_type = mono_gc_get_managed_allocator_type (method);
-                       g_assert (alloc_type != -1);
-                       encode_value (alloc_type, p, &p);
+                       AllocatorWrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+                       g_assert (info->alloc_type != -1);
+                       encode_value (info->alloc_type, p, &p);
                        break;
                }
+               case MONO_WRAPPER_WRITE_BARRIER:
+                       break;
                case MONO_WRAPPER_STELEMREF:
                        break;
                case MONO_WRAPPER_UNKNOWN:
@@ -1436,6 +1630,18 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                        encode_method_ref (acfg, m, p, &p);
                        break;
                }
+               case MONO_WRAPPER_MANAGED_TO_MANAGED:
+                       if (!strcmp (method->name, "ElementAddr")) {
+                               ElementAddrWrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+                               g_assert (info);
+                               encode_value (MONO_AOT_WRAPPER_ELEMENT_ADDR, p, &p);
+                               encode_value (info->rank, p, &p);
+                               encode_value (info->elem_size, p, &p);
+                       } else {
+                               g_assert_not_reached ();
+                       }
+                       break;
                default:
                        g_assert_not_reached ();
                }
@@ -1555,6 +1761,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;
@@ -1569,10 +1776,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;
@@ -1583,6 +1791,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));
@@ -1604,17 +1814,21 @@ 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;
 
        got_offset = acfg->got_offset;
        acfg->got_offset ++;
 
+       if (acfg->final_got_size)
+               g_assert (got_offset < acfg->final_got_size);
+
        acfg->stats.got_slots ++;
        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;
@@ -1646,7 +1860,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;
 
@@ -1660,6 +1874,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;
@@ -1668,13 +1884,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
@@ -1706,6 +1928,57 @@ 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 (!mono_class_from_mono_type (field->type)->enumtype && !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)
 {
@@ -1751,9 +2024,29 @@ 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
@@ -1816,6 +2109,15 @@ add_wrappers (MonoAotCompile *acfg)
                /* 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);
@@ -1901,7 +2203,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));
        }
 
@@ -1917,6 +2219,69 @@ add_wrappers (MonoAotCompile *acfg)
                        add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
                }
        }
+       /* native-to-managed wrappers */
+       for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoMethod *method;
+               guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+               MonoCustomAttrInfo *cattr;
+               int j;
+
+               method = mono_get_method (acfg->image, token, NULL);
+
+               /* 
+                * Only generate native-to-managed wrappers for methods which have an
+                * attribute named MonoPInvokeCallbackAttribute. We search for the attribute by
+                * name to avoid defining a new assembly to contain it.
+                */
+               cattr = mono_custom_attrs_from_method (method);
+
+               if (cattr) {
+                       for (j = 0; j < cattr->num_attrs; ++j)
+                               if (cattr->attrs [j].ctor && !strcmp (cattr->attrs [j].ctor->klass->name, "MonoPInvokeCallbackAttribute"))
+                                       break;
+                       if (j < cattr->num_attrs) {
+                               MonoCustomAttrEntry *e = &cattr->attrs [j];
+                               MonoMethodSignature *sig = mono_method_signature (e->ctor);
+                               const char *p = (const char*)e->data;
+                               int slen;
+                               char *n;
+                               MonoType *t;
+                               MonoClass *klass;
+
+                               g_assert (method->flags & METHOD_ATTRIBUTE_STATIC);
+
+                               g_assert (sig->param_count == 1);
+                               g_assert (sig->params [0]->type == MONO_TYPE_CLASS && !strcmp (mono_class_from_mono_type (sig->params [0])->name, "Type"));
+
+                               /* 
+                                * Decode the cattr manually since we can't create objects
+                                * during aot compilation.
+                                */
+                                       
+                               /* Skip prolog */
+                               p += 2;
+
+                               /* From load_cattr_value () in reflection.c */
+                               slen = mono_metadata_decode_value (p, &p);
+                               n = g_memdup (p, slen + 1);
+                               n [slen] = 0;
+                               t = mono_reflection_type_from_name (n, acfg->image);
+                               g_assert (t);
+                               g_free (n);
+
+                               klass = mono_class_from_mono_type (t);
+                               g_assert (klass->parent == mono_defaults.multicastdelegate_class);
+
+                               add_method (acfg, mono_marshal_get_managed_wrapper (method, klass, NULL));
+                       }
+               }
+
+               if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+                       (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
+                       add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
+               }
+       }
 
        /* StructureToPtr/PtrToStructure wrappers */
        for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
@@ -1925,38 +2290,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)) {
-                       gboolean can_marshal = TRUE;
-                       gpointer iter = NULL;
-                       MonoClassField *field;
-
-                       /* Only allow a few field types to avoid asserts in the marshalling code */
-                       while ((field = mono_class_get_fields (klass, &iter))) {
-                               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_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));
                }
        }
 }
@@ -2024,7 +2360,7 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
 
        iter = NULL;
        while ((method = mono_class_get_methods (klass, &iter))) {
-               if (mono_method_is_generic_sharable_impl (method, FALSE))
+               if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
                        /* Already added */
                        continue;
 
@@ -2048,12 +2384,11 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
        }
 
        /* 
-        * 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;
@@ -2080,23 +2415,50 @@ 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_array_wrappers (MonoAotCompile *acfg, MonoClass *klass)
+add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int ninsts)
 {
        int i;
+       MonoGenericContext ctx;
+       MonoType *args [16];
 
-       mono_class_setup_methods (klass);
-       for (i = 0; i < klass->method.count; ++i) {
-               if (klass->methods [i]->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED)
-                       add_extra_method (acfg, klass->methods [i]);
+       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));
        }
 }
 
@@ -2119,18 +2481,98 @@ add_generic_instances (MonoAotCompile *acfg)
                token = MONO_TOKEN_METHOD_SPEC | (i + 1);
                method = mono_get_method (acfg->image, token, NULL);
 
-               context = mono_method_get_context (method);
-               if (context && ((context->class_inst && context->class_inst->is_open) ||
-                                               (context->method_inst && context->method_inst->is_open)))
+               if (method->klass->image != acfg->image)
                        continue;
 
-               if (method->klass->image != acfg->image)
+               context = mono_method_get_context (method);
+
+               if (context && ((context->class_inst && context->class_inst->is_open)))
                        continue;
 
-               if (mono_method_is_generic_sharable_impl (method, FALSE))
-                       /* Already added */
+               /*
+                * For open methods, create an instantiation which can be passed to the JIT.
+                * FIXME: Handle class_inst as well.
+                */
+               if (context && context->method_inst && context->method_inst->is_open) {
+                       MonoGenericContext shared_context;
+                       MonoGenericInst *inst;
+                       MonoType **type_argv;
+                       int i;
+                       MonoMethod *declaring_method;
+                       gboolean supported = TRUE;
+
+                       /* Check that the context doesn't contain open constructed types */
+                       if (context->class_inst) {
+                               inst = context->class_inst;
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               continue;
+                                       if (mono_class_is_open_constructed_type (inst->type_argv [i]))
+                                               supported = FALSE;
+                               }
+                       }
+                       if (context->method_inst) {
+                               inst = context->method_inst;
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               continue;
+                                       if (mono_class_is_open_constructed_type (inst->type_argv [i]))
+                                               supported = FALSE;
+                               }
+                       }
+
+                       if (!supported)
+                               continue;
+
+                       memset (&shared_context, 0, sizeof (MonoGenericContext));
+
+                       inst = context->class_inst;
+                       if (inst) {
+                               type_argv = g_new0 (MonoType*, inst->type_argc);
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               type_argv [i] = &mono_defaults.object_class->byval_arg;
+                                       else
+                                               type_argv [i] = inst->type_argv [i];
+                               }
+                               
+                               shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+                               g_free (type_argv);
+                       }
+
+                       inst = context->method_inst;
+                       if (inst) {
+                               type_argv = g_new0 (MonoType*, inst->type_argc);
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               type_argv [i] = &mono_defaults.object_class->byval_arg;
+                                       else
+                                               type_argv [i] = inst->type_argv [i];
+                               }
+
+                               shared_context.method_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+                               g_free (type_argv);
+                       }
+
+                       if (method->is_generic || method->klass->generic_container)
+                               declaring_method = method;
+                       else
+                               declaring_method = mono_method_get_declaring_generic_method (method);
+
+                       method = mono_class_inflate_generic_method (declaring_method, &shared_context);
+               }
+
+               /* 
+                * If the method is fully sharable, it was already added in place of its
+                * generic definition.
+                */
+               if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
                        continue;
 
+               /*
+                * FIXME: Partially shared methods are not shared here, so we end up with
+                * many identical methods.
+                */
                add_extra_method (acfg, method);
        }
 
@@ -2170,124 +2612,60 @@ add_generic_instances (MonoAotCompile *acfg)
        }
 
        if (acfg->image == mono_defaults.corlib) {
-               /* Add GenericComparer<T> instances for primitive types for Enum.ToString () */
-               MonoClass *klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
-
-               if (klass) {
-                       MonoGenericContext ctx;
-                       MonoType *args [16];
-
-                       memset (&ctx, 0, sizeof (ctx));
-
-                       args [0] = &mono_defaults.byte_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.sbyte_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.int16_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.uint16_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.int32_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.uint32_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.int64_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.uint64_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-               }
+               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 GenericEqualityComparer<T> instances for primitive types */
+               /* 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);
 
-               if (klass) {
-                       MonoGenericContext ctx;
-                       MonoType *args [16];
-
-                       memset (&ctx, 0, sizeof (ctx));
-
-                       args [0] = &mono_defaults.byte_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.sbyte_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.int16_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.uint16_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.int32_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.uint32_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.int64_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-
-                       args [0] = &mono_defaults.uint64_class->byval_arg;
-                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
-               }
-
-               /* Emit the array wrapper methods for arrays of primitive types */
-               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.byte_class, 1));
-               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.sbyte_class, 1));
-               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int16_class, 1));
-               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.uint16_class, 1));
-               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int32_class, 1));
-               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.uint32_class, 1));
-               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int64_class, 1));
-               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.single_class, 1));
-               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.double_class, 1));
-               /* These are not handled by generic sharing */
-               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.object_class, 1));
-               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.string_class, 1));
-
-               /* Add instances of Array.GetGenericValueImpl */
+               /* 
+                * 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 *method;
+                       MonoMethod *get_method;
+                       MonoClass *array_klass = mono_array_class_get (mono_defaults.object_class, 1)->parent;
 
-                       memset (&ctx, 0, sizeof (ctx));
-
-                       /* 
-                        * managed-to-native wrappers are not shared, so have to generate 
-                        * these for ref types too.
-                        */
-                       klass = mono_array_class_get (mono_defaults.int_class, 1)->parent;
-                       method = mono_class_get_method_from_name (klass, "GetGenericValueImpl", 2);
+                       get_method = mono_class_get_method_from_name (array_klass, "GetGenericValueImpl", 2);
 
-                       if (method) {
-                               /* String */
-                               args [0] = &mono_defaults.string_class->byval_arg;
+                       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 (method, &ctx), TRUE, TRUE));
+                               add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (get_method, &ctx), TRUE, TRUE));
                        }
                }
        }
@@ -2390,7 +2768,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                                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));
+                                               sprintf (direct_call_target, callee_cfg->asm_symbol);
                                                patch_info->type = MONO_PATCH_INFO_NONE;
                                                acfg->stats.direct_calls ++;
                                        }
@@ -2403,7 +2781,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                        if (plt_offset != -1) {
                                                /* This patch has a PLT entry, so we must emit a call to the PLT entry */
                                                direct_call = TRUE;
-                                               sprintf (direct_call_target, "%sp_%d", acfg->temp_prefix, plt_offset);
+                                               sprintf (direct_call_target, "%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, plt_offset);
                
                                                /* Nullify the patch */
                                                patch_info->type = MONO_PATCH_INFO_NONE;
@@ -2520,29 +2898,10 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
 
        method_index = get_method_index (acfg, method);
 
-       /* Emit unbox trampoline */
-       if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
-               char call_target [256];
-
-               if (!method->wrapper_type && !method->is_inflated) {
-                       g_assert (method->token);
-                       sprintf (symbol, "ut_%d", mono_metadata_token_index (method->token) - 1);
-               } else {
-                       sprintf (symbol, "ut_e_%d", get_method_index (acfg, method));
-               }
-
-               emit_section_change (acfg, ".text", 0);
-               emit_global (acfg, symbol, TRUE);
-               emit_label (acfg, symbol);
-
-               sprintf (call_target, "%sm_%x", acfg->temp_prefix, method_index);
-
-               arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
-       }
-
        /* Make the labels local */
-       sprintf (symbol, "%sm_%x", acfg->temp_prefix, method_index);
+       sprintf (symbol, "%s", cfg->asm_symbol);
 
+       emit_section_change (acfg, ".text", 0);
        emit_alignment (acfg, func_alignment);
        emit_label (acfg, symbol);
 
@@ -2660,8 +3019,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:
@@ -2692,6 +3051,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);
@@ -2713,7 +3077,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;
 
@@ -2731,7 +3095,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;
@@ -2745,9 +3108,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)
@@ -2813,12 +3173,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);
 }
 
@@ -2859,15 +3216,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;
@@ -2875,9 +3232,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 {
@@ -2885,16 +3239,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) {
@@ -2913,14 +3268,44 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        }
 
        /* Exception table */
-       if (header->num_clauses) {
+       if (cfg->compile_llvm) {
+               /* The assembly might be CIL stripped so emit the data ourselves */
+               if (header->num_clauses)
+                       encode_value (header->num_clauses, p, &p);
+
                for (k = 0; k < header->num_clauses; ++k) {
+                       MonoExceptionClause *clause;
+
+                       clause = &header->clauses [k];
+
+                       encode_value (clause->flags, p, &p);
+                       if (clause->data.catch_class) {
+                               encode_value (1, p, &p);
+                               encode_klass_ref (acfg, clause->data.catch_class, p, &p);
+                       } else {
+                               encode_value (0, p, &p);
+                       }
+               }
+       } else {
+               if (jinfo->num_clauses)
+                       encode_value (jinfo->num_clauses, p, &p);
+
+               for (k = 0; k < jinfo->num_clauses; ++k) {
                        MonoJitExceptionInfo *ei = &jinfo->clauses [k];
 
+                       encode_value (ei->flags, p, &p);
                        encode_value (ei->exvar_offset, 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);
@@ -2942,6 +3327,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);
@@ -2953,22 +3359,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;
 
@@ -3005,7 +3408,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)
@@ -3028,13 +3431,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;
 }
 
 /*
@@ -3072,13 +3473,30 @@ emit_plt (MonoAotCompile *acfg)
        for (i = 0; i < acfg->plt_offset; ++i) {
                char label [128];
                char *debug_sym = NULL;
+               MonoJumpInfo *ji;
+
+               sprintf (label, "%s%sp_%d", acfg->llvm_label_prefix, 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, %s\n", label, callee_cfg->asm_symbol);
+                               continue;
+                       }
+               }
 
-               sprintf (label, "%sp_%d", acfg->temp_prefix, i);
                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));
-                       char *debug_sym = NULL;
 
                        if (ji) {
                                switch (ji->type) {
@@ -3145,7 +3563,7 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
 {
        char start_symbol [256];
        char symbol [256];
-       guint32 buf_size;
+       guint32 buf_size, info_offset;
        MonoJumpInfo *patch_info;
        guint8 *buf, *p;
        GPtrArray *patches;
@@ -3188,11 +3606,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) {
@@ -3225,7 +3645,7 @@ emit_trampolines (MonoAotCompile *acfg)
        
        g_assert (acfg->image->assembly);
 
-       /* Currently, we only emit most trampolines into the mscorlib AOT image. */
+       /* Currently, we emit most trampolines into the mscorlib AOT image. */
        if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
                /*
@@ -3266,8 +3686,10 @@ emit_trampolines (MonoAotCompile *acfg)
                emit_trampoline (acfg, "throw_exception", code, code_size, acfg->got_offset, ji, NULL);
                code = mono_arch_get_rethrow_exception_full (&code_size, &ji, TRUE);
                emit_trampoline (acfg, "rethrow_exception", code, code_size, acfg->got_offset, ji, NULL);
+#ifdef MONO_ARCH_HAVE_THROW_EXCEPTION_BY_NAME
                code = mono_arch_get_throw_exception_by_name_full (&code_size, &ji, TRUE);
                emit_trampoline (acfg, "throw_exception_by_name", code, code_size, acfg->got_offset, ji, NULL);
+#endif
                code = mono_arch_get_throw_corlib_exception_full (&code_size, &ji, TRUE);
                emit_trampoline (acfg, "throw_corlib_exception", code, code_size, acfg->got_offset, ji, NULL);
 
@@ -3437,8 +3859,20 @@ 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, "nimt-trampolines=")) {
+                       opts->nimt_trampolines = atoi (arg + strlen ("nimt-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);
@@ -3497,7 +3931,13 @@ can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
                        case MONO_WRAPPER_ALLOC:
                        case MONO_WRAPPER_REMOTING_INVOKE:
                        case MONO_WRAPPER_UNKNOWN:
+                       case MONO_WRAPPER_WRITE_BARRIER:
                                break;
+                       case MONO_WRAPPER_MANAGED_TO_MANAGED:
+                               if (!strcmp (method->name, "ElementAddr"))
+                                       return TRUE;
+                               else
+                                       return FALSE;
                        default:
                                //printf ("Skip (wrapper call): %d -> %s\n", patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
                                return FALSE;
@@ -3554,7 +3994,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)
@@ -3678,34 +4118,43 @@ 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);
+                               if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED && !strcmp (m->name, "ElementAddr"))
+                                       add_extra_method_with_depth (acfg, m, depth + 1);
+                               break;
                        }
-                       break;
-               }
-               case MONO_PATCH_INFO_VTABLE: {
-                       MonoClass *klass = patch_info->data.klass;
+                       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;
+                               if (klass->generic_class && !mono_generic_context_is_sharable (&klass->generic_class->context, FALSE))
+                                       add_generic_class (acfg, klass);
+                               break;
+                       }
+                       default:
+                               break;
+                       }
                }
        }
 
@@ -3730,6 +4179,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;
@@ -3847,7 +4299,7 @@ load_profile_files (MonoAotCompile *acfg)
 
        file_index = 0;
        while (TRUE) {
-               tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg->image->assembly_name, acfg->image->guid, file_index);
+               tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%d", g_get_home_dir (), acfg->image->assembly_name, file_index);
 
                if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) {
                        g_free (tmp);
@@ -3863,21 +4315,38 @@ load_profile_files (MonoAotCompile *acfg)
                file_index ++;
 
                res = fscanf (infile, "%32s\n", ver);
-               if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
+               if ((res != 1) || strcmp (ver, "#VER:2") != 0) {
                        printf ("Profile file has wrong version or invalid.\n");
                        fclose (infile);
                        continue;
                }
 
                while (TRUE) {
-                       res = fscanf (infile, "%d\n", &token);
-                       if (res < 1)
+                       char name [1024];
+                       MonoMethodDesc *desc;
+                       MonoMethod *method;
+
+                       if (fgets (name, 1023, infile) == NULL)
                                break;
 
-                       method_index = mono_metadata_token_index (token) - 1;
+                       /* Kill the newline */
+                       if (strlen (name) > 0)
+                               name [strlen (name) - 1] = '\0';
+
+                       desc = mono_method_desc_new (name, TRUE);
+
+                       method = mono_method_desc_search_in_image (desc, acfg->image);
 
-                       if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
-                               acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+                       if (method && mono_method_get_token (method)) {
+                               token = mono_method_get_token (method);
+                               method_index = mono_metadata_token_index (token) - 1;
+
+                               if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index))) {
+                                       acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+                               }
+                       } else {
+                               //printf ("No method found matching '%s'.\n", name);
+                       }
                }
                fclose (infile);
        }
@@ -3894,12 +4363,152 @@ 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);
+
+       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 ("%sp_%d", llvm_acfg->temp_prefix, 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;
+       char *llc_target_args;
+
+       /*
+        * 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;
+
+       if (acfg->aot_opts.full_aot) {
+               int ntype;
+
+               /* 
+                * Need to add the got entries used by the trampolines.
+                * This is only a conservative approximation.
+                */
+               if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
+                       /* For the generic + rgctx trampolines */
+                       acfg->final_got_size += 200;
+                       /* For the specific trampolines */
+                       for (ntype = 0; ntype < MONO_AOT_TRAMP_NUM; ++ntype)
+                               acfg->final_got_size += acfg->num_trampolines [ntype] * 2;
+               }
+       }
+
+
+       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'
+        * The opt list below was produced by taking the output of:
+        * llvm-as < /dev/null | opt -O2 -disable-output -debug-pass=Arguments
+        * then removing tailcallelim + the global opts, and adding a second gvn.
+        */
+       opts = g_strdup ("-instcombine -simplifycfg");
+       opts = g_strdup ("-simplifycfg -domtree -domfrontier -scalarrepl -instcombine -simplifycfg -basiccg -prune-eh -inline -functionattrs -domtree -domfrontier -scalarrepl -simplify-libcalls -instcombine -jump-threading -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loopsimplify -domfrontier -loopsimplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loopsimplify -lcssa -iv-users -indvars -loop-deletion -loopsimplify -lcssa -loop-unroll -instcombine -memdep -gvn -memdep -memcpyopt -sccp -instcombine -jump-threading -domtree -memdep -dse -adce -gvn -simplifycfg -preverify -domtree -verify");
+#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);
+
+       llc_target_args = g_strdup (LLC_TARGET_ARGS);
+
+       command = g_strdup_printf ("llc %s -f -relocation-model=pic -unwind-tables -o %s temp.opt.bc", llc_target_args, acfg->tmpfname);
+       g_free (llc_target_args);
+
+       printf ("Executing llc: %s\n", command);
+
+       if (system (command) != 0) {
+               exit (1);
+       }
+}
+#endif
 
 static void
 emit_code (MonoAotCompile *acfg)
 {
        int i;
        char symbol [256];
+       char end_symbol [256];
        GList *l;
 
 #if defined(TARGET_POWERPC64)
@@ -3910,11 +4519,28 @@ emit_code (MonoAotCompile *acfg)
        emit_pointer (acfg, acfg->got_symbol);
 #endif
 
+       /* 
+        * This global symbol is used to compute the address of each method using the
+        * code_offsets array. It is also used to compute the memory ranges occupied by
+        * AOT code, so it must be equal to the address of the first emitted method.
+        */
        sprintf (symbol, "methods");
        emit_section_change (acfg, ".text", 0);
        emit_global (acfg, symbol, TRUE);
        emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
+       if (acfg->llvm) {
+               for (i = 0; i < acfg->nmethods; ++i) {
+                       if (acfg->cfgs [i] && acfg->cfgs [i]->compile_llvm) {
+                               fprintf (acfg->fp, "\n.set methods, %s\n", acfg->cfgs [i]->asm_symbol);
+                               break;
+                       }
+               }
+               if (i == acfg->nmethods)
+                       /* No LLVM compiled methods */
+                       emit_label (acfg, symbol);
+       } else {
+               emit_label (acfg, symbol);
+       }
 
        /* 
         * Emit some padding so the local symbol for the first method doesn't have the
@@ -3923,10 +4549,42 @@ emit_code (MonoAotCompile *acfg)
        emit_zero_bytes (acfg, 16);
 
        for (l = acfg->method_order; l != NULL; l = l->next) {
+               MonoCompile *cfg;
+               MonoMethod *method;
+
                i = GPOINTER_TO_UINT (l->data);
 
-               if (acfg->cfgs [i])
-                       emit_method_code (acfg, acfg->cfgs [i]);
+               cfg = acfg->cfgs [i];
+
+               if (!cfg)
+                       continue;
+
+               method = cfg->orig_method;
+
+               /* Emit unbox trampoline */
+               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+                       char call_target [256];
+
+                       if (!method->wrapper_type && !method->is_inflated) {
+                               g_assert (method->token);
+                               sprintf (symbol, "ut_%d", mono_metadata_token_index (method->token) - 1);
+                       } else {
+                               sprintf (symbol, "ut_e_%d", get_method_index (acfg, method));
+                       }
+
+                       emit_section_change (acfg, ".text", 0);
+                       emit_global (acfg, symbol, TRUE);
+                       emit_label (acfg, symbol);
+
+                       sprintf (call_target, "%s", cfg->asm_symbol);
+
+                       arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
+               }
+
+               if (cfg->compile_llvm)
+                       acfg->stats.llvm_count ++;
+               else
+                       emit_method_code (acfg, cfg);
        }
 
        sprintf (symbol, "methods_end");
@@ -3935,16 +4593,18 @@ 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;
+
+       sprintf (end_symbol, "methods");
        for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
-                       sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
-                       emit_symbol_diff (acfg, symbol, "methods", 0);
+                       emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, end_symbol, 0);
                } else {
                        emit_int32 (acfg, 0xffffffff);
                }
@@ -3958,23 +4618,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");
@@ -3983,40 +4639,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; \
@@ -4047,11 +4676,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;
        }
@@ -4090,14 +4719,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++) {
@@ -4149,16 +4782,15 @@ mono_aot_wrapper_name (MonoMethod *method)
 
        switch (method->wrapper_type) {
        case MONO_WRAPPER_RUNTIME_INVOKE:
-       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 */
-               name = g_strdup_printf ("%s (%s)", method->name, tmpsig);
+               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;
        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;
        }
 
@@ -4167,6 +4799,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:
  *
@@ -4211,14 +4886,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);
@@ -4227,8 +4896,12 @@ emit_extra_methods (MonoAotCompile *acfg)
                if (!cfg)
                        continue;
 
+               buf_size = 512;
+               p = buf = g_malloc (buf_size);
+
                nmethods ++;
-               info_offsets [i] = p - buf;
+
+               method = cfg->method_to_register;
 
                name = NULL;
                if (method->wrapper_type) {
@@ -4265,20 +4938,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
@@ -4306,8 +4969,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;
 
@@ -4334,9 +4996,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);
 
@@ -4345,7 +5005,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)
@@ -4375,89 +5035,31 @@ emit_extra_methods (MonoAotCompile *acfg)
 }      
 
 static void
-emit_method_order (MonoAotCompile *acfg)
+emit_exception_info (MonoAotCompile *acfg)
 {
-       int i, index, len;
+       int i;
        char symbol [256];
-       GList *l;
+       gint32 *offsets;
+
+       offsets = g_new0 (gint32, acfg->nmethods);
+       for (i = 0; i < acfg->nmethods; ++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, "method_order");
+       sprintf (symbol, "ex_info_offsets");
        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];
-
-       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);
-
-       for (i = 0; i < acfg->nmethods; ++i) {
-               if (acfg->cfgs [i])
-                       emit_exception_debug_info (acfg, acfg->cfgs [i]);
-       }
-
-       sprintf (symbol, "ex_info_offsets");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       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
 emit_unwind_info (MonoAotCompile *acfg)
@@ -4500,15 +5102,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);
@@ -4516,11 +5114,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 {
@@ -4550,7 +5145,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 */
@@ -4678,25 +5273,18 @@ emit_got_info (MonoAotCompile *acfg)
        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");
@@ -4706,10 +5294,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
@@ -4717,17 +5302,19 @@ emit_got (MonoAotCompile *acfg)
 {
        char symbol [256];
 
-       /* 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)));
+       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);
@@ -4737,22 +5324,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);
@@ -4765,42 +5448,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
@@ -4822,10 +5476,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)
 {
@@ -4858,6 +5532,8 @@ emit_file_info (MonoAotCompile *acfg)
        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]);
@@ -4867,6 +5543,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)
 {
@@ -4881,7 +5571,11 @@ emit_dwarf_info (MonoAotCompile *acfg)
                if (!cfg)
                        continue;
 
-               sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
+               // FIXME: LLVM doesn't define .Lme_...
+               if (cfg->compile_llvm)
+                       continue;
+
+               sprintf (symbol, "%s", cfg->asm_symbol);
                sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
 
                mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, symbol, symbol2, 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 ()));
@@ -4917,6 +5611,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 ++;
@@ -5009,6 +5718,12 @@ compile_asm (MonoAotCompile *acfg)
 
 #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) {
@@ -5054,10 +5769,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 ("%sld %s -shared -o %s %s.o", tool_prefix, LD_OPTIONS, 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) {
@@ -5110,13 +5825,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);
@@ -5154,6 +5874,7 @@ acfg_free (MonoAotCompile *acfg)
        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);
@@ -5162,6 +5883,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);
 }
@@ -5170,7 +5894,7 @@ int
 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 {
        MonoImage *image = ass->image;
-       int res;
+       int i, res;
        MonoAotCompile *acfg;
        char *outfile_name, *tmp_outfile_name, *p;
        TV_DECLARE (atv);
@@ -5183,9 +5907,14 @@ 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;
+       acfg->aot_opts.nimt_trampolines = 128;
 
        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
@@ -5198,19 +5927,40 @@ 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->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? acfg->aot_opts.nimt_trampolines : 0;
 
-       acfg->got_symbol = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
+       acfg->got_symbol_base = 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 */
-       for (p = acfg->got_symbol; *p; ++p) {
+       for (p = acfg->got_symbol_base; *p; ++p) {
                if (!(isalnum (*p) || *p == '_'))
                        *p = '_';
        }
@@ -5219,6 +5969,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        *p = '_';
        }
 
+       acfg->temp_prefix = img_writer_get_temp_label_prefix (NULL);
+
        acfg->method_index = 1;
 
        collect_methods (acfg);
@@ -5229,6 +5981,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_base);
+#endif
+
        /* GOT offset 0 is reserved for the address of the current assembly */
        {
                MonoJumpInfo *ji;
@@ -5255,6 +6012,21 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        TV_GETTIME (atv);
 
+#ifdef ENABLE_LLVM
+       if (acfg->llvm) {
+               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);
+               } else {
+                       acfg->tmpfname = g_strdup ("temp.s");
+               }
+       }
+
+       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);
@@ -5276,33 +6048,58 @@ 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->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;
                outfile_name = NULL;
        }
 
-       acfg->temp_prefix = img_writer_get_temp_label_prefix (acfg->w);
+       /*
+        * The prefix LLVM likes to put in front of symbol names on darwin.
+        * The mach-os specs require this for globals, but LLVM puts them in front of all
+        * symbols. We need to handle this, since we need to refer to LLVM generated
+        * symbols.
+        */
+       acfg->llvm_label_prefix = "";
+       if (acfg->llvm)
+               acfg->llvm_label_prefix = LLVM_LABEL_PREFIX;
+
+       acfg->got_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, acfg->got_symbol_base);
+
+       /* Compute symbols for methods */
+       for (i = 0; i < acfg->nmethods; ++i) {
+               if (acfg->cfgs [i]) {
+                       MonoCompile *cfg = acfg->cfgs [i];
+                       int method_index = get_method_index (acfg, cfg->orig_method);
+
+                       cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, LLVM_LABEL_PREFIX, method_index);
+               }
+       }
 
        if (!acfg->aot_opts.nodebug)
-               acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, FALSE);
+               acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE);
 
        img_writer_emit_start (acfg->w);
 
        if (acfg->dwarf)
-               mono_dwarf_writer_emit_base_info (acfg->dwarf, arch_get_cie_program ());
+               mono_dwarf_writer_emit_base_info (acfg->dwarf, mono_unwind_get_cie_program ());
 
        emit_code (acfg);
 
@@ -5310,8 +6107,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);
@@ -5332,8 +6127,12 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        emit_file_info (acfg);
 
+       emit_blob (acfg);
+
        emit_globals (acfg);
 
+       emit_autoreg (acfg);
+
        if (acfg->dwarf) {
                emit_dwarf_info (acfg);
                mono_dwarf_writer_close (acfg->dwarf);
@@ -5345,7 +6144,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);
@@ -5379,15 +6181,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);
 
@@ -5395,96 +6201,6 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        
        return 0;
 }
-/*
- * Support for emitting debug info for JITted code.
- *
- *   This works as follows:
- * - the runtime writes out an xdb.s file containing DWARF debug info.
- * - the user calls a gdb macro
- * - the macro compiles and loads this shared library using add-symbol-file.
- *
- * This is based on the xdebug functionality in the Kaffe Java VM.
- * 
- * We emit assembly code instead of using the ELF writer, so we can emit debug info
- * incrementally as each method is JITted, and the debugger doesn't have to call
- * 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.
- */
-
-/* The recommended gdb macro is: */
-/*
-  define xdb
-  shell rm -f xdb.so && as --64 -o xdb.o xdb.s && ld -shared -o xdb.so xdb.o
-  add-symbol-file xdb.so 0
-  end
-*/
-
-static MonoDwarfWriter *xdebug_writer;
-static FILE *xdebug_fp;
-
-void
-mono_xdebug_init (void)
-{
-       FILE *il_file;
-       MonoImageWriter *w;
-
-       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, TRUE);
-
-       /* Emit something so the file has a text segment */
-       img_writer_emit_section_change (w, ".text", 0);
-       img_writer_emit_string (w, "");
-
-       mono_dwarf_writer_emit_base_info (xdebug_writer, arch_get_cie_program ());
-}
-
-/*
- * mono_save_xdebug_info:
- *
- *   Emit debugging info for METHOD into an assembly file which can be assembled
- * and loaded into gdb to provide debugging info for JITted code.
- * LOCKING: Acquires the loader lock.
- */
-void
-mono_save_xdebug_info (MonoCompile *cfg)
-{
-       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 ();
-}
-
-/*
- * mono_save_trampoline_xdebug_info:
- *
- *   Same as mono_save_xdebug_info, but for trampolines.
- * LOCKING: Acquires the loader lock.
- */
-void
-mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info)
-{
-       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
 
@@ -5496,19 +6212,4 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        return 0;
 }
 
-void
-mono_xdebug_init (void)
-{
-}
-
-void
-mono_save_xdebug_info (MonoCompile *cfg)
-{
-}
-
-void
-mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info)
-{
-}
-
 #endif