2010-01-18 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-compiler.c
index 9c27d85ae54911aa103cd5a8bb09cb5b15884823..cb1fc0e368fe3344632c5ef0d9ddc5fd7c158e25 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>
@@ -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"
@@ -99,16 +99,18 @@ typedef struct MonoAotOptions {
        gboolean soft_debug;
        int nthreads;
        int ntrampolines;
+       int nrgctx_trampolines;
        gboolean print_skipped_methods;
+       gboolean stats;
        char *tool_prefix;
        gboolean autoreg;
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
        int ccount, mcount, lmfcount, abscount, gcount, ocount, genericcount;
-       int code_size, info_size, ex_info_size, unwind_info_size, got_size, class_info_size, got_info_size, got_info_offsets_size;
+       int 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;
+       int got_slots, offsets_size;
        int got_slot_types [MONO_PATCH_INFO_NONE];
        int jit_time, gen_time, link_time;
 } MonoAotStats;
@@ -117,6 +119,7 @@ typedef struct MonoAotCompile {
        MonoImage *image;
        GPtrArray *methods;
        GHashTable *method_indexes;
+       GHashTable *method_depth;
        MonoCompile **cfgs;
        int cfgs_size;
        GHashTable *patch_to_plt_offset;
@@ -164,6 +167,8 @@ typedef struct MonoAotCompile {
        const char *temp_prefix;
        guint32 label_generator;
        gboolean llvm;
+       MonoAotFileFlags flags;
+       MonoDynamicStream blob;
 } MonoAotCompile;
 
 #define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
@@ -624,7 +629,6 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                 * We can't emit jumps because they are 32 bits only so they can't be patched.
                 * So we make indirect calls through GOT entries which are patched by the AOT 
                 * loader to point to .Lpd entries. 
-                * An x86_64 plt entry is 10 bytes long, init_plt () depends on this.
                 */
                /* jmpq *<offset>(%rip) */
                emit_byte (acfg, '\xff');
@@ -640,7 +644,6 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                 * - optimize OP_AOTCONST implementation
                 * - optimize the PLT entries
                 * - optimize SWITCH AOT implementation
-                * - implement IMT support
                 */
                code = buf;
                if (acfg->use_bin_writer && FALSE) {
@@ -1107,6 +1110,73 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
 #endif
 }
 
+static void
+arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
+{
+#if defined(TARGET_POWERPC) && defined(__mono_ilp32__)
+       /* Based on code generated by gcc */
+       img_writer_emit_unset_mode (acfg->w);
+
+       fprintf (acfg->fp,
+#if defined(_MSC_VER) || defined(MONO_CROSS_COMPILE) 
+                        ".section      .ctors,\"aw\",@progbits\n"
+                        ".align 2\n"
+                        ".globl        %s\n"
+                        ".long %s\n"
+                        ".section      .opd,\"aw\"\n"
+                        ".align 2\n"
+                        "%s:\n"
+                        ".long .%s,.TOC.@tocbase32\n"
+                        ".size %s,.-%s\n"
+                        ".section .text\n"
+                        ".type .%s,@function\n"
+                        ".align 2\n"
+                        ".%s:\n", symbol, symbol, symbol, symbol, symbol, symbol, symbol, symbol);
+#else
+                        ".section      .ctors,\"aw\",@progbits\n"
+                        ".align 2\n"
+                        ".globl        %1$s\n"
+                        ".long %1$s\n"
+                        ".section      .opd,\"aw\"\n"
+                        ".align 2\n"
+                        "%1$s:\n"
+                        ".long .%1$s,.TOC.@tocbase32\n"
+                        ".size %1$s,.-%1$s\n"
+                        ".section .text\n"
+                        ".type .%1$s,@function\n"
+                        ".align 2\n"
+                        ".%1$s:\n", symbol);
+#endif
+
+
+       fprintf (acfg->fp,
+                        "stdu 1,-128(1)\n"
+                        "mflr 0\n"
+                        "std 31,120(1)\n"
+                        "std 0,144(1)\n"
+
+                        ".Lautoreg:\n"
+                        "lis 3, .Lglobals@h\n"
+                        "ori 3, 3, .Lglobals@l\n"
+                        "bl .mono_aot_register_module\n"
+                        "ld 11,0(1)\n"
+                        "ld 0,16(11)\n"
+                        "mtlr 0\n"
+                        "ld 31,-8(11)\n"
+                        "mr 1,11\n"
+                        "blr\n"
+                        );
+#if defined(_MSC_VER) || defined(MONO_CROSS_COMPILE) 
+               fprintf (acfg->fp,
+                        ".size .%s,.-.%s\n", symbol, symbol);
+#else
+       fprintf (acfg->fp,
+                        ".size .%1$s,.-.%1$s\n", symbol);
+#endif
+#else
+#endif
+}
+
 /*
  * arch_get_cie_program:
  *
@@ -1186,6 +1256,123 @@ encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
                *endbuf = p;
 }
 
+static void
+stream_init (MonoDynamicStream *sh)
+{
+       sh->index = 0;
+       sh->alloc_size = 4096;
+       sh->data = g_malloc (4096);
+
+       /* So offsets are > 0 */
+       sh->index ++;
+}
+
+static void
+make_room_in_stream (MonoDynamicStream *stream, int size)
+{
+       if (size <= stream->alloc_size)
+               return;
+       
+       while (stream->alloc_size <= size) {
+               if (stream->alloc_size < 4096)
+                       stream->alloc_size = 4096;
+               else
+                       stream->alloc_size *= 2;
+       }
+       
+       stream->data = g_realloc (stream->data, stream->alloc_size);
+}
+
+static guint32
+add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
+{
+       guint32 idx;
+       
+       make_room_in_stream (stream, stream->index + len);
+       memcpy (stream->data + stream->index, data, len);
+       idx = stream->index;
+       stream->index += len;
+       return idx;
+}
+
+/*
+ * add_to_blob:
+ *
+ *   Add data to the binary blob inside the aot image. Returns the offset inside the
+ * blob where the data was stored.
+ */
+static guint32
+add_to_blob (MonoAotCompile *acfg, guint8 *data, guint32 data_len)
+{
+       if (acfg->blob.alloc_size == 0)
+               stream_init (&acfg->blob);
+
+       return add_stream_data (&acfg->blob, (char*)data, data_len);
+}
+
+/*
+ * emit_offset_table:
+ *
+ *   Emit a table of increasing offsets in a compact form using differential encoding.
+ * There is an index entry for each GROUP_SIZE number of entries. The greater the
+ * group size, the more compact the table becomes, but the slower it becomes to compute
+ * a given entry. Returns the size of the table.
+ */
+static guint32
+emit_offset_table (MonoAotCompile *acfg, int noffsets, int group_size, gint32 *offsets)
+{
+       gint32 current_offset;
+       int i, buf_size, ngroups, index_entry_size;
+       guint8 *p, *buf;
+       guint32 *index_offsets;
+
+       ngroups = (noffsets + (group_size - 1)) / group_size;
+
+       index_offsets = g_new0 (guint32, ngroups);
+
+       buf_size = noffsets * 4;
+       p = buf = g_malloc0 (buf_size);
+
+       current_offset = 0;
+       for (i = 0; i < noffsets; ++i) {
+               //printf ("D: %d -> %d\n", i, offsets [i]);
+               if ((i % group_size) == 0) {
+                       index_offsets [i / group_size] = p - buf;
+                       /* Emit the full value for these entries */
+                       encode_value (offsets [i], p, &p);
+               } else {
+                       /* The offsets are allowed to be non-increasing */
+                       //g_assert (offsets [i] >= current_offset);
+                       encode_value (offsets [i] - current_offset, p, &p);
+               }
+               current_offset = offsets [i];
+       }
+
+       if (ngroups && index_offsets [ngroups - 1] < 65000)
+               index_entry_size = 2;
+       else
+               index_entry_size = 4;
+
+       /* Emit the header */
+       emit_int32 (acfg, noffsets);
+       emit_int32 (acfg, group_size);
+       emit_int32 (acfg, ngroups);
+       emit_int32 (acfg, index_entry_size);
+
+       /* Emit the index */
+       for (i = 0; i < ngroups; ++i) {
+               if (index_entry_size == 2)
+                       emit_int16 (acfg, index_offsets [i]);
+               else
+                       emit_int32 (acfg, index_offsets [i]);
+       }
+
+       /* Emit the data */
+       emit_bytes (acfg, buf, p - buf);
+
+    return (int)(p - buf) + (ngroups * 4);
+}
+
 static guint32
 get_image_index (MonoAotCompile *cfg, MonoImage *image)
 {
@@ -1565,6 +1752,7 @@ is_plt_patch (MonoJumpInfo *patch_info)
        case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
        case MONO_PATCH_INFO_MONITOR_ENTER:
        case MONO_PATCH_INFO_MONITOR_EXIT:
+       case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
                return TRUE;
        default:
                return FALSE;
@@ -1662,7 +1850,7 @@ get_method_index (MonoAotCompile *acfg, MonoMethod *method)
 }
 
 static int
-add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra)
+add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra, int depth)
 {
        int index;
 
@@ -1676,6 +1864,8 @@ add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra)
        /* FIXME: Fix quadratic behavior */
        acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (index));
 
+       g_hash_table_insert (acfg->method_depth, method, GUINT_TO_POINTER (depth));
+
        acfg->method_index ++;
 
        return index;
@@ -1684,13 +1874,19 @@ add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra)
 static int
 add_method (MonoAotCompile *acfg, MonoMethod *method)
 {
-       return add_method_full (acfg, method, FALSE);
+       return add_method_full (acfg, method, FALSE, 0);
 }
 
 static void
 add_extra_method (MonoAotCompile *acfg, MonoMethod *method)
 {
-       add_method_full (acfg, method, TRUE);
+       add_method_full (acfg, method, TRUE, 0);
+}
+
+static void
+add_extra_method_with_depth (MonoAotCompile *acfg, MonoMethod *method, int depth)
+{
+       add_method_full (acfg, method, TRUE, depth);
 }
 
 static void
@@ -1821,8 +2017,14 @@ add_wrappers (MonoAotCompile *acfg)
 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
                if (!method->klass->contextbound) {
                        MonoDynCallInfo *info = mono_arch_dyn_call_prepare (sig);
+                       gboolean has_nullable = FALSE;
 
-                       if (info) {
+                       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);
@@ -1991,7 +2193,7 @@ add_wrappers (MonoAotCompile *acfg)
                token = MONO_TOKEN_METHOD_DEF | (i + 1);
                method = mono_get_method (acfg->image, token, NULL);
 
-               if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+               if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED && !method->is_generic)
                        add_method (acfg, mono_marshal_get_synchronized_wrapper (method));
        }
 
@@ -2271,6 +2473,8 @@ add_generic_instances (MonoAotCompile *acfg)
                insts [ninsts ++] = &mono_defaults.uint64_class->byval_arg;
                insts [ninsts ++] = &mono_defaults.single_class->byval_arg;
                insts [ninsts ++] = &mono_defaults.double_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.char_class->byval_arg;
+               insts [ninsts ++] = &mono_defaults.boolean_class->byval_arg;
 
                /* Add GenericComparer<T> instances for primitive types for Enum.ToString () */
                klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
@@ -2682,8 +2886,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                encode_value (*((guint32 *)patch_info->data.target), p, &p);
                break;
        case MONO_PATCH_INFO_R8:
-               encode_value (*((guint32 *)patch_info->data.target), p, &p);
-               encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
+               encode_value (((guint32 *)patch_info->data.target) [MINI_LS_WORD_IDX], p, &p);
+               encode_value (((guint32 *)patch_info->data.target) [MINI_MS_WORD_IDX], p, &p);
                break;
        case MONO_PATCH_INFO_VTABLE:
        case MONO_PATCH_INFO_CLASS:
@@ -2716,6 +2920,10 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        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);
                g_assert_not_reached ();
@@ -2754,7 +2962,6 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        GList *l;
        int pindex, buf_size, n_patches;
        guint8 *code;
-       char symbol [128];
        GPtrArray *patches;
        MonoJumpInfo *patch_info;
        MonoMethodHeader *header;
@@ -2768,9 +2975,6 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        method_index = get_method_index (acfg, method);
 
-       /* Make the labels local */
-       sprintf (symbol, "%sm_%x_p", acfg->temp_prefix, method_index);
-
        /* Sort relocations */
        patches = g_ptr_array_new ();
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
@@ -2836,12 +3040,9 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        acfg->stats.info_size += p - buf;
 
-       /* Emit method info */
-
-       emit_label (acfg, symbol);
-
        g_assert (p - buf < buf_size);
-       emit_bytes (acfg, buf, p - buf);
+
+       cfg->method_info_offset = add_to_blob (acfg, buf, p - buf);
        g_free (buf);
 }
 
@@ -2885,13 +3086,12 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        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;
-       GPtrArray *seq_points;
+       MonoSeqPointInfo *seq_points;
 
        method = cfg->orig_method;
        code = cfg->native_code;
@@ -2899,9 +3099,6 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        method_index = get_method_index (acfg, method);
 
-       /* Make the labels local */
-       sprintf (symbol, "%se_%x_p", acfg->temp_prefix, method_index);
-
        if (!acfg->aot_opts.nodebug) {
                mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
        } else {
@@ -2909,23 +3106,17 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                debug_info_size = 0;
        }
 
-       buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (cfg->seq_points ? (cfg->seq_points->len * 16) : 0);
+       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
 
-       seq_points = cfg->seq_points;
-
-       flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points ? 8 : 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);
 
-       if (cfg->compile_llvm) {
-               /* Emitted by LLVM into the .eh_frame section */
-               encode_value (0, p, &p);
-       } else {
-               encode_value (jinfo->code_size, p, &p);
-       }
        encode_value (flags, p, &p);
 
        if (use_unwind_ops) {
@@ -2984,17 +3175,22 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        }
 
        if (seq_points) {
-               int il_offset, native_offset, last_il_offset, last_native_offset;
+               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 += 2) {
-                       il_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i));
-                       native_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i + 1));
+               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);
                }
        }
                
@@ -3010,22 +3206,19 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        acfg->stats.ex_info_size += p - buf;
 
-       /* Emit info */
-
-       emit_label (acfg, symbol);
-
        g_assert (p - buf < buf_size);
-       emit_bytes (acfg, buf, p - buf);
+
+       /* Emit info */
+       cfg->ex_info_offset = add_to_blob (acfg, buf, p - buf);
        g_free (buf);
 }
 
-static void
+static guint32
 emit_klass_info (MonoAotCompile *acfg, guint32 token)
 {
        MonoClass *klass = mono_class_get (acfg->image, token);
        guint8 *p, *buf;
-       int i, buf_size;
-       char symbol [128];
+       int i, buf_size, res;
        gboolean no_special_static, cant_encode;
        gpointer iter = NULL;
 
@@ -3062,7 +3255,7 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
                encode_value (-1, p, &p);
        } else {
                encode_value (klass->vtable_size, p, &p);
-               encode_value ((no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | ((klass->ext && klass->ext->nested_classes) ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
+               encode_value ((klass->generic_container ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | ((klass->ext && klass->ext->nested_classes) ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
                if (klass->has_cctor)
                        encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
                if (klass->has_finalize)
@@ -3085,13 +3278,11 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token)
 
        acfg->stats.class_info_size += p - buf;
 
-       /* Emit the info */
-       sprintf (symbol, "%sK_I_%x", acfg->temp_prefix, token - MONO_TOKEN_TYPE_DEF - 1);
-       emit_label (acfg, symbol);
-
        g_assert (p - buf < buf_size);
-       emit_bytes (acfg, buf, p - buf);
+       res = add_to_blob (acfg, buf, p - buf);
        g_free (buf);
+
+       return res;
 }
 
 /*
@@ -3219,7 +3410,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;
@@ -3262,11 +3453,13 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
 
        sprintf (symbol, "%s_p", name);
 
+       info_offset = add_to_blob (acfg, buf, p - buf);
+
        emit_section_change (acfg, ".text", 0);
        emit_global (acfg, symbol, FALSE);
        emit_label (acfg, symbol);
-               
-       emit_bytes (acfg, buf, p - buf);
+
+       emit_int32 (acfg, info_offset);
 
        /* Emit debug info */
        if (unwind_ops) {
@@ -3511,12 +3704,18 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->nodebug = TRUE;
                } else if (str_begins_with (arg, "ntrampolines=")) {
                        opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
-               } else if (str_begins_with (arg, "tool-prefix=")) {
-                       opts->tool_prefix = g_strdup (arg + strlen ("tool-prefix="));
+               } else if (str_begins_with (arg, "nrgctx-trampolines=")) {
+                       opts->nrgctx_trampolines = atoi (arg + strlen ("nrgctx-trampolines="));
                } else if (str_begins_with (arg, "autoreg")) {
                        opts->autoreg = TRUE;
+               } else if (str_begins_with (arg, "tool-prefix=")) {
+                       opts->tool_prefix = g_strdup (arg + strlen ("tool-prefix="));
                } else if (str_begins_with (arg, "soft-debug")) {
                        opts->soft_debug = TRUE;
+               } else if (str_begins_with (arg, "print-skipped")) {
+                       opts->print_skipped_methods = TRUE;
+               } else if (str_begins_with (arg, "stats")) {
+                       opts->stats = TRUE;
                } else {
                        fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
                        exit (1);
@@ -3632,7 +3831,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
        MonoCompile *cfg;
        MonoJumpInfo *patch_info;
        gboolean skip;
-       int index;
+       int index, depth;
        MonoMethod *wrapped;
 
        if (acfg->aot_opts.metadata_only)
@@ -3756,34 +3955,41 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
        }
 
        /* Adds generic instances referenced by this method */
-       for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
-               switch (patch_info->type) {
-               case MONO_PATCH_INFO_METHOD: {
-                       MonoMethod *m = patch_info->data.method;
-                       if (m->is_inflated) {
-                               if (!(mono_class_generic_sharing_enabled (m->klass) &&
-                                         mono_method_is_generic_sharable_impl (m, FALSE)) &&
-                                       !method_has_type_vars (m)) {
-                                       if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
-                                               if (acfg->aot_opts.full_aot)
-                                                       add_extra_method (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE));
-                                       } else {
-                                               add_extra_method (acfg, m);
+       /* 
+        * The depth is used to avoid infinite loops when generic virtual recursion is 
+        * encountered.
+        */
+       depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method));
+       if (depth < 32) {
+               for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
+                       switch (patch_info->type) {
+                       case MONO_PATCH_INFO_METHOD: {
+                               MonoMethod *m = patch_info->data.method;
+                               if (m->is_inflated) {
+                                       if (!(mono_class_generic_sharing_enabled (m->klass) &&
+                                                 mono_method_is_generic_sharable_impl (m, FALSE)) &&
+                                               !method_has_type_vars (m)) {
+                                               if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
+                                                       if (acfg->aot_opts.full_aot)
+                                                               add_extra_method_with_depth (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE), depth + 1);
+                                               } else {
+                                                       add_extra_method_with_depth (acfg, m, depth + 1);
+                                               }
                                        }
+                                       add_generic_class (acfg, m->klass);
                                }
-                               add_generic_class (acfg, m->klass);
+                               break;
                        }
-                       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;
+                       }
                }
        }
 
@@ -4007,6 +4213,9 @@ mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
        ji->type = type;
        ji->data.target = data;
 
+       if (!can_encode_patch (llvm_acfg, ji))
+               return NULL;
+
        offset = get_plt_offset (llvm_acfg, ji);
 
        return g_strdup_printf (".Lp_%d", offset);
@@ -4035,7 +4244,7 @@ mono_aot_patch_info_dup (MonoJumpInfo* ji)
 static void
 emit_llvm_file (MonoAotCompile *acfg)
 {
-       char *command;
+       char *command, *opts;
        int i;
        MonoJumpInfo *patch_info;
 
@@ -4061,8 +4270,24 @@ emit_llvm_file (MonoAotCompile *acfg)
 
        mono_llvm_emit_aot_module ("temp.bc", acfg->final_got_size);
 
+       /*
+        * FIXME: Experiment with adding optimizations, the -std-compile-opts set takes
+        * a lot of time, and doesn't seem to save much space.
+        * The following optimizations cannot be enabled:
+        * - 'tailcallelim'
+        */
+       opts = g_strdup ("-instcombine -simplifycfg");
+#if 1
+       command = g_strdup_printf ("opt -f %s -o temp.opt.bc temp.bc", opts);
+       printf ("Executing opt: %s\n", command);
+       if (system (command) != 0) {
+               exit (1);
+       }
+#endif
+       g_free (opts);
+
        //command = g_strdup_printf ("llc -march=arm -mtriple=arm-linux-gnueabi -f -relocation-model=pic -unwind-tables temp.bc");
-       command = g_strdup_printf ("llc -f -relocation-model=pic -unwind-tables temp.bc");
+       command = g_strdup_printf ("llc -f -relocation-model=pic -unwind-tables -o temp.s temp.opt.bc");
        printf ("Executing llc: %s\n", command);
 
        if (system (command) != 0) {
@@ -4117,12 +4342,14 @@ emit_code (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
-       sprintf (symbol, "method_offsets");
+       sprintf (symbol, "code_offsets");
        emit_section_change (acfg, ".text", 1);
        emit_global (acfg, symbol, FALSE);
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
+       acfg->stats.offsets_size += acfg->nmethods * 4;
+
        for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
                        sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
@@ -4140,23 +4367,19 @@ emit_info (MonoAotCompile *acfg)
        int i;
        char symbol [256];
        GList *l;
+       gint32 *offsets;
 
-       /* Emit method info */
-       sprintf (symbol, "method_info");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
-       /* To reduce size of generated assembly code */
-       sprintf (symbol, "mi");
-       emit_label (acfg, symbol);
+       offsets = g_new0 (gint32, acfg->nmethods);
 
        for (l = acfg->method_order; l != NULL; l = l->next) {
                i = GPOINTER_TO_UINT (l->data);
 
-               if (acfg->cfgs [i])
+               if (acfg->cfgs [i]) {
                        emit_method_info (acfg, acfg->cfgs [i]);
+                       offsets [i] = acfg->cfgs [i]->method_info_offset;
+               } else {
+                       offsets [i] = 0;
+               }
        }
 
        sprintf (symbol, "method_info_offsets");
@@ -4165,40 +4388,13 @@ emit_info (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
-       for (i = 0; i < acfg->nmethods; ++i) {
-               if (acfg->cfgs [i]) {
-                       sprintf (symbol, "%sm_%x_p", acfg->temp_prefix, i);
-                       emit_symbol_diff (acfg, symbol, "mi", 0);
-               } else {
-                       emit_int32 (acfg, 0);
-               }
-       }
-       emit_line (acfg);
+       acfg->stats.offsets_size += emit_offset_table (acfg, acfg->nmethods, 10, offsets);
+
+       g_free (offsets);
 }
 
 #endif /* #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */
 
-/*
- * mono_aot_str_hash:
- *
- * Hash function for strings which we use to hash strings for things which are
- * saved in the AOT image, since g_str_hash () can change.
- */
-guint
-mono_aot_str_hash (gconstpointer v1)
-{
-       /* Same as g_str_hash () in glib */
-       char *p = (char *) v1;
-       guint hash = *p;
-
-       while (*p++) {
-               if (*p)
-                       hash = (hash << 5) - hash + *p;
-       }
-
-       return hash;
-} 
-
 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
 #define mix(a,b,c) { \
        a -= c;  a ^= rot(c, 4);  c += b; \
@@ -4229,11 +4425,11 @@ mono_aot_type_hash (MonoType *t1)
        case MONO_TYPE_CLASS:
        case MONO_TYPE_SZARRAY:
                /* check if the distribution is good enough */
-               return ((hash << 5) - hash) ^ mono_aot_str_hash (t1->data.klass->name);
+               return ((hash << 5) - hash) ^ mono_metadata_str_hash (t1->data.klass->name);
        case MONO_TYPE_PTR:
-               return ((hash << 5) - hash) ^ mono_aot_type_hash (t1->data.type);
+               return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
        case MONO_TYPE_ARRAY:
-               return ((hash << 5) - hash) ^ mono_aot_type_hash (&t1->data.array->eklass->byval_arg);
+               return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg);
        case MONO_TYPE_GENERICINST:
                return ((hash << 5) - hash) ^ 0;
        }
@@ -4272,18 +4468,18 @@ mono_aot_method_hash (MonoMethod *method)
        if (!method->wrapper_type) {
                char *full_name = mono_type_full_name (&klass->byval_arg);
 
-               hashes [0] = mono_aot_str_hash (full_name);
+               hashes [0] = mono_metadata_str_hash (full_name);
                hashes [1] = 0;
                g_free (full_name);
        } else {
-               hashes [0] = mono_aot_str_hash (klass->name);
-               hashes [1] = mono_aot_str_hash (klass->name_space);
+               hashes [0] = mono_metadata_str_hash (klass->name);
+               hashes [1] = mono_metadata_str_hash (klass->name_space);
        }
        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_aot_str_hash (method->name);
+               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++) {
@@ -4445,14 +4641,8 @@ emit_extra_methods (MonoAotCompile *acfg)
 
        info_offsets = g_new0 (guint32, acfg->extra_methods->len);
 
-       buf_size = acfg->extra_methods->len * 256 + 256;
-       p = buf = g_malloc (buf_size);
-
-       /* Encode method info */
+       /* Emit method info */
        nmethods = 0;
-       /* So offsets are > 0 */
-       *p = 0;
-       p++;
        for (i = 0; i < acfg->extra_methods->len; ++i) {
                MonoMethod *method = g_ptr_array_index (acfg->extra_methods, i);
                MonoCompile *cfg = g_hash_table_lookup (acfg->method_to_cfg, method);
@@ -4461,8 +4651,10 @@ emit_extra_methods (MonoAotCompile *acfg)
                if (!cfg)
                        continue;
 
+               buf_size = 512;
+               p = buf = g_malloc (buf_size);
+
                nmethods ++;
-               info_offsets [i] = p - buf;
 
                name = NULL;
                if (method->wrapper_type) {
@@ -4499,20 +4691,10 @@ emit_extra_methods (MonoAotCompile *acfg)
                }
 
                g_assert ((p - buf) < buf_size);
-       }
-
-       g_assert ((p - buf) < buf_size);
 
-       /* Emit method info */
-       sprintf (symbol, "extra_method_info");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
-       emit_bytes (acfg, buf, p - buf);
-
-       emit_line (acfg);
+               info_offsets [i] = add_to_blob (acfg, buf, p - buf);
+               g_free (buf);
+       }
 
        /*
         * Construct a chained hash table for mapping indexes in extra_method_info to
@@ -4610,20 +4792,16 @@ emit_exception_info (MonoAotCompile *acfg)
 {
        int i;
        char symbol [256];
+       gint32 *offsets;
 
-       sprintf (symbol, "ex_info");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
-       /* To reduce size of generated assembly */
-       sprintf (symbol, "ex");
-       emit_label (acfg, symbol);
-
+       offsets = g_new0 (gint32, acfg->nmethods);
        for (i = 0; i < acfg->nmethods; ++i) {
-               if (acfg->cfgs [i])
+               if (acfg->cfgs [i]) {
                        emit_exception_debug_info (acfg, acfg->cfgs [i]);
+                       offsets [i] = acfg->cfgs [i]->ex_info_offset;
+               } else {
+                       offsets [i] = 0;
+               }
        }
 
        sprintf (symbol, "ex_info_offsets");
@@ -4632,15 +4810,8 @@ emit_exception_info (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
-       for (i = 0; i < acfg->nmethods; ++i) {
-               if (acfg->cfgs [i]) {
-                       sprintf (symbol, "%se_%x_p", acfg->temp_prefix, i);
-                       emit_symbol_diff (acfg, symbol, "ex", 0);
-               } else {
-                       emit_int32 (acfg, 0);
-               }
-       }
-       emit_line (acfg);
+       acfg->stats.offsets_size += emit_offset_table (acfg, acfg->nmethods, 10, offsets);
+       g_free (offsets);
 }
 
 static void
@@ -4684,15 +4855,11 @@ emit_class_info (MonoAotCompile *acfg)
 {
        int i;
        char symbol [256];
+       gint32 *offsets;
 
-       sprintf (symbol, "class_info");
-       emit_section_change (acfg, ".text", 1);
-       emit_global (acfg, symbol, FALSE);
-       emit_alignment (acfg, 8);
-       emit_label (acfg, symbol);
-
+       offsets = g_new0 (gint32, acfg->image->tables [MONO_TABLE_TYPEDEF].rows);
        for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
-               emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
+               offsets [i] = emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
 
        sprintf (symbol, "class_info_offsets");
        emit_section_change (acfg, ".text", 1);
@@ -4700,11 +4867,8 @@ emit_class_info (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
-       for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
-               sprintf (symbol, "%sK_I_%x", acfg->temp_prefix, i);
-               emit_symbol_diff (acfg, symbol, "class_info", 0);
-       }
-       emit_line (acfg);
+       acfg->stats.offsets_size += emit_offset_table (acfg, acfg->image->tables [MONO_TABLE_TYPEDEF].rows, 10, offsets);
+       g_free (offsets);
 }
 
 typedef struct ClassNameTableEntry {
@@ -4734,7 +4898,7 @@ emit_class_name_table (MonoAotCompile *acfg)
                token = MONO_TOKEN_TYPE_DEF | (i + 1);
                klass = mono_class_get (acfg->image, token);
                full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
-               hash = mono_aot_str_hash (full_name) % table_size;
+               hash = mono_metadata_str_hash (full_name) % table_size;
                g_free (full_name);
 
                /* FIXME: Allocate from the mempool */
@@ -4862,25 +5026,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);
+               g_assert (p - buf <= buf_size);
+               got_info_offsets [i] = add_to_blob (acfg, buf, p - buf);
 
-       acfg->stats.got_info_size = 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");
@@ -4890,10 +5047,7 @@ emit_got_info (MonoAotCompile *acfg)
        emit_label (acfg, symbol);
 
        /* No need to emit offsets for the got plt entries, the plt embeds them directly */
-       for (i = 0; i < first_plt_got_patch; ++i)
-               emit_int32 (acfg, got_info_offsets [i]);
-
-       acfg->stats.got_info_offsets_size = acfg->got_patches->len * 4;
+       acfg->stats.offsets_size += emit_offset_table (acfg, first_plt_got_patch, 10, (gint32*)got_info_offsets);
 }
 
 static void
@@ -4923,22 +5077,118 @@ emit_got (MonoAotCompile *acfg)
        emit_pointer (acfg, acfg->got_symbol);
 }
 
+typedef struct GlobalsTableEntry {
+       guint32 value, index;
+       struct GlobalsTableEntry *next;
+} GlobalsTableEntry;
+
+static void
+emit_globals_table (MonoAotCompile *acfg)
+{
+       int i, table_size;
+       guint32 hash;
+       GPtrArray *table;
+       char symbol [256];
+       GlobalsTableEntry *entry, *new_entry;
+
+       /*
+        * Construct a chained hash table for mapping global names to their index in
+        * the globals table.
+        */
+       table_size = g_spaced_primes_closest ((int)(acfg->globals->len * 1.5));
+       table = g_ptr_array_sized_new (table_size);
+       for (i = 0; i < table_size; ++i)
+               g_ptr_array_add (table, NULL);
+       for (i = 0; i < acfg->globals->len; ++i) {
+               char *name = g_ptr_array_index (acfg->globals, i);
+
+               hash = mono_metadata_str_hash (name) % table_size;
+
+               /* FIXME: Allocate from the mempool */
+               new_entry = g_new0 (GlobalsTableEntry, 1);
+               new_entry->value = i;
+
+               entry = g_ptr_array_index (table, hash);
+               if (entry == NULL) {
+                       new_entry->index = hash;
+                       g_ptr_array_index (table, hash) = new_entry;
+               } else {
+                       while (entry->next)
+                               entry = entry->next;
+                       
+                       entry->next = new_entry;
+                       new_entry->index = table->len;
+                       g_ptr_array_add (table, new_entry);
+               }
+       }
+
+       /* Emit the table */
+       sprintf (symbol, ".Lglobals_hash");
+       emit_section_change (acfg, ".text", 0);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+
+       /* FIXME: Optimize memory usage */
+       g_assert (table_size < 65000);
+       emit_int16 (acfg, table_size);
+       for (i = 0; i < table->len; ++i) {
+               GlobalsTableEntry *entry = g_ptr_array_index (table, i);
+
+               if (entry == NULL) {
+                       emit_int16 (acfg, 0);
+                       emit_int16 (acfg, 0);
+               } else {
+                       emit_int16 (acfg, entry->value + 1);
+                       if (entry->next)
+                               emit_int16 (acfg, entry->next->index);
+                       else
+                               emit_int16 (acfg, 0);
+               }
+       }
+
+       /* Emit the names */
+       for (i = 0; i < acfg->globals->len; ++i) {
+               char *name = g_ptr_array_index (acfg->globals, i);
+
+               sprintf (symbol, "name_%d", i);
+               emit_section_change (acfg, ".text", 1);
+               emit_label (acfg, symbol);
+               emit_string (acfg, name);
+       }
+
+       /* Emit the globals table */
+       sprintf (symbol, ".Lglobals");
+       emit_section_change (acfg, ".data", 0);
+       /* This is not a global, since it is accessed by the init function */
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+
+       sprintf (symbol, "%sglobals_hash", acfg->temp_prefix);
+       emit_pointer (acfg, symbol);
+
+       for (i = 0; i < acfg->globals->len; ++i) {
+               char *name = g_ptr_array_index (acfg->globals, i);
+
+               sprintf (symbol, "name_%d", i);
+               emit_pointer (acfg, symbol);
+
+               sprintf (symbol, "%s", name);
+               emit_pointer (acfg, symbol);
+       }
+       /* Null terminate the table */
+       emit_int32 (acfg, 0);
+       emit_int32 (acfg, 0);
+}
+
 static void
 emit_globals (MonoAotCompile *acfg)
 {
-       char *opts_str;
        char *build_info;
 
        emit_string_symbol (acfg, "mono_assembly_guid" , acfg->image->guid);
 
        emit_string_symbol (acfg, "mono_aot_version", MONO_AOT_FILE_VERSION);
 
-       opts_str = g_strdup_printf ("%d", acfg->opts);
-       emit_string_symbol (acfg, "mono_aot_opt_flags", opts_str);
-       g_free (opts_str);
-
-       emit_string_symbol (acfg, "mono_aot_full_aot", acfg->aot_opts.full_aot ? "TRUE" : "FALSE");
-
        if (acfg->aot_opts.bind_to_runtime_version) {
                build_info = mono_get_runtime_build_info ();
                emit_string_symbol (acfg, "mono_runtime_version", build_info);
@@ -4951,42 +5201,13 @@ emit_globals (MonoAotCompile *acfg)
         * When static linking, we emit a global which will point to the symbol table.
         */
        if (acfg->aot_opts.static_link) {
-               int i;
                char symbol [256];
                char *p;
 
                /* Emit a string holding the assembly name */
                emit_string_symbol (acfg, "mono_aot_assembly_name", acfg->image->assembly->aname.name);
 
-               /* Emit the names */
-               for (i = 0; i < acfg->globals->len; ++i) {
-                       char *name = g_ptr_array_index (acfg->globals, i);
-
-                       sprintf (symbol, "name_%d", i);
-                       emit_section_change (acfg, ".text", 1);
-                       emit_label (acfg, symbol);
-                       emit_string (acfg, name);
-               }
-
-               /* Emit the globals table */
-               sprintf (symbol, ".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);
-
-               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
@@ -5008,7 +5229,8 @@ emit_globals (MonoAotCompile *acfg)
                emit_global_inner (acfg, symbol, FALSE);
                emit_alignment (acfg, 8);
                emit_label (acfg, symbol);
-               emit_pointer (acfg, ".Lglobals");
+               sprintf (symbol, "%sglobals", acfg->temp_prefix);
+               emit_pointer (acfg, symbol);
        }
 }
 
@@ -5026,48 +5248,7 @@ emit_autoreg (MonoAotCompile *acfg)
 
        symbol = g_strdup_printf ("_%s_autoreg", acfg->static_linking_symbol);
 
-#if defined(TARGET_POWERPC) && defined(__mono_ilp32__)
-       /* Based on code generated by gcc */
-       img_writer_emit_unset_mode (acfg->w);
-
-       fprintf (acfg->fp,
-                        ".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"
-                        ".%1$s:\n"
-                        , symbol);
-
-       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"
-                        );
-
-       fprintf (acfg->fp,
-                        ".size .%1$s,.-.%1$s\n", symbol);
-#else
-       g_assert_not_reached ();
-#endif
+       arch_emit_autoreg (acfg, symbol);
 
        g_free (symbol);
 }      
@@ -5104,6 +5285,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]);
@@ -5113,6 +5296,20 @@ emit_file_info (MonoAotCompile *acfg)
                emit_int32 (acfg, acfg->trampoline_size [i]);
 }
 
+static void
+emit_blob (MonoAotCompile *acfg)
+{
+       char symbol [128];
+
+       sprintf (symbol, "blob");
+       emit_section_change (acfg, ".text", 1);
+       emit_global (acfg, symbol, FALSE);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+
+       emit_bytes (acfg, (guint8*)acfg->blob.data, acfg->blob.index);
+}
+
 static void
 emit_dwarf_info (MonoAotCompile *acfg)
 {
@@ -5325,7 +5522,7 @@ 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 %s -shared -o %s %s.o", tool_prefix, EH_LD_OPTIONS, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
@@ -5386,6 +5583,7 @@ acfg_create (MonoAssembly *ass, guint32 opts)
        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);
@@ -5429,6 +5627,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);
@@ -5461,6 +5660,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts));
        acfg->aot_opts.write_symbols = TRUE;
        acfg->aot_opts.ntrampolines = 1024;
+       acfg->aot_opts.nrgctx_trampolines = 1024;
 
        mono_aot_parse_options (aot_options, &acfg->aot_opts);
 
@@ -5494,13 +5694,17 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 #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;
 
@@ -5643,6 +5847,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        emit_file_info (acfg);
 
+       emit_blob (acfg);
+
        emit_globals (acfg);
 
        emit_autoreg (acfg);
@@ -5661,7 +5867,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        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 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)));
+       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);
@@ -5700,12 +5906,14 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        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);
 
@@ -5917,7 +6125,7 @@ xdebug_end_emit (MonoImageWriter *w, MonoDwarfWriter *dw, MonoMethod *method)
  *   This could be called from inside gdb to flush the debugging information not yet
  * registered with gdb.
  */
-static void
+void
 mono_xdebug_flush (void)
 {
        if (xdebug_w)