2009-08-25 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-compiler.c
index 67f0b8eca8940c1c30a35de355dc2b6dd7176765..58d9bea5d9175e66f733004e136e42e018e6ccb1 100644 (file)
@@ -9,8 +9,6 @@
  */
 
 /* Remaining AOT-only work:
- * - reduce the length of the wrapper names.
- * - aot IMT tables, so we don't have two kinds of aot code.
  * - optimize the trampolines, generate more code in the arch files.
  * - make things more consistent with how elf works, for example, use ELF 
  *   relocations.
@@ -101,6 +99,7 @@ typedef struct MonoAotOptions {
        int nthreads;
        int ntrampolines;
        gboolean print_skipped_methods;
+       char *tool_prefix;
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
@@ -156,8 +155,10 @@ typedef struct MonoAotCompile {
        GPtrArray *unwind_ops;
        guint32 unwind_info_offset;
        char *got_symbol;
+       char *plt_symbol;
        GHashTable *method_label_hash;
        const char *temp_prefix;
+       guint32 label_generator;
 } MonoAotCompile;
 
 #define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
@@ -312,11 +313,18 @@ emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
 {
        if (acfg->aot_opts.no_dlsym) {
                g_ptr_array_add (acfg->globals, g_strdup (name));
+               img_writer_emit_local_symbol (acfg->w, name, NULL, func);
        } else {
                img_writer_emit_global (acfg->w, name, func);
        }
 }
 
+static void
+emit_symbol_size (MonoAotCompile *acfg, const char *name, const char *end_label)
+{
+       img_writer_emit_symbol_size (acfg->w, name, end_label);
+}
+
 static void
 emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
 {
@@ -415,7 +423,7 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 
 /* ARCHITECTURE SPECIFIC CODE */
 
-#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM)
+#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_POWERPC)
 #define EMIT_DWARF_INFO 1
 #endif
 
@@ -424,6 +432,14 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #else
 #define AOT_FUNC_ALIGNMENT 16
 #endif
+#if defined(TARGET_POWERPC64) && !defined(__mono_ilp32__)
+#define PPC_LD_OP "ld"
+#define PPC_LDX_OP "ldx"
+#else
+#define PPC_LD_OP "lwz"
+#define PPC_LDX_OP "lwzx"
+#endif
 
 /*
  * arch_emit_direct_call:
@@ -454,11 +470,45 @@ arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size)
                fprintf (acfg->fp, "bl %s\n", target);
        }
        *call_size = 4;
+#elif defined(TARGET_POWERPC)
+       if (acfg->use_bin_writer) {
+               g_assert_not_reached ();
+       } else {
+               img_writer_emit_unset_mode (acfg->w);
+               fprintf (acfg->fp, "bl %s\n", target);
+               *call_size = 4;
+       }
 #else
        g_assert_not_reached ();
 #endif
 }
 
+/*
+ * PPC32 design:
+ * - we use an approach similar to the x86 abi: reserve a register (r30) to hold 
+ *   the GOT pointer.
+ * - The full-aot trampolines need access to the GOT of mscorlib, so we store
+ *   in in the 2. slot of every GOT, and require every method to place the GOT
+ *   address in r30, even when it doesn't access the GOT otherwise. This way,
+ *   the trampolines can compute the mscorlib GOT address by loading 4(r30).
+ */
+
+/*
+ * PPC64 design:
+ * PPC64 uses function descriptors which greatly complicate all code, since
+ * these are used very inconsistently in the runtime. Some functions like 
+ * mono_compile_method () return ftn descriptors, while others like the
+ * trampoline creation functions do not.
+ * We assume that all GOT slots contain function descriptors, and create 
+ * descriptors in aot-runtime.c when needed.
+ * The ppc64 abi uses r2 to hold the address of the TOC/GOT, which is loaded
+ * from function descriptors, we could do the same, but it would require 
+ * rewriting all the ppc/aot code to handle function descriptors properly.
+ * So instead, we use the same approach as on PPC32.
+ * This is a horrible mess, but fixing it would probably lead to an even bigger
+ * one.
+ */
+
 #ifdef MONO_ARCH_AOT_SUPPORTED
 /*
  * arch_emit_got_offset:
@@ -470,11 +520,36 @@ arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size)
 static void
 arch_emit_got_offset (MonoAotCompile *acfg, guint8 *code, int *code_size)
 {
+#if defined(TARGET_POWERPC64)
+       g_assert (!acfg->use_bin_writer);
+       img_writer_emit_unset_mode (acfg->w);
+       /* 
+        * The ppc32 code doesn't seem to work on ppc64, the assembler complains about
+        * unsupported relocations. So we store the got address into the .Lgot_addr
+        * symbol which is in the text segment, compute its address, and load it.
+        */
+       fprintf (acfg->fp, ".L%d:\n", acfg->label_generator);
+       fprintf (acfg->fp, "lis 0, (.Lgot_addr + 4 - .L%d)@h\n", acfg->label_generator);
+       fprintf (acfg->fp, "ori 0, 0, (.Lgot_addr + 4 - .L%d)@l\n", acfg->label_generator);
+       fprintf (acfg->fp, "add 30, 30, 0\n");
+       fprintf (acfg->fp, "%s 30, 0(30)\n", PPC_LD_OP);
+       acfg->label_generator ++;
+       *code_size = 16;
+#elif defined(TARGET_POWERPC)
+       g_assert (!acfg->use_bin_writer);
+       img_writer_emit_unset_mode (acfg->w);
+       fprintf (acfg->fp, ".L%d:\n", acfg->label_generator);
+       fprintf (acfg->fp, "lis 0, (%s + 4 - .L%d)@h\n", acfg->got_symbol, acfg->label_generator);
+       fprintf (acfg->fp, "ori 0, 0, (%s + 4 - .L%d)@l\n", acfg->got_symbol, acfg->label_generator);
+       acfg->label_generator ++;
+       *code_size = 8;
+#else
        guint32 offset = mono_arch_get_patch_offset (code);
        emit_bytes (acfg, code, offset);
        emit_symbol_diff (acfg, acfg->got_symbol, ".", offset);
 
        *code_size = offset + 4;
+#endif
 }
 
 /*
@@ -493,15 +568,27 @@ arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *cod
        /* Emit the offset */
 #ifdef TARGET_AMD64
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
+       *code_size = mono_arch_get_patch_offset (code) + 4;
 #elif defined(TARGET_X86)
        emit_int32 (acfg, (unsigned int) ((got_slot * sizeof (gpointer))));
+       *code_size = mono_arch_get_patch_offset (code) + 4;
 #elif defined(TARGET_ARM)
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer))) - 12);
+       *code_size = mono_arch_get_patch_offset (code) + 4;
+#elif defined(TARGET_POWERPC)
+       {
+               guint8 buf [32];
+               guint8 *code;
+
+               code = buf;
+               ppc_load32 (code, ppc_r0, got_slot * sizeof (gpointer));
+               g_assert (code - buf == 8);
+               emit_bytes (acfg, buf, code - buf);
+               *code_size = code - buf;
+       }
 #else
        g_assert_not_reached ();
 #endif
-
-       *code_size = mono_arch_get_patch_offset (code) + 4;
 }
 
 #endif
@@ -521,7 +608,7 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                } else {
                        /* Need to make sure this is 9 bytes long */
                        emit_byte (acfg, '\xe9');
-                       emit_symbol_diff (acfg, "plt", ".", -4);
+                       emit_symbol_diff (acfg, acfg->plt_symbol, ".", -4);
                        emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
                }
 #elif defined(TARGET_AMD64)
@@ -571,6 +658,23 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
                 * The plt_got_info_offset is computed automatically by 
                 * mono_aot_get_plt_info_offset (), so no need to save it here.
                 */
+#elif defined(TARGET_POWERPC)
+               guint32 offset = (acfg->plt_got_offset_base + index) * sizeof (gpointer);
+
+               /* The GOT address is guaranteed to be in r30 by OP_LOAD_GOTADDR */
+               g_assert (!acfg->use_bin_writer);
+               img_writer_emit_unset_mode (acfg->w);
+               fprintf (acfg->fp, "lis 11, %d@h\n", offset);
+               fprintf (acfg->fp, "ori 11, 11, %d@l\n", offset);
+               fprintf (acfg->fp, "add 11, 11, 30\n");
+               fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+               fprintf (acfg->fp, "%s 2, %d(11)\n", PPC_LD_OP, (int)sizeof (gpointer));
+               fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
+#endif
+               fprintf (acfg->fp, "mtctr 11\n");
+               fprintf (acfg->fp, "bctr\n");
+               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
 #else
                g_assert_not_reached ();
 #endif
@@ -633,6 +737,45 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
         */
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4 + 4);
        //emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4 + 8);
+#elif defined(TARGET_POWERPC)
+       guint8 buf [128];
+       guint8 *code;
+
+       *tramp_size = 4;
+       code = buf;
+
+       g_assert (!acfg->use_bin_writer);
+
+       /*
+        * PPC has no ip relative addressing, so we need to compute the address
+        * of the mscorlib got. That is slow and complex, so instead, we store it
+        * in the second got slot of every aot image. The caller already computed
+        * the address of its got and placed it into r30.
+        */
+       img_writer_emit_unset_mode (acfg->w);
+       /* Load mscorlib got address */
+       fprintf (acfg->fp, "%s 0, %d(30)\n", PPC_LD_OP, (int)sizeof (gpointer));
+       /* Load generic trampoline address */
+       fprintf (acfg->fp, "lis 11, %d@h\n", (int)(offset * sizeof (gpointer)));
+       fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)(offset * sizeof (gpointer)));
+       fprintf (acfg->fp, "%s 11, 11, 0\n", PPC_LDX_OP);
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+       fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
+#endif
+       fprintf (acfg->fp, "mtctr 11\n");
+       /* Load trampoline argument */
+       /* On ppc, we pass it normally to the generic trampoline */
+       fprintf (acfg->fp, "lis 11, %d@h\n", (int)((offset + 1) * sizeof (gpointer)));
+       fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)((offset + 1) * sizeof (gpointer)));
+       fprintf (acfg->fp, "%s 0, 11, 0\n", PPC_LDX_OP);
+       /* Branch to generic trampoline */
+       fprintf (acfg->fp, "bctr\n");
+
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+       *tramp_size = 10 * 4;
+#else
+       *tramp_size = 9 * 4;
+#endif
 #else
        g_assert_not_reached ();
 #endif
@@ -686,6 +829,16 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGeneri
        } else {
                fprintf (acfg->fp, "\n\tb %s\n", call_target);
        }
+#elif defined(TARGET_POWERPC)
+       int this_pos = 3;
+
+       if (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret))
+               this_pos = 4;
+
+       g_assert (!acfg->use_bin_writer);
+
+       fprintf (acfg->fp, "\n\taddi %d, %d, %d\n", this_pos, this_pos, (int)sizeof (MonoObject));
+       fprintf (acfg->fp, "\n\tb %s\n", call_target);
 #else
        g_assert_not_reached ();
 #endif
@@ -738,6 +891,46 @@ arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_
        emit_bytes (acfg, buf, code - buf);
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4 + 8);
        emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4 + 4);
+#elif defined(TARGET_POWERPC)
+       guint8 buf [128];
+       guint8 *code;
+
+       *tramp_size = 4;
+       code = buf;
+
+       g_assert (!acfg->use_bin_writer);
+
+       /*
+        * PPC has no ip relative addressing, so we need to compute the address
+        * of the mscorlib got. That is slow and complex, so instead, we store it
+        * in the second got slot of every aot image. The caller already computed
+        * the address of its got and placed it into r30.
+        */
+       img_writer_emit_unset_mode (acfg->w);
+       /* Load mscorlib got address */
+       fprintf (acfg->fp, "%s 0, %d(30)\n", PPC_LD_OP, (int)sizeof (gpointer));
+       /* Load rgctx */
+       fprintf (acfg->fp, "lis 11, %d@h\n", (int)(offset * sizeof (gpointer)));
+       fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)(offset * sizeof (gpointer)));
+       fprintf (acfg->fp, "%s %d, 11, 0\n", PPC_LDX_OP, MONO_ARCH_RGCTX_REG);
+       /* Load target address */
+       fprintf (acfg->fp, "lis 11, %d@h\n", (int)((offset + 1) * sizeof (gpointer)));
+       fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)((offset + 1) * sizeof (gpointer)));
+       fprintf (acfg->fp, "%s 11, 11, 0\n", PPC_LDX_OP);
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+       fprintf (acfg->fp, "%s 2, %d(11)\n", PPC_LD_OP, (int)sizeof (gpointer));
+       fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
+#endif
+       fprintf (acfg->fp, "mtctr 11\n");
+       /* Branch to the target address */
+       fprintf (acfg->fp, "bctr\n");
+
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+       *tramp_size = 11 * 4;
+#else
+       *tramp_size = 9 * 4;
+#endif
+
 #else
        g_assert_not_reached ();
 #endif
@@ -809,15 +1002,15 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
 
        /* The IMT method is in v5 */
 
-       /* Only IP is available, but we need at least two free registers */
-       ARM_PUSH1 (code, ARMREG_R1);
+       /* Need at least two free registers, plus a slot for storing the pc */
+       ARM_PUSH (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_R2));
        labels [0] = code;
        /* Load the parameter from the GOT */
-       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
-       ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_PC, ARMREG_IP);
+       ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
+       ARM_LDR_REG_REG (code, ARMREG_R0, ARMREG_PC, ARMREG_R0);
 
        labels [1] = code;
-       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_IP, 0);
+       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_R0, 0);
        ARM_CMP_REG_REG (code, ARMREG_R1, ARMREG_V5);
        labels [2] = code;
        ARM_B_COND (code, ARMCOND_EQ, 0);
@@ -828,16 +1021,19 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
        ARM_B_COND (code, ARMCOND_EQ, 0);
 
        /* Loop footer */
-       ARM_ADD_REG_IMM8 (code, ARMREG_IP, ARMREG_IP, sizeof (gpointer) * 2);
+       ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (gpointer) * 2);
        labels [4] = code;
        ARM_B (code, 0);
        arm_patch (labels [4], labels [1]);
 
        /* Match */
        arm_patch (labels [2], code);
-       ARM_POP1 (code, ARMREG_R1);
-       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, 4);
-       ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, 0);
+       ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 4);
+       ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 0);
+       /* Save it to the third stack slot */
+       ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, 8);
+       /* Restore the registers and branch */
+       ARM_POP (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_PC));
 
        /* No match */
        arm_patch (labels [3], code);
@@ -845,12 +1041,59 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
 
        /* Fixup offset */
        code2 = labels [0];
-       ARM_LDR_IMM (code2, ARMREG_IP, ARMREG_PC, (code - (labels [0] + 8)));
+       ARM_LDR_IMM (code2, ARMREG_R0, ARMREG_PC, (code - (labels [0] + 8)));
 
        emit_bytes (acfg, buf, code - buf);
        emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) + (code - (labels [0] + 8)) - 4);
 
        *tramp_size = code - buf + 4;
+#elif defined(TARGET_POWERPC)
+       guint8 buf [128];
+       guint8 *code, *labels [16];
+
+       code = buf;
+
+       /* Load the mscorlib got address */
+       ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
+       /* Load the parameter from the GOT */
+       ppc_load (code, ppc_r0, offset * sizeof (gpointer));
+       ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
+
+       /* Load and check key */
+       labels [1] = code;
+       ppc_ldptr (code, ppc_r0, 0, ppc_r11);
+       ppc_cmp (code, 0, sizeof (gpointer) == 8 ? 1 : 0, ppc_r0, MONO_ARCH_IMT_REG);
+       labels [2] = code;
+       ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
+
+       /* End-of-loop check */
+       ppc_cmpi (code, 0, sizeof (gpointer) == 8 ? 1 : 0, ppc_r0, 0);
+       labels [3] = code;
+       ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
+
+       /* Loop footer */
+       ppc_addi (code, ppc_r11, ppc_r11, 2 * sizeof (gpointer));
+       labels [4] = code;
+       ppc_b (code, 0);
+       mono_ppc_patch (labels [4], labels [1]);
+
+       /* Match */
+       mono_ppc_patch (labels [2], code);
+       ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r11);
+       /* r11 now contains the value of the vtable slot */
+       /* this is not a function descriptor on ppc64 */
+       ppc_ldptr (code, ppc_r11, 0, ppc_r11);
+       ppc_mtctr (code, ppc_r11);
+       ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+
+       /* Fail */
+       mono_ppc_patch (labels [3], code);
+       /* FIXME: */
+       ppc_break (code);
+
+       *tramp_size = code - buf;
+
+       emit_bytes (acfg, buf, code - buf);
 #else
        g_assert_not_reached ();
 #endif
@@ -870,6 +1113,12 @@ arch_get_cie_program (void)
        mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, AMD64_RSP, 8);
        mono_add_unwind_op_offset (l, (guint8*)NULL, (guint8*)NULL, AMD64_RIP, -8);
 
+       return l;
+#elif defined(TARGET_POWERPC)
+       GSList *l = NULL;
+
+       mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
+
        return l;
 #else
        return NULL;
@@ -1461,7 +1710,7 @@ static void
 add_wrappers (MonoAotCompile *acfg)
 {
        MonoMethod *method, *m;
-       int i, j, nallocators;
+       int i, j;
        MonoMethodSignature *sig, *csig;
        guint32 token;
 
@@ -1476,62 +1725,6 @@ add_wrappers (MonoAotCompile *acfg)
         * names.
         */
 
-       /* FIXME: Collect these automatically */
-
-       /* Runtime invoke wrappers */
-
-       /* void runtime-invoke () [.cctor] */
-       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
-       csig->ret = &mono_defaults.void_class->byval_arg;
-       add_method (acfg, get_runtime_invoke_sig (csig));
-
-       /* void runtime-invoke () [Finalize] */
-       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
-       csig->hasthis = 1;
-       csig->ret = &mono_defaults.void_class->byval_arg;
-       add_method (acfg, get_runtime_invoke_sig (csig));
-
-       /* void runtime-invoke (string) [exception ctor] */
-       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
-       csig->hasthis = 1;
-       csig->ret = &mono_defaults.void_class->byval_arg;
-       csig->params [0] = &mono_defaults.string_class->byval_arg;
-       add_method (acfg, get_runtime_invoke_sig (csig));
-
-       /* void runtime-invoke (string, string) [exception ctor] */
-       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       csig->hasthis = 1;
-       csig->ret = &mono_defaults.void_class->byval_arg;
-       csig->params [0] = &mono_defaults.string_class->byval_arg;
-       csig->params [1] = &mono_defaults.string_class->byval_arg;
-       add_method (acfg, get_runtime_invoke_sig (csig));
-
-       /* string runtime-invoke () [Exception.ToString ()] */
-       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
-       csig->hasthis = 1;
-       csig->ret = &mono_defaults.string_class->byval_arg;
-       add_method (acfg, get_runtime_invoke_sig (csig));
-
-       /* void runtime-invoke (string, Exception) [exception ctor] */
-       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       csig->hasthis = 1;
-       csig->ret = &mono_defaults.void_class->byval_arg;
-       csig->params [0] = &mono_defaults.string_class->byval_arg;
-       csig->params [1] = &mono_defaults.exception_class->byval_arg;
-       add_method (acfg, get_runtime_invoke_sig (csig));
-
-       /* Assembly runtime-invoke (string, bool) [DoAssemblyResolve] */
-       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-       csig->hasthis = 1;
-       csig->ret = &(mono_class_from_name (
-                                                                               mono_defaults.corlib, "System.Reflection", "Assembly"))->byval_arg;
-       csig->params [0] = &mono_defaults.string_class->byval_arg;
-       csig->params [1] = &mono_defaults.boolean_class->byval_arg;
-       add_method (acfg, get_runtime_invoke_sig (csig));
-
-       /* runtime-invoke used by finalizers */
-       add_method (acfg, mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE));
-
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
                MonoMethod *method;
                guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
@@ -1563,13 +1756,74 @@ add_wrappers (MonoAotCompile *acfg)
        }
 
        if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
+#ifdef MONO_ARCH_HAVE_TLS_GET
                MonoMethodDesc *desc;
                MonoMethod *orig_method;
+               int nallocators;
+#endif
+
+               /* Runtime invoke wrappers */
+
+               /* void runtime-invoke () [.cctor] */
+               csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+               csig->ret = &mono_defaults.void_class->byval_arg;
+               add_method (acfg, get_runtime_invoke_sig (csig));
+
+               /* void runtime-invoke () [Finalize] */
+               csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+               csig->hasthis = 1;
+               csig->ret = &mono_defaults.void_class->byval_arg;
+               add_method (acfg, get_runtime_invoke_sig (csig));
+
+               /* void runtime-invoke (string) [exception ctor] */
+               csig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
+               csig->hasthis = 1;
+               csig->ret = &mono_defaults.void_class->byval_arg;
+               csig->params [0] = &mono_defaults.string_class->byval_arg;
+               add_method (acfg, get_runtime_invoke_sig (csig));
+
+               /* void runtime-invoke (string, string) [exception ctor] */
+               csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
+               csig->hasthis = 1;
+               csig->ret = &mono_defaults.void_class->byval_arg;
+               csig->params [0] = &mono_defaults.string_class->byval_arg;
+               csig->params [1] = &mono_defaults.string_class->byval_arg;
+               add_method (acfg, get_runtime_invoke_sig (csig));
+
+               /* string runtime-invoke () [Exception.ToString ()] */
+               csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+               csig->hasthis = 1;
+               csig->ret = &mono_defaults.string_class->byval_arg;
+               add_method (acfg, get_runtime_invoke_sig (csig));
+
+               /* void runtime-invoke (string, Exception) [exception ctor] */
+               csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
+               csig->hasthis = 1;
+               csig->ret = &mono_defaults.void_class->byval_arg;
+               csig->params [0] = &mono_defaults.string_class->byval_arg;
+               csig->params [1] = &mono_defaults.exception_class->byval_arg;
+               add_method (acfg, get_runtime_invoke_sig (csig));
+
+               /* Assembly runtime-invoke (string, bool) [DoAssemblyResolve] */
+               csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
+               csig->hasthis = 1;
+               csig->ret = &(mono_class_from_name (
+                                                                                       mono_defaults.corlib, "System.Reflection", "Assembly"))->byval_arg;
+               csig->params [0] = &mono_defaults.string_class->byval_arg;
+               csig->params [1] = &mono_defaults.boolean_class->byval_arg;
+               add_method (acfg, get_runtime_invoke_sig (csig));
+
+               /* runtime-invoke used by finalizers */
+               add_method (acfg, mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE));
 
                /* JIT icall wrappers */
                /* FIXME: locking */
                g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper, acfg);
 
+               /* stelemref */
+               add_method (acfg, mono_marshal_get_stelemref ());
+
+#ifdef MONO_ARCH_HAVE_TLS_GET
                /* Managed Allocators */
                nallocators = mono_gc_get_managed_allocator_types ();
                for (i = 0; i < nallocators; ++i) {
@@ -1578,9 +1832,6 @@ add_wrappers (MonoAotCompile *acfg)
                                add_method (acfg, m);
                }
 
-               /* stelemref */
-               add_method (acfg, mono_marshal_get_stelemref ());
-
                /* Monitor Enter/Exit */
                desc = mono_method_desc_new ("Monitor:Enter", FALSE);
                orig_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
@@ -1597,6 +1848,7 @@ add_wrappers (MonoAotCompile *acfg)
                method = mono_monitor_get_fast_path (orig_method);
                if (method)
                        add_method (acfg, method);
+#endif
        }
 
        /* 
@@ -1674,15 +1926,13 @@ add_wrappers (MonoAotCompile *acfg)
                klass = mono_class_get (acfg->image, token);
 
                if (klass->valuetype && !klass->generic_container && ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)) {
-                       MonoMarshalType *info;
                        gboolean can_marshal = TRUE;
-                       int j;
-
-                       info = mono_marshal_load_type_info (klass);
+                       gpointer iter = NULL;
+                       MonoClassField *field;
 
                        /* Only allow a few field types to avoid asserts in the marshalling code */
-                       for (j = 0; j < info->num_fields; j++) {
-                               switch (info->fields [j].field->type->type) {
+                       while ((field = mono_class_get_fields (klass, &iter))) {
+                               switch (field->type->type) {
                                case MONO_TYPE_I4:
                                case MONO_TYPE_U4:
                                case MONO_TYPE_I1:
@@ -1789,6 +2039,14 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
                add_extra_method (acfg, method);
        }
 
+       if (klass->delegate) {
+               method = mono_get_delegate_invoke (klass);
+
+               method = mono_marshal_get_delegate_invoke (method, NULL);
+
+               add_method (acfg, method);
+       }
+
        /* 
         * For ICollection<T>, where T is a vtype, add instances of the helper methods
         * in Array, since a T[] could be cast to ICollection<T>.
@@ -1830,6 +2088,18 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
        }
 }
 
+static void
+add_array_wrappers (MonoAotCompile *acfg, MonoClass *klass)
+{
+       int i;
+
+       mono_class_setup_methods (klass);
+       for (i = 0; i < klass->method.count; ++i) {
+               if (klass->methods [i]->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED)
+                       add_extra_method (acfg, klass->methods [i]);
+       }
+}
+
 /*
  * add_generic_instances:
  *
@@ -1898,6 +2168,157 @@ add_generic_instances (MonoAotCompile *acfg)
                                        add_generic_class (acfg, mono_class_from_mono_type (header->locals [j]));
                }
        }
+
+       if (acfg->image == mono_defaults.corlib) {
+               /* Add GenericComparer<T> instances for primitive types for Enum.ToString () */
+               MonoClass *klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
+
+               if (klass) {
+                       MonoGenericContext ctx;
+                       MonoType *args [16];
+
+                       memset (&ctx, 0, sizeof (ctx));
+
+                       args [0] = &mono_defaults.byte_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.sbyte_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.int16_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.uint16_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.int32_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.uint32_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.int64_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.uint64_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+               }
+
+               /* Add GenericEqualityComparer<T> instances for primitive types */
+               klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericEqualityComparer`1");
+
+               if (klass) {
+                       MonoGenericContext ctx;
+                       MonoType *args [16];
+
+                       memset (&ctx, 0, sizeof (ctx));
+
+                       args [0] = &mono_defaults.byte_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.sbyte_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.int16_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.uint16_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.int32_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.uint32_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.int64_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+
+                       args [0] = &mono_defaults.uint64_class->byval_arg;
+                       ctx.class_inst = mono_metadata_get_generic_inst (1, args);
+                       add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx));
+               }
+
+               /* Emit the array wrapper methods for arrays of primitive types */
+               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.byte_class, 1));
+               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.sbyte_class, 1));
+               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int16_class, 1));
+               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.uint16_class, 1));
+               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int32_class, 1));
+               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.uint32_class, 1));
+               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.int64_class, 1));
+               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.single_class, 1));
+               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.double_class, 1));
+               /* These are not handled by generic sharing */
+               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.object_class, 1));
+               add_array_wrappers (acfg, mono_array_class_get (mono_defaults.string_class, 1));
+
+               /* Add instances of Array.GetGenericValueImpl */
+               {
+                       MonoGenericContext ctx;
+                       MonoType *args [16];
+                       MonoMethod *method;
+
+                       memset (&ctx, 0, sizeof (ctx));
+
+                       /* 
+                        * managed-to-native wrappers are not shared, so have to generate 
+                        * these for ref types too.
+                        */
+                       klass = mono_array_class_get (mono_defaults.int_class, 1)->parent;
+                       method = mono_class_get_method_from_name (klass, "GetGenericValueImpl", 2);
+
+                       if (method) {
+                               /* String */
+                               args [0] = &mono_defaults.string_class->byval_arg;
+                               ctx.method_inst = mono_metadata_get_generic_inst (1, args);
+                               add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (method, &ctx), TRUE, TRUE));
+                       }
+               }
+       }
+}
+
+/*
+ * is_direct_callable:
+ *
+ *   Return whenever the method identified by JI is directly callable without 
+ * going through the PLT.
+ */
+static gboolean
+is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patch_info)
+{
+       if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == acfg->image)) {
+               MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
+               if (callee_cfg) {
+                       gboolean direct_callable = TRUE;
+
+                       if (direct_callable && !(!callee_cfg->has_got_slots && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
+                               direct_callable = FALSE;
+                       if ((callee_cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) && (!method || method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED))
+                               // FIXME: Maybe call the wrapper directly ?
+                               direct_callable = FALSE;
+
+                       if (direct_callable)
+                               return TRUE;
+               }
+       }
+
+       return FALSE;
 }
 
 /*
@@ -1954,6 +2375,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                arch_emit_got_offset (acfg, code + i, &code_size);
                                i += code_size - 1;
                                skip = TRUE;
+                               patch_info->type = MONO_PATCH_INFO_NONE;
                                break;
                        }
                        default: {
@@ -1963,23 +2385,14 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                 * the same assembly and requires no initialization.
                                 */
                                direct_call = FALSE;
-                               if (!got_only && (patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == method->klass->image)) {
-                                       MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
-                                       if (callee_cfg) {
-                                               gboolean direct_callable = TRUE;
-
-                                               if (direct_callable && !(!callee_cfg->has_got_slots && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
-                                                       direct_callable = FALSE;
-                                               if ((callee_cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) && method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
-                                                       // FIXME: Maybe call the wrapper directly ?
-                                                       direct_callable = FALSE;
-                                               if (direct_callable) {
-                                                       //printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
-                                                       direct_call = TRUE;
-                                                       sprintf (direct_call_target, "%sm_%x", acfg->temp_prefix, get_method_index (acfg, callee_cfg->orig_method));
-                                                       patch_info->type = MONO_PATCH_INFO_NONE;
-                                                       acfg->stats.direct_calls ++;
-                                               }
+                               if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == acfg->image)) {
+                                       if (!got_only && is_direct_callable (acfg, method, patch_info)) {
+                                               MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
+                                               //printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
+                                               direct_call = TRUE;
+                                               sprintf (direct_call_target, "%sm_%x", acfg->temp_prefix, get_method_index (acfg, callee_cfg->orig_method));
+                                               patch_info->type = MONO_PATCH_INFO_NONE;
+                                               acfg->stats.direct_calls ++;
                                        }
 
                                        acfg->stats.all_calls ++;
@@ -2036,12 +2449,67 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
        }
 }
 
+/*
+ * sanitize_symbol:
+ *
+ *   Modify SYMBOL so it only includes characters permissible in symbols.
+ */
+static void
+sanitize_symbol (char *symbol)
+{
+       int i, len = strlen (symbol);
+
+       for (i = 0; i < len; ++i)
+               if (!isalnum (symbol [i]) && (symbol [i] != '_'))
+                       symbol [i] = '_';
+}
+
+static char*
+get_debug_sym (MonoMethod *method, const char *prefix, GHashTable *cache)
+{
+       char *name1, *name2, *cached;
+       int i, j, len, count;
+               
+       name1 = mono_method_full_name (method, TRUE);
+       len = strlen (name1);
+       name2 = malloc (strlen (prefix) + len + 16);
+       memcpy (name2, prefix, strlen (prefix));
+       j = strlen (prefix);
+       for (i = 0; i < len; ++i) {
+               if (isalnum (name1 [i])) {
+                       name2 [j ++] = name1 [i];
+               } else if (name1 [i] == ' ' && name1 [i + 1] == '(' && name1 [i + 2] == ')') {
+                       i += 2;
+               } else if (name1 [i] == ',' && name1 [i + 1] == ' ') {
+                       name2 [j ++] = '_';
+                       i++;
+               } else if (name1 [i] == '(' || name1 [i] == ')' || name1 [i] == '>') {
+               } else
+                       name2 [j ++] = '_';
+       }
+       name2 [j] = '\0';
+
+       g_free (name1);
+
+       count = 0;
+       while (g_hash_table_lookup (cache, name2)) {
+               sprintf (name2 + j, "_%d", count);
+               count ++;
+       }
+
+       cached = g_strdup (name2);
+       g_hash_table_insert (cache, cached, cached);
+
+       return name2;
+}
+
 static void
 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
 {
        MonoMethod *method;
        int method_index;
        guint8 *code;
+       char *debug_sym = NULL;
        char symbol [128];
        int func_alignment = AOT_FUNC_ALIGNMENT;
        MonoMethodHeader *header;
@@ -2079,47 +2547,17 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        emit_label (acfg, symbol);
 
        if (acfg->aot_opts.write_symbols) {
-               char *name1, *name2, *cached;
-               int i, j, len, count;
-
                /* 
                 * Write a C style symbol for every method, this has two uses:
                 * - it works on platforms where the dwarf debugging info is not
                 *   yet supported.
                 * - it allows the setting of breakpoints of aot-ed methods.
                 */
-               name1 = mono_method_full_name (method, TRUE);
-               len = strlen (name1);
-               name2 = malloc (len + 1);
-               j = 0;
-               for (i = 0; i < len; ++i) {
-                       if (isalnum (name1 [i])) {
-                               name2 [j ++] = name1 [i];
-                       } else if (name1 [i] == ' ' && name1 [i + 1] == '(' && name1 [i + 2] == ')') {
-                               i += 2;
-                       } else if (name1 [i] == ',' && name1 [i + 1] == ' ') {
-                               name2 [j ++] = '_';
-                               i++;
-                       } else if (name1 [i] == '(' || name1 [i] == ')' || name1 [i] == '>') {
-                       } else
-                               name2 [j ++] = '_';
-               }
-               name2 [j] = '\0';
-
-               count = 0;
-               while (g_hash_table_lookup (acfg->method_label_hash, name2)) {
-                       sprintf (name2 + j, "_%d", count);
-                       count ++;
-               }
-
-               cached = g_strdup (name2);
-               g_hash_table_insert (acfg->method_label_hash, cached, cached);
+               debug_sym = get_debug_sym (method, "", acfg->method_label_hash);
 
                sprintf (symbol, "%sme_%x", acfg->temp_prefix, method_index);
-               emit_local_symbol (acfg, name2, symbol, TRUE);
-               emit_label (acfg, name2);
-               g_free (name1);
-               g_free (name2);
+               emit_local_symbol (acfg, debug_sym, symbol, TRUE);
+               emit_label (acfg, debug_sym);
        }
 
        if (cfg->verbose_level > 0)
@@ -2133,6 +2571,11 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
 
        emit_line (acfg);
 
+       if (acfg->aot_opts.write_symbols) {
+               emit_symbol_size (acfg, debug_sym, ".");
+               g_free (debug_sym);
+       }
+
        sprintf (symbol, "%sme_%x", acfg->temp_prefix, method_index);
        emit_label (acfg, symbol);
 }
@@ -2153,6 +2596,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        case MONO_PATCH_INFO_IMAGE:
                encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
                break;
+       case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
+               break;
        case MONO_PATCH_INFO_METHOD_REL:
                encode_value ((gint)patch_info->data.offset, p, &p);
                break;
@@ -2447,7 +2892,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        use_unwind_ops = cfg->unwind_ops != NULL;
 #endif
 
-       flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0);
+       flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0);
 
        encode_value (jinfo->code_size, p, &p);
        encode_value (flags, p, &p);
@@ -2468,19 +2913,28 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        }
 
        /* Exception table */
-       if (header->num_clauses) {
-               for (k = 0; k < header->num_clauses; ++k) {
-                       MonoJitExceptionInfo *ei = &jinfo->clauses [k];
+       if (jinfo->num_clauses)
+               encode_value (jinfo->num_clauses, p, &p);
 
-                       encode_value (ei->exvar_offset, p, &p);
+       for (k = 0; k < jinfo->num_clauses; ++k) {
+               MonoJitExceptionInfo *ei = &jinfo->clauses [k];
 
-                       if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
-                               encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+               encode_value (ei->exvar_offset, p, &p);
 
-                       encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
-                       encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
-                       encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
+               if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
+                       encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+               else {
+                       if (ei->data.catch_class) {
+                               encode_value (1, p, &p);
+                               encode_klass_ref (acfg, ei->data.catch_class, p, &p);
+                       } else {
+                               encode_value (0, p, &p);
+                       }
                }
+
+               encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
+               encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
+               encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
        }
 
        if (jinfo->has_generic_jit_info) {
@@ -2606,6 +3060,9 @@ emit_plt (MonoAotCompile *acfg)
 {
        char symbol [128];
        int i;
+       GHashTable *cache;
+
+       cache = g_hash_table_new (g_str_hash, g_str_equal);
 
        emit_line (acfg);
        sprintf (symbol, "plt");
@@ -2619,28 +3076,83 @@ emit_plt (MonoAotCompile *acfg)
        emit_alignment (acfg, 16);
 #endif
        emit_label (acfg, symbol);
+       emit_label (acfg, acfg->plt_symbol);
 
        for (i = 0; i < acfg->plt_offset; ++i) {
                char label [128];
+               char *debug_sym = NULL;
 
                sprintf (label, "%sp_%d", acfg->temp_prefix, i);
                emit_label (acfg, label);
 
+               if (acfg->aot_opts.write_symbols) {
+                       MonoJumpInfo *ji = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
+                       char *debug_sym = NULL;
+
+                       if (ji) {
+                               switch (ji->type) {
+                               case MONO_PATCH_INFO_METHOD:
+                                       debug_sym = get_debug_sym (ji->data.method, "plt_", cache);
+                                       break;
+                               case MONO_PATCH_INFO_INTERNAL_METHOD:
+                                       debug_sym = g_strdup_printf ("plt__jit_icall_%s", ji->data.name);
+                                       break;
+                               case MONO_PATCH_INFO_CLASS_INIT:
+                                       debug_sym = g_strdup_printf ("plt__class_init_%s", mono_type_get_name (&ji->data.klass->byval_arg));
+                                       sanitize_symbol (debug_sym);
+                                       break;
+                               case MONO_PATCH_INFO_RGCTX_FETCH:
+                                       debug_sym = g_strdup_printf ("plt__rgctx_fetch_%d", acfg->label_generator ++);
+                                       break;
+                               case MONO_PATCH_INFO_ICALL_ADDR: {
+                                       char *s = get_debug_sym (ji->data.method, "", cache);
+                                       
+                                       debug_sym = g_strdup_printf ("plt__icall_native_%s", s);
+                                       g_free (s);
+                                       break;
+                               }
+                               case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+                                       debug_sym = g_strdup_printf ("plt__jit_icall_native_%s", ji->data.name);
+                                       break;
+                               case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
+                                       debug_sym = g_strdup_printf ("plt__generic_class_init");
+                                       break;
+                               default:
+                                       break;
+                               }
+
+                               if (debug_sym) {
+                                       emit_local_symbol (acfg, debug_sym, NULL, TRUE);
+                                       emit_label (acfg, debug_sym);
+                               }
+                       }
+               }
+
                /* 
                 * The first plt entry is used to transfer code to the AOT loader. 
                 */
                arch_emit_plt_entry (acfg, i);
+
+               if (debug_sym) {
+                       emit_symbol_size (acfg, debug_sym, ".");
+                       g_free (debug_sym);
+               }
        }
 
+       emit_symbol_size (acfg, acfg->plt_symbol, ".");
+
        sprintf (symbol, "plt_end");
        emit_global (acfg, symbol, TRUE);
        emit_label (acfg, symbol);
+
+       g_hash_table_destroy (cache);
 }
 
 static G_GNUC_UNUSED void
 emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code, 
                                 guint32 code_size, int got_offset, MonoJumpInfo *ji, GSList *unwind_ops)
 {
+       char start_symbol [256];
        char symbol [256];
        guint32 buf_size;
        MonoJumpInfo *patch_info;
@@ -2649,12 +3161,12 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
 
        /* Emit code */
 
-       sprintf (symbol, "%s", name);
+       sprintf (start_symbol, "%s", name);
 
        emit_section_change (acfg, ".text", 0);
-       emit_global (acfg, symbol, TRUE);
+       emit_global (acfg, start_symbol, TRUE);
        emit_alignment (acfg, 16);
-       emit_label (acfg, symbol);
+       emit_label (acfg, start_symbol);
 
        sprintf (symbol, "%snamed_%s", acfg->temp_prefix, name);
        emit_label (acfg, symbol);
@@ -2665,12 +3177,15 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
         */
        emit_and_reloc_code (acfg, NULL, code, code_size, ji, TRUE);
 
+       emit_symbol_size (acfg, start_symbol, ".");
+
        /* Emit info */
 
        /* Sort relocations */
        patches = g_ptr_array_new ();
        for (patch_info = ji; patch_info; patch_info = patch_info->next)
-               g_ptr_array_add (patches, patch_info);
+               if (patch_info->type != MONO_PATCH_INFO_NONE)
+                       g_ptr_array_add (patches, patch_info);
        g_ptr_array_sort (patches, compare_patches);
 
        buf_size = patches->len * 128 + 128;
@@ -2770,7 +3285,6 @@ emit_trampolines (MonoAotCompile *acfg)
                emit_trampoline (acfg, "throw_pending_exception", code, code_size, acfg->got_offset, ji, NULL);
 #endif
 
-#if defined(TARGET_AMD64) || defined(TARGET_ARM)
                for (i = 0; i < 128; ++i) {
                        int offset;
 
@@ -2784,9 +3298,7 @@ emit_trampolines (MonoAotCompile *acfg)
                        sprintf (symbol, "rgctx_fetch_trampoline_%u", offset);
                        emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL);
                }
-#endif
 
-#if defined(TARGET_AMD64) || defined(TARGET_ARM)
                {
                        GSList *l;
 
@@ -2799,7 +3311,6 @@ emit_trampolines (MonoAotCompile *acfg)
                                l = l->next;
                        }
                }
-#endif
 
 #endif /* #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES */
 
@@ -2935,6 +3446,8 @@ 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 {
                        fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
                        exit (1);
@@ -3193,6 +3706,13 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                        }
                        break;
                }
+               case MONO_PATCH_INFO_VTABLE: {
+                       MonoClass *klass = patch_info->data.klass;
+
+                       if (klass->generic_class && !mono_generic_context_is_sharable (&klass->generic_class->context, FALSE))
+                               add_generic_class (acfg, klass);
+                       break;
+               }
                default:
                        break;
                }
@@ -3391,6 +3911,14 @@ emit_code (MonoAotCompile *acfg)
        char symbol [256];
        GList *l;
 
+#if defined(TARGET_POWERPC64)
+       sprintf (symbol, ".Lgot_addr");
+       emit_section_change (acfg, ".text", 0);
+       emit_alignment (acfg, 8);
+       emit_label (acfg, symbol);
+       emit_pointer (acfg, acfg->got_symbol);
+#endif
+
        sprintf (symbol, "methods");
        emit_section_change (acfg, ".text", 0);
        emit_global (acfg, symbol, TRUE);
@@ -4153,6 +4681,9 @@ emit_got_info (MonoAotCompile *acfg)
        p = buf = mono_mempool_alloc (acfg->mempool, buf_size);
        got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->got_patches->len * sizeof (guint32));
        acfg->plt_got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->plt_offset * sizeof (guint32));
+       /* Unused */
+       if (acfg->plt_offset)
+               acfg->plt_got_info_offsets [0] = 0;
        for (i = 0; i < acfg->got_patches->len; ++i) {
                MonoJumpInfo *ji = g_ptr_array_index (acfg->got_patches, i);
 
@@ -4196,7 +4727,7 @@ emit_got (MonoAotCompile *acfg)
        char symbol [256];
 
        /* Don't make GOT global so accesses to it don't need relocations */
-       sprintf (symbol, acfg->got_symbol);
+       sprintf (symbol, "%s", acfg->got_symbol);
        emit_section_change (acfg, ".bss", 0);
        emit_alignment (acfg, 8);
        emit_local_symbol (acfg, symbol, "got_end", FALSE);
@@ -4335,6 +4866,7 @@ emit_file_info (MonoAotCompile *acfg)
        emit_int32 (acfg, acfg->plt_got_offset_base);
        emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
        emit_int32 (acfg, acfg->plt_offset);
+       emit_int32 (acfg, acfg->nmethods);
 
        for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
                emit_int32 (acfg, acfg->num_trampolines [i]);
@@ -4471,13 +5003,21 @@ compile_asm (MonoAotCompile *acfg)
 {
        char *command, *objfile;
        char *outfile_name, *tmp_outfile_name;
+       const char *tool_prefix = acfg->aot_opts.tool_prefix ? acfg->aot_opts.tool_prefix : "";
 
 #if defined(TARGET_AMD64)
 #define AS_OPTIONS "--64"
+#elif defined(TARGET_POWERPC64)
+#define AS_OPTIONS "-a64 -mppc64"
+#define LD_OPTIONS "-m elf64ppc"
 #elif defined(sparc) && SIZEOF_VOID_P == 8
 #define AS_OPTIONS "-xarch=v9"
 #else
 #define AS_OPTIONS ""
+#endif
+
+#ifndef LD_OPTIONS
+#define LD_OPTIONS ""
 #endif
 
        if (acfg->aot_opts.asm_only) {
@@ -4495,7 +5035,7 @@ compile_asm (MonoAotCompile *acfg)
        } else {
                objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
        }
-       command = g_strdup_printf ("as %s %s -o %s", AS_OPTIONS, acfg->tmpfname, objfile);
+       command = g_strdup_printf ("%sas %s %s -o %s", tool_prefix, AS_OPTIONS, acfg->tmpfname, objfile);
        printf ("Executing the native assembler: %s\n", command);
        if (system (command) != 0) {
                g_free (command);
@@ -4526,7 +5066,7 @@ compile_asm (MonoAotCompile *acfg)
 #elif defined(PLATFORM_WIN32)
        command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
 #else
-       command = g_strdup_printf ("ld -shared -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
+       command = g_strdup_printf ("%sld %s -shared -o %s %s.o", tool_prefix, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
 #endif
        printf ("Executing the native linker: %s\n", command);
        if (system (command) != 0) {
@@ -4549,7 +5089,7 @@ compile_asm (MonoAotCompile *acfg)
         * gas generates 'mapping symbols' each time code and data is mixed, which 
         * happens a lot in emit_and_reloc_code (), so we need to get rid of them.
         */
-       command = g_strdup_printf ("strip --strip-symbol=\\$a --strip-symbol=\\$d %s", tmp_outfile_name);
+       command = g_strdup_printf ("%sstrip --strip-symbol=\\$a --strip-symbol=\\$d %s", tool_prefix, tmp_outfile_name);
        printf ("Stripping the binary: %s\n", command);
        if (system (command) != 0) {
                g_free (tmp_outfile_name);
@@ -4615,6 +5155,8 @@ acfg_free (MonoAotCompile *acfg)
                        g_free (acfg->cfgs [i]);
        g_free (acfg->cfgs);
        g_free (acfg->static_linking_symbol);
+       g_free (acfg->got_symbol);
+       g_free (acfg->plt_symbol);
        g_ptr_array_free (acfg->methods, TRUE);
        g_ptr_array_free (acfg->got_patches, TRUE);
        g_ptr_array_free (acfg->image_table, TRUE);
@@ -4674,13 +5216,17 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? 128 : 0;
 
        acfg->got_symbol = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
+       acfg->plt_symbol = g_strdup_printf ("mono_aot_%s_plt", acfg->image->assembly->aname.name);
 
        /* Get rid of characters which cannot occur in symbols */
-       p = acfg->got_symbol;
        for (p = acfg->got_symbol; *p; ++p) {
                if (!(isalnum (*p) || *p == '_'))
                        *p = '_';
        }
+       for (p = acfg->plt_symbol; *p; ++p) {
+               if (!(isalnum (*p) || *p == '_'))
+                       *p = '_';
+       }
 
        acfg->method_index = 1;
 
@@ -4701,6 +5247,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                ji->data.image = acfg->image;
 
                get_got_offset (acfg, ji);
+
+               /* Slot 1 is reserved for the mscorlib got addr */
+               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
+               ji->type = MONO_PATCH_INFO_MSCORLIB_GOT_ADDR;
+               get_got_offset (acfg, ji);
        }
 
        TV_GETTIME (atv);