2010-01-18 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-compiler.c
index 72901e498bbb16557afdc6859e7a771e1b7af158..cb1fc0e368fe3344632c5ef0d9ddc5fd7c158e25 100644 (file)
@@ -99,6 +99,7 @@ typedef struct MonoAotOptions {
        gboolean soft_debug;
        int nthreads;
        int ntrampolines;
+       int nrgctx_trampolines;
        gboolean print_skipped_methods;
        gboolean stats;
        char *tool_prefix;
@@ -107,9 +108,9 @@ typedef struct 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;
@@ -167,6 +168,7 @@ typedef struct MonoAotCompile {
        guint32 label_generator;
        gboolean llvm;
        MonoAotFileFlags flags;
+       MonoDynamicStream blob;
 } MonoAotCompile;
 
 #define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
@@ -627,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');
@@ -643,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) {
@@ -1110,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:
  *
@@ -1189,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)
 {
@@ -1833,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;
+
+                       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) {
+                       if (info && !has_nullable) {
                                /* Supported by the dynamic runtime-invoke wrapper */
                                skip = TRUE;
                                g_free (info);
@@ -2003,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));
        }
 
@@ -2772,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;
@@ -2786,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)
@@ -2854,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);
 }
 
@@ -2903,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;
@@ -2917,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 {
@@ -2927,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) | (cfg->compile_llvm ? 16 : 0);
 
-       flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points ? 8 : 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) {
@@ -3002,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);
                }
        }
                
@@ -3028,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;
 
@@ -3103,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;
 }
 
 /*
@@ -3237,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;
@@ -3280,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) {
@@ -3529,12 +3704,12 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->nodebug = TRUE;
                } else if (str_begins_with (arg, "ntrampolines=")) {
                        opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
+               } else if (str_begins_with (arg, "nrgctx-trampolines=")) {
+                       opts->nrgctx_trampolines = atoi (arg + strlen ("nrgctx-trampolines="));
                } else if (str_begins_with (arg, "autoreg")) {
                        opts->autoreg = TRUE;
                } else if (str_begins_with (arg, "tool-prefix=")) {
                        opts->tool_prefix = g_strdup (arg + strlen ("tool-prefix="));
-               } else if (str_begins_with (arg, "autoreg")) {
-                       opts->autoreg = TRUE;
                } else if (str_begins_with (arg, "soft-debug")) {
                        opts->soft_debug = TRUE;
                } else if (str_begins_with (arg, "print-skipped")) {
@@ -4099,14 +4274,11 @@ emit_llvm_file (MonoAotCompile *acfg)
         * 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:
-        * - 'globalopt', which seems to remove our methods, even though they have a global
-        *   alias pointing at them.
-        * - 'constmerge'/'globaldce', which seems to remove our got symbol.
         * - 'tailcallelim'
         */
        opts = g_strdup ("-instcombine -simplifycfg");
 #if 1
-       command = g_strdup_printf ("opt -f %s -o temp.bc temp.bc", opts);
+       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);
@@ -4115,7 +4287,7 @@ emit_llvm_file (MonoAotCompile *acfg)
        g_free (opts);
 
        //command = g_strdup_printf ("llc -march=arm -mtriple=arm-linux-gnueabi -f -relocation-model=pic -unwind-tables temp.bc");
-       command = g_strdup_printf ("llc -f -relocation-model=pic -unwind-tables -o temp.s temp.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) {
@@ -4170,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);
@@ -4193,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");
@@ -4218,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; \
@@ -4282,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;
        }
@@ -4325,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++) {
@@ -4498,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);
@@ -4514,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) {
@@ -4552,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
@@ -4663,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");
@@ -4685,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
@@ -4737,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);
@@ -4753,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 {
@@ -4787,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 */
@@ -4915,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);
-
-       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);
+               g_assert (p - buf <= buf_size);
+               got_info_offsets [i] = add_to_blob (acfg, buf, p - buf);
 
-       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");
@@ -4943,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
@@ -5001,7 +5102,7 @@ emit_globals_table (MonoAotCompile *acfg)
        for (i = 0; i < acfg->globals->len; ++i) {
                char *name = g_ptr_array_index (acfg->globals, i);
 
-               hash = mono_aot_str_hash (name) % table_size;
+               hash = mono_metadata_str_hash (name) % table_size;
 
                /* FIXME: Allocate from the mempool */
                new_entry = g_new0 (GlobalsTableEntry, 1);
@@ -5062,7 +5163,8 @@ emit_globals_table (MonoAotCompile *acfg)
        emit_alignment (acfg, 8);
        emit_label (acfg, symbol);
 
-       emit_pointer (acfg, ".Lglobals_hash");
+       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);
@@ -5081,19 +5183,12 @@ emit_globals_table (MonoAotCompile *acfg)
 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);
@@ -5134,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);
        }
 }
 
@@ -5152,66 +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,
-#ifdef _MSC_VER  
-                        ".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"
-                        ".%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"
-                        ".%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"
-                        );
-#ifdef _MSC_VER
-               fprintf (acfg->fp,
-                        ".size .%s,.-.%s\n", symbol, symbol);
-#else
-       fprintf (acfg->fp,
-                        ".size .%1$s,.-.%1$s\n", symbol);
-#endif
-#else
-#endif
+       arch_emit_autoreg (acfg, symbol);
 
        g_free (symbol);
 }      
@@ -5249,6 +5286,7 @@ emit_file_info (MonoAotCompile *acfg)
        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]);
@@ -5258,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)
 {
@@ -5608,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);
 
@@ -5644,11 +5697,14 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        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;
 
@@ -5791,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);
@@ -5809,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);
@@ -6067,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)