Fix mono_patch_info_equal () for MONO_PATCH_INFO_GSHAREDVT_CALL.
[mono.git] / mono / mini / aot-compiler.c
index 320f9d9d6b5dc95476eadb1125355c135edcf8eb..853327fe79f1c43c0a694e9e8dbc706003ad17be 100644 (file)
@@ -65,6 +65,7 @@
 #include "mini.h"
 #include "image-writer.h"
 #include "dwarfwriter.h"
+#include "mini-gc.h"
 
 #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
 
@@ -80,9 +81,9 @@
 
 #ifdef TARGET_WIN32
 #define SHARED_EXT ".dll"
-#elif defined(__ppc__) && defined(__APPLE__)
+#elif defined(__ppc__) && defined(TARGET_MACH)
 #define SHARED_EXT ".dylib"
-#elif defined(__APPLE__) && defined(TARGET_X86) && !defined(__native_client_codegen__)
+#elif defined(TARGET_MACH) && defined(TARGET_X86) && !defined(__native_client_codegen__)
 #define SHARED_EXT ".dylib"
 #else
 #define SHARED_EXT ".so"
@@ -124,10 +125,14 @@ typedef struct MonoAotOptions {
        gboolean log_generics;
        gboolean direct_pinvoke;
        gboolean direct_icalls;
+       gboolean no_direct_calls;
+       gboolean use_trampolines_page;
+       gboolean no_instances;
        int nthreads;
        int ntrampolines;
        int nrgctx_trampolines;
        int nimt_trampolines;
+       int ngsharedvt_arg_trampolines;
        gboolean print_skipped_methods;
        gboolean stats;
        char *tool_prefix;
@@ -216,6 +221,8 @@ typedef struct MonoAotCompile {
        GHashTable *plt_entry_debug_sym_cache;
        gboolean thumb_mixed, need_no_dead_strip, need_pt_gnu_stack;
        GHashTable *ginst_hash;
+       gboolean global_symbols;
+       gboolean direct_method_addresses;
 } MonoAotCompile;
 
 typedef struct {
@@ -407,7 +414,7 @@ static void
 emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
 {
        img_writer_emit_section_change (acfg->w, RODATA_SECT, 1);
-#ifdef __APPLE__
+#ifdef TARGET_MACH
        /* On apple, all symbols need to be aligned to avoid warnings from ld */
        emit_alignment (acfg, 4);
 #endif
@@ -531,7 +538,7 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #endif
 
 #ifdef TARGET_ARM
-#ifdef __MACH__
+#ifdef TARGET_MACH
 #define AOT_TARGET_STR "ARM (MACH)"
 #else
 #define AOT_TARGET_STR "ARM (!MACH)"
@@ -587,7 +594,7 @@ arch_init (MonoAotCompile *acfg)
                g_string_append (acfg->llc_args, "-mattr=+v6");
        } else {
 #ifdef ARM_FPU_VFP
-               g_string_append (acfg->llc_args, " -mattr=+vfp2,+d16");
+               g_string_append (acfg->llc_args, " -mattr=+vfp2,-neon,+d16");
                g_string_append (acfg->as_args, " -mfpu=vfp3");
 #else
                g_string_append (acfg->llc_args, " -soft-float");
@@ -600,7 +607,7 @@ arch_init (MonoAotCompile *acfg)
                mono_arch_set_target (acfg->aot_opts.mtriple);
 #endif
 
-#ifdef __APPLE__
+#ifdef TARGET_MACH
        acfg->llvm_label_prefix = "_";
        acfg->need_no_dead_strip = TRUE;
 #endif
@@ -608,6 +615,11 @@ arch_init (MonoAotCompile *acfg)
 #if defined(__linux__) && !defined(TARGET_ARM)
        acfg->need_pt_gnu_stack = TRUE;
 #endif
+
+#ifdef MONOTOUCH
+       acfg->direct_method_addresses = TRUE;
+       acfg->global_symbols = TRUE;
+#endif
 }
 
 /*
@@ -896,6 +908,152 @@ arch_emit_llvm_plt_entry (MonoAotCompile *acfg, int index)
 #endif
 }
 
+/*
+ * arch_emit_specific_trampoline_pages:
+ *
+ * Emits a page full of trampolines: each trampoline uses its own address to
+ * lookup both the generic trampoline code and the data argument.
+ * This page can be remapped in process multiple times so we can get an
+ * unlimited number of trampolines.
+ * Specifically this implementation uses the following trick: two memory pages
+ * are allocated, with the first containing the data and the second containing the trampolines.
+ * To reduce trampoline size, each trampoline jumps at the start of the page where a common
+ * implementation does all the lifting.
+ * Note that the ARM single trampoline size is 8 bytes, exactly like the data that needs to be stored
+ * on the arm 32 bit system.
+ */
+static void
+arch_emit_specific_trampoline_pages (MonoAotCompile *acfg)
+{
+#if defined(TARGET_ARM)
+       guint8 buf [128];
+       guint8 *code;
+       guint8 *loop_start, *loop_branch_back, *loop_end_check, *imt_found_check;
+       int i;
+#define COMMON_TRAMP_SIZE 16
+       int count = (mono_pagesize () - COMMON_TRAMP_SIZE) / 8;
+       int imm8, rot_amount;
+
+       if (!acfg->aot_opts.use_trampolines_page)
+               return;
+
+       emit_alignment (acfg, mono_pagesize ());
+       emit_global (acfg, "specific_trampolines_page", TRUE);
+       emit_label (acfg, "specific_trampolines_page");
+
+       /* emit the generic code first, the trampoline address + 8 is in the lr register */
+       code = buf;
+       imm8 = mono_arm_is_rotated_imm8 (mono_pagesize (), &rot_amount);
+       ARM_SUB_REG_IMM (code, ARMREG_LR, ARMREG_LR, imm8, rot_amount);
+       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_LR, -8);
+       ARM_LDR_IMM (code, ARMREG_PC, ARMREG_LR, -4);
+       ARM_NOP (code);
+       g_assert (code - buf == COMMON_TRAMP_SIZE);
+
+       /* Emit it */
+       emit_bytes (acfg, buf, code - buf);
+
+       for (i = 0; i < count; ++i) {
+               code = buf;
+               ARM_PUSH (code, 0x5fff);
+               ARM_BL (code, 0);
+               arm_patch (code - 4, code - COMMON_TRAMP_SIZE - 8 * (i + 1));
+               g_assert (code - buf == 8);
+               emit_bytes (acfg, buf, code - buf);
+       }
+
+       /* now the rgctx trampolines: each specific trampolines puts in the ip register
+        * the instruction pointer address, so the generic trampoline at the start of the page
+        * subtracts 4096 to get to the data page and loads the values
+        * We again fit the generic trampiline in 16 bytes.
+        */
+       emit_global (acfg, "rgctx_trampolines_page", TRUE);
+       emit_label (acfg, "rgctx_trampolines_page");
+       code = buf;
+       imm8 = mono_arm_is_rotated_imm8 (mono_pagesize (), &rot_amount);
+       ARM_SUB_REG_IMM (code, ARMREG_IP, ARMREG_IP, imm8, rot_amount);
+       ARM_LDR_IMM (code, MONO_ARCH_RGCTX_REG, ARMREG_IP, -8);
+       ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, -4);
+       ARM_NOP (code);
+       g_assert (code - buf == COMMON_TRAMP_SIZE);
+
+       /* Emit it */
+       emit_bytes (acfg, buf, code - buf);
+
+       for (i = 0; i < count; ++i) {
+               code = buf;
+               ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_PC);
+               ARM_B (code, 0);
+               arm_patch (code - 4, code - COMMON_TRAMP_SIZE - 8 * (i + 1));
+               g_assert (code - buf == 8);
+               emit_bytes (acfg, buf, code - buf);
+       }
+       /* now the imt trampolines: each specific trampolines puts in the ip register
+        * the instruction pointer address, so the generic trampoline at the start of the page
+        * subtracts 4096 to get to the data page and loads the values
+        * We again fit the generic trampiline in 16 bytes.
+        */
+#define IMT_TRAMP_SIZE 72
+       emit_global (acfg, "imt_trampolines_page", TRUE);
+       emit_label (acfg, "imt_trampolines_page");
+       code = buf;
+       /* 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));
+
+       imm8 = mono_arm_is_rotated_imm8 (mono_pagesize (), &rot_amount);
+       ARM_SUB_REG_IMM (code, ARMREG_IP, ARMREG_IP, imm8, rot_amount);
+       ARM_LDR_IMM (code, ARMREG_R0, ARMREG_IP, -8);
+
+       /* The IMT method is in v5, r0 has the imt array address */
+
+       loop_start = code;
+       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_R0, 0);
+       ARM_CMP_REG_REG (code, ARMREG_R1, ARMREG_V5);
+       imt_found_check = code;
+       ARM_B_COND (code, ARMCOND_EQ, 0);
+
+       /* End-of-loop check */
+       ARM_CMP_REG_IMM (code, ARMREG_R1, 0, 0);
+       loop_end_check = code;
+       ARM_B_COND (code, ARMCOND_EQ, 0);
+
+       /* Loop footer */
+       ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (gpointer) * 2);
+       loop_branch_back = code;
+       ARM_B (code, 0);
+       arm_patch (loop_branch_back, loop_start);
+
+       /* Match */
+       arm_patch (imt_found_check, code);
+       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 (loop_end_check, code);
+       ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 4);
+       ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, 8);
+       ARM_POP (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_PC));
+       ARM_NOP (code);
+
+       /* Emit it */
+       g_assert (code - buf == IMT_TRAMP_SIZE);
+       emit_bytes (acfg, buf, code - buf);
+
+       for (i = 0; i < count; ++i) {
+               code = buf;
+               ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_PC);
+               ARM_B (code, 0);
+               arm_patch (code - 4, code - IMT_TRAMP_SIZE - 8 * (i + 1));
+               g_assert (code - buf == 8);
+               emit_bytes (acfg, buf, code - buf);
+       }
+#endif
+}
+
 /*
  * arch_emit_specific_trampoline:
  *
@@ -1126,7 +1284,7 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoCompile *cfg, MonoMethod *
        guint8 *code;
 
        if (acfg->thumb_mixed && cfg->compile_llvm) {
-               fprintf (acfg->fp, "add r0, r0, #%d\n", sizeof (MonoObject));
+               fprintf (acfg->fp, "add r0, r0, #%d\n", (int)sizeof (MonoObject));
                fprintf (acfg->fp, "b %s\n", call_target);
                fprintf (acfg->fp, ".arm\n");
                return;
@@ -1594,6 +1752,74 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
 #endif
 }
 
+/*
+ * arch_emit_gsharedvt_arg_trampoline:
+ *
+ *   Emit code for a gsharedvt arg trampoline. OFFSET is the offset of the first of
+ * two GOT slots which contain the argument, and the code to jump to.
+ * TRAMP_SIZE is set to the size of the emitted trampoline.
+ * These kinds of trampolines cannot be enumerated statically, since there could
+ * be one trampoline per method instantiation, so we emit the same code for all
+ * trampolines, and parameterize them using two GOT slots.
+ */
+static void
+arch_emit_gsharedvt_arg_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+#if defined(TARGET_X86)
+       guint8 buf [128];
+       guint8 *code;
+
+       /* Similar to the PPC code above */
+
+       g_assert (MONO_ARCH_RGCTX_REG != X86_ECX);
+
+       code = buf;
+       /* Load mscorlib got address */
+       x86_mov_reg_membase (code, X86_ECX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
+       /* Load arg */
+       x86_mov_reg_membase (code, X86_EAX, X86_ECX, offset * sizeof (gpointer), 4);
+       /* Branch to the target address */
+       x86_jump_membase (code, X86_ECX, (offset + 1) * sizeof (gpointer));
+
+#ifdef __native_client_codegen__
+       {
+               /* emit nops to next 32 byte alignment */
+               int a = (~kNaClAlignmentMask) & ((code - buf) + kNaClAlignment - 1);
+               while (code < (buf + a)) x86_nop(code);
+       }
+#endif
+
+       emit_bytes (acfg, buf, code - buf);
+
+       *tramp_size = NACL_SIZE (15, kNaClAlignment);
+       g_assert (code - buf == *tramp_size);
+#elif defined(TARGET_ARM)
+       guint8 buf [128];
+       guint8 *code;
+
+       /* The same as mono_arch_get_gsharedvt_arg_trampoline (), but for AOT */
+       /* Similar to arch_emit_specific_trampoline () */
+       *tramp_size = 24;
+       code = buf;
+       ARM_PUSH (code, (1 << ARMREG_R0) | (1 << ARMREG_R1) | (1 << ARMREG_R2) | (1 << ARMREG_R3) | (1 << ARMREG_LR));
+       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 8);
+       /* Load the arg value from the GOT */
+       ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_PC, ARMREG_R1);
+       /* Load the addr from the GOT */
+       ARM_LDR_REG_REG (code, ARMREG_R1, ARMREG_PC, ARMREG_R1);
+       /* Branch to it */
+       ARM_BX (code, ARMREG_R1);
+
+       g_assert (code - buf == 20);
+
+       /* Emit it */
+       emit_bytes (acfg, buf, code - buf);
+       emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) + 4);
+#else
+       g_assert_not_reached ();
+#endif
+}      
+
 static void
 arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
 {
@@ -1947,17 +2173,23 @@ encode_klass_ref_inner (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, gui
                }
        } else if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR)) {
                MonoGenericContainer *container = mono_type_get_generic_param_owner (&klass->byval_arg);
-               g_assert (container);
+               MonoGenericParam *par = klass->byval_arg.data.generic_param;
 
                encode_value (MONO_AOT_TYPEREF_VAR, p, &p);
                encode_value (klass->byval_arg.type, p, &p);
                encode_value (mono_type_get_generic_param_num (&klass->byval_arg), p, &p);
-               
-               encode_value (container->is_method, p, &p);
-               if (container->is_method)
-                       encode_method_ref (acfg, container->owner.method, p, &p);
-               else
-                       encode_klass_ref (acfg, container->owner.klass, p, &p);
+
+               encode_value (container ? 1 : 0, p, &p);
+               if (container) {
+                       encode_value (container->is_method, p, &p);
+                       g_assert (par->serial == 0);
+                       if (container->is_method)
+                               encode_method_ref (acfg, container->owner.method, p, &p);
+                       else
+                               encode_klass_ref (acfg, container->owner.klass, p, &p);
+               } else {
+                       encode_value (par->serial, p, &p);
+               }
        } else if (klass->byval_arg.type == MONO_TYPE_PTR) {
                encode_value (MONO_AOT_TYPEREF_PTR, p, &p);
                encode_type (acfg, &klass->byval_arg, p, &p);
@@ -2146,6 +2378,10 @@ encode_type (MonoAotCompile *acfg, MonoType *t, guint8 *buf, guint8 **endbuf)
                        encode_value (array->lobounds [i], p, &p);
                break;
        }
+       case MONO_TYPE_VAR:
+       case MONO_TYPE_MVAR:
+               encode_klass_ref (acfg, mono_class_from_mono_type (t), p, &p);
+               break;
        default:
                g_assert_not_reached ();
        }
@@ -2205,8 +2441,6 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
         * types of method encodings.
         */
 
-       g_assert (image_index < MONO_AOT_METHODREF_MIN);
-
        /* Mark methods which can't use aot trampolines because they need the further 
         * processing in mono_magic_trampoline () which requires a MonoMethod*.
         */
@@ -2338,7 +2572,19 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                        }
                        break;
                }
-               case MONO_WRAPPER_DELEGATE_INVOKE:
+               case MONO_WRAPPER_DELEGATE_INVOKE: {
+                       if (method->is_inflated) {
+                               /* These wrappers are identified by their class */
+                               encode_value (1, p, &p);
+                               encode_klass_ref (acfg, method->klass, p, &p);
+                       } else {
+                               MonoMethodSignature *sig = mono_method_signature (method);
+
+                               encode_value (0, p, &p);
+                               encode_signature (acfg, sig, p, &p);
+                       }
+                       break;
+               }
                case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
                case MONO_WRAPPER_DELEGATE_END_INVOKE: {
                        MonoMethodSignature *sig = mono_method_signature (method);
@@ -2383,7 +2629,6 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                         * doesn't have a token since the reference is generated by the JIT 
                         * like Nullable:Box/Unbox, or by generic sharing.
                         */
-
                        encode_value ((MONO_AOT_METHODREF_GINST << 24), p, &p);
                        /* Encode the klass */
                        encode_klass_ref (acfg, method->klass, p, &p);
@@ -2431,7 +2676,14 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                }
        } else {
                g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
-               encode_value ((image_index << 24) | mono_metadata_token_index (token), p, &p);
+
+               if (image_index >= MONO_AOT_METHODREF_MIN) {
+                       encode_value ((MONO_AOT_METHODREF_LARGE_IMAGE_INDEX << 24), p, &p);
+                       encode_value (image_index, p, &p);
+                       encode_value (mono_metadata_token_index (token), p, &p);
+               } else {
+                       encode_value ((image_index << 24) | mono_metadata_token_index (token), p, &p);
+               }
        }
        *endbuf = p;
 }
@@ -2507,7 +2759,7 @@ is_plt_patch (MonoJumpInfo *patch_info)
 static char*
 get_plt_symbol (MonoAotCompile *acfg, int plt_offset, MonoJumpInfo *patch_info)
 {
-#ifdef __APPLE__
+#ifdef TARGET_MACH
        /* 
         * The Apple linker reorganizes object files, so it doesn't like branches to local
         * labels, since those have no relocations.
@@ -2550,6 +2802,8 @@ get_plt_entry (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
 
                new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
 
+               // g_assert (mono_patch_info_equal (patch_info, new_ji));
+
                res = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoPltEntry));
                res->plt_offset = acfg->plt_offset;
                res->ji = new_ji;
@@ -2704,10 +2958,14 @@ can_marshal_struct (MonoClass *klass)
        MonoClassField *field;
        gboolean can_marshal = TRUE;
        gpointer iter = NULL;
+       MonoMarshalType *info;
+       int i;
 
        if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
                return FALSE;
 
+       info = mono_marshal_load_type_info (klass);
+
        /* Only allow a few field types to avoid asserts in the marshalling code */
        while ((field = mono_class_get_fields (klass, &iter))) {
                if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC))
@@ -2735,6 +2993,19 @@ can_marshal_struct (MonoClass *klass)
                        if (!mono_class_from_mono_type (field->type)->enumtype && !can_marshal_struct (mono_class_from_mono_type (field->type)))
                                can_marshal = FALSE;
                        break;
+               case MONO_TYPE_SZARRAY: {
+                       gboolean has_mspec = FALSE;
+
+                       if (info) {
+                               for (i = 0; i < info->num_fields; ++i) {
+                                       if (info->fields [i].field == field && info->fields [i].mspec)
+                                               has_mspec = TRUE;
+                               }
+                       }
+                       if (!has_mspec)
+                               can_marshal = FALSE;
+                       break;
+               }
                default:
                        can_marshal = FALSE;
                        break;
@@ -2743,12 +3014,66 @@ can_marshal_struct (MonoClass *klass)
 
        /* Special cases */
        /* Its hard to compute whenever these can be marshalled or not */
-       if (!strcmp (klass->name_space, "System.Net.NetworkInformation.MacOsStructs"))
+       if (!strcmp (klass->name_space, "System.Net.NetworkInformation.MacOsStructs") && strcmp (klass->name, "sockaddr_dl"))
                return TRUE;
 
        return can_marshal;
 }
 
+static void
+create_gsharedvt_inst (MonoAotCompile *acfg, MonoMethod *method, MonoGenericContext *ctx)
+{
+       /* Create a vtype instantiation */
+       MonoGenericContext shared_context;
+       MonoType **args;
+       MonoGenericInst *inst;
+       MonoGenericContainer *container;
+       MonoClass **constraints;
+       int i;
+
+       memset (ctx, 0, sizeof (MonoGenericContext));
+
+       if (method->klass->generic_container) {
+               shared_context = method->klass->generic_container->context;
+               inst = shared_context.class_inst;
+
+               args = g_new0 (MonoType*, inst->type_argc);
+               for (i = 0; i < inst->type_argc; ++i) {
+                       args [i] = &mono_defaults.int_class->byval_arg;
+               }
+               ctx->class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
+       }
+       if (method->is_generic) {
+               container = mono_method_get_generic_container (method);
+               shared_context = container->context;
+               inst = shared_context.method_inst;
+
+               args = g_new0 (MonoType*, inst->type_argc);
+               for (i = 0; i < container->type_argc; ++i) {
+                       MonoGenericParamInfo *info = &container->type_params [i].info;
+                       gboolean ref_only = FALSE;
+
+                       if (info && info->constraints) {
+                               constraints = info->constraints;
+
+                               while (*constraints) {
+                                       MonoClass *cklass = *constraints;
+                                       if (!(cklass == mono_defaults.object_class || (cklass->image == mono_defaults.corlib && !strcmp (cklass->name, "ValueType"))))
+                                               /* Inflaring the method with our vtype would not be valid */
+                                               ref_only = TRUE;
+                                       constraints ++;
+                               }
+                       }
+
+                       if (ref_only)
+                               args [i] = &mono_defaults.object_class->byval_arg;
+                       else
+                               args [i] = &mono_defaults.int_class->byval_arg;
+               }
+               ctx->method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
+       }
+}
+
 static void
 add_wrappers (MonoAotCompile *acfg)
 {
@@ -2997,7 +3322,10 @@ add_wrappers (MonoAotCompile *acfg)
                        continue;
                }
 
-               if (klass->delegate && klass != mono_defaults.delegate_class && klass != mono_defaults.multicastdelegate_class && !klass->generic_container) {
+               if (!klass->delegate || klass == mono_defaults.delegate_class || klass == mono_defaults.multicastdelegate_class)
+                       continue;
+
+               if (!klass->generic_container) {
                        method = mono_get_delegate_invoke (klass);
 
                        m = mono_marshal_get_delegate_invoke (method, NULL);
@@ -3018,11 +3346,29 @@ add_wrappers (MonoAotCompile *acfg)
                                int j;
 
                                for (j = 0; j < cattr->num_attrs; ++j)
-                                       if (cattr->attrs [j].ctor && !strcmp (cattr->attrs [j].ctor->klass->name, "MonoNativeFunctionWrapperAttribute"))
+                                       if (cattr->attrs [j].ctor && (!strcmp (cattr->attrs [j].ctor->klass->name, "MonoNativeFunctionWrapperAttribute") || !strcmp (cattr->attrs [j].ctor->klass->name, "UnmanagedFunctionPointerAttribute")))
                                                break;
                                if (j < cattr->num_attrs)
                                        add_method (acfg, mono_marshal_get_native_func_wrapper_aot (klass));
                        }
+               } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->generic_container) {
+                       MonoGenericContext ctx;
+                       MonoMethod *inst, *gshared;
+
+                       /*
+                        * Emit a gsharedvt version of the generic delegate-invoke wrapper
+                        */
+
+                       method = mono_get_delegate_invoke (klass);
+                       create_gsharedvt_inst (acfg, method, &ctx);
+
+                       inst = mono_class_inflate_generic_method (method, &ctx);
+
+                       m = mono_marshal_get_delegate_invoke (inst, NULL);
+                       g_assert (m->is_inflated);
+
+                       gshared = mini_get_shared_method_full (m, FALSE, TRUE);
+                       add_extra_method (acfg, gshared);
                }
        }
 
@@ -3284,6 +3630,9 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
        if (!klass->generic_class && !klass->rank)
                return;
 
+       if (klass->exception_type)
+               return;
+
        if (!acfg->ginst_hash)
                acfg->ginst_hash = g_hash_table_new (NULL, NULL);
 
@@ -3300,7 +3649,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
 
        iter = NULL;
        while ((method = mono_class_get_methods (klass, &iter))) {
-               if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
+               if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, FALSE))
                        /* Already added */
                        continue;
 
@@ -3341,7 +3690,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
         * in Array, since a T[] could be cast to ICollection<T>.
         */
        if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") &&
-               (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1"))) {
+               (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1") || !strcmp (klass->name, "IReadOnlyList`1"))) {
                MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
                MonoClass *array_class = mono_bounded_array_class_get (tclass, 1, FALSE);
                gpointer iter;
@@ -3428,6 +3777,9 @@ add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int
        MonoGenericContext ctx;
        MonoType *args [16];
 
+       if (acfg->aot_opts.no_instances)
+               return;
+
        memset (&ctx, 0, sizeof (ctx));
 
        for (i = 0; i < ninsts; ++i) {
@@ -3476,6 +3828,9 @@ add_generic_instances (MonoAotCompile *acfg)
        MonoMethod *method;
        MonoGenericContext *context;
 
+       if (acfg->aot_opts.no_instances)
+               return;
+
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows; ++i) {
                token = MONO_TOKEN_METHOD_SPEC | (i + 1);
                method = mono_get_method (acfg->image, token, NULL);
@@ -3568,7 +3923,7 @@ add_generic_instances (MonoAotCompile *acfg)
                 * If the method is fully sharable, it was already added in place of its
                 * generic definition.
                 */
-               if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
+               if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, FALSE))
                        continue;
 
                /*
@@ -3696,7 +4051,7 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc
                                // FIXME: Maybe call the wrapper directly ?
                                direct_callable = FALSE;
 
-                       if (acfg->aot_opts.soft_debug) {
+                       if (acfg->aot_opts.soft_debug || acfg->aot_opts.no_direct_calls) {
                                /* Disable this so all calls go through load_method (), see the
                                 * mini_get_debug_options ()->load_aot_jit_info_eagerly = TRUE; line in
                                 * mono_debugger_agent_init ().
@@ -3766,7 +4121,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
        MonoMethodHeader *header;
        gboolean skip, direct_call;
        guint32 got_slot;
-       char direct_call_target [1024];
+       const char *direct_call_target;
        const char *direct_pinvoke;
 
        if (method) {
@@ -3819,8 +4174,9 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                                MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
                                                //printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
                                                direct_call = TRUE;
-                                               g_assert (strlen (callee_cfg->asm_symbol) < 1000);
-                                               sprintf (direct_call_target, "%s", callee_cfg->asm_symbol);
+                                               direct_call_target = callee_cfg->asm_symbol;
+                                               patch_info->type = MONO_PATCH_INFO_NONE;
+                                               acfg->stats.direct_calls ++;
                                        }
 
                                        acfg->stats.all_calls ++;
@@ -3832,14 +4188,14 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                                        direct_pinvoke = get_pinvoke_import (acfg, patch_info->data.method);
                                                if (direct_pinvoke) {
                                                        const char*prefix;
-#if defined(__APPLE__)
+#if defined(TARGET_MACH)
                                                        prefix = "_";
 #else
                                                        prefix = "";
 #endif
                                                        direct_call = TRUE;
                                                        g_assert (strlen (direct_pinvoke) < 1000);
-                                                       sprintf (direct_call_target, "%s%s", prefix, direct_pinvoke);
+                                                       direct_call_target = g_strdup_printf ("%s%s", prefix, direct_pinvoke);
                                                }
                                        }
                                }
@@ -3854,7 +4210,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                        if (plt_entry) {
                                                /* This patch has a PLT entry, so we must emit a call to the PLT entry */
                                                direct_call = TRUE;
-                                               sprintf (direct_call_target, "%s", plt_entry->symbol);
+                                               direct_call_target = plt_entry->symbol;
                
                                                /* Nullify the patch */
                                                patch_info->type = MONO_PATCH_INFO_NONE;
@@ -3922,6 +4278,12 @@ get_debug_sym (MonoMethod *method, const char *prefix, GHashTable *cache)
        char *name1, *name2, *cached;
        int i, j, len, count;
 
+#ifdef TARGET_MACH
+       // This is so that we don't accidentally create a local symbol (which starts with 'L')
+       if (!prefix || !*prefix)
+               prefix = "_";
+#endif
+
        name1 = mono_method_full_name (method, TRUE);
        len = strlen (name1);
        name2 = malloc (strlen (prefix) + len + 16);
@@ -3962,7 +4324,7 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        int method_index;
        guint8 *code;
        char *debug_sym = NULL;
-       char symbol [128];
+       char *symbol = NULL;
        int func_alignment = AOT_FUNC_ALIGNMENT;
        MonoMethodHeader *header;
        char *export_name;
@@ -3972,15 +4334,19 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        header = cfg->header;
 
        method_index = get_method_index (acfg, method);
+       symbol = g_strdup_printf ("%sme_%x", acfg->temp_prefix, method_index);
 
-       /* Make the labels local */
-       sprintf (symbol, "%s", cfg->asm_symbol);
 
+       /* Make the labels local */
        emit_section_change (acfg, ".text", 0);
        emit_alignment (acfg, func_alignment);
-       emit_label (acfg, symbol);
+       
+       if (acfg->global_symbols && acfg->need_no_dead_strip)
+               fprintf (acfg->fp, "    .no_dead_strip %s\n", cfg->asm_symbol);
+       
+       emit_label (acfg, cfg->asm_symbol);
 
-       if (acfg->aot_opts.write_symbols) {
+       if (acfg->aot_opts.write_symbols && !acfg->global_symbols) {
                /* 
                 * Write a C style symbol for every method, this has two uses:
                 * - it works on platforms where the dwarf debugging info is not
@@ -3989,7 +4355,6 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
                 */
                debug_sym = get_debug_sym (method, "", acfg->method_label_hash);
 
-               sprintf (symbol, "%sme_%x", acfg->temp_prefix, method_index);
                if (acfg->need_no_dead_strip)
                        fprintf (acfg->fp, "    .no_dead_strip %s\n", debug_sym);
                emit_local_symbol (acfg, debug_sym, symbol, TRUE);
@@ -4004,7 +4369,7 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        }
 
        if (cfg->verbose_level > 0)
-               g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
+               g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), cfg->asm_symbol);
 
        acfg->stats.code_size += cfg->code_len;
 
@@ -4019,8 +4384,8 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
                g_free (debug_sym);
        }
 
-       sprintf (symbol, "%sme_%x", acfg->temp_prefix, method_index);
        emit_label (acfg, symbol);
+       g_free (symbol);
 }
 
 /**
@@ -4168,6 +4533,10 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        case MONO_PATCH_INFO_SIGNATURE:
                encode_signature (acfg, (MonoMethodSignature*)patch_info->data.target, p, &p);
                break;
+       case MONO_PATCH_INFO_GSHAREDVT_CALL:
+               encode_signature (acfg, (MonoMethodSignature*)patch_info->data.gsharedvt->sig, p, &p);
+               encode_method_ref (acfg, patch_info->data.gsharedvt->method, p, &p);
+               break;
        default:
                g_warning ("unable to handle jump info %d", patch_info->type);
                g_assert_not_reached ();
@@ -4453,6 +4822,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        if (jinfo->has_generic_jit_info) {
                MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (jinfo);
+               MonoGenericSharingContext* gsctx = gi->generic_sharing_context;
                guint8 *p1;
 
                p1 = p;
@@ -4484,6 +4854,38 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                 * when using generic sharing.
                 */
                encode_method_ref (acfg, jinfo->method, p, &p);
+
+               if (gsctx && (gsctx->var_is_vt || gsctx->mvar_is_vt)) {
+                       MonoMethodInflated *inflated;
+                       MonoGenericContext *context;
+                       MonoGenericInst *inst;
+
+                       g_assert (jinfo->method->is_inflated);
+                       inflated = (MonoMethodInflated*)jinfo->method;
+                       context = &inflated->context;
+
+                       encode_value (1, p, &p);
+                       if (context->class_inst) {
+                               inst = context->class_inst;
+
+                               encode_value (inst->type_argc, p, &p);
+                               for (i = 0; i < inst->type_argc; ++i)
+                                       encode_value (gsctx->var_is_vt [i], p, &p);
+                       } else {
+                               encode_value (0, p, &p);
+                       }
+                       if (context->method_inst) {
+                               inst = context->method_inst;
+
+                               encode_value (inst->type_argc, p, &p);
+                               for (i = 0; i < inst->type_argc; ++i)
+                                       encode_value (gsctx->mvar_is_vt [i], p, &p);
+                       } else {
+                               encode_value (0, p, &p);
+                       }
+               } else {
+                       encode_value (0, p, &p);
+               }
        }
 
        if (jinfo->has_try_block_holes) {
@@ -4748,12 +5150,14 @@ emit_plt (MonoAotCompile *acfg)
                        /* Emit only a thumb version */
                        continue;
 
-               if (!acfg->thumb_mixed)
+               if (acfg->llvm && !acfg->thumb_mixed)
                        emit_label (acfg, plt_entry->llvm_symbol);
 
                if (debug_sym) {
-                       if (acfg->need_no_dead_strip)
+                       if (acfg->need_no_dead_strip) {
+                               img_writer_emit_unset_mode (acfg->w);
                                fprintf (acfg->fp, "    .no_dead_strip %s\n", debug_sym);
+                       }
                        emit_local_symbol (acfg, debug_sym, NULL, TRUE);
                        emit_label (acfg, debug_sym);
                }
@@ -4798,7 +5202,7 @@ emit_plt (MonoAotCompile *acfg)
                        }
 
                        if (debug_sym) {
-#if defined(__APPLE__)
+#if defined(TARGET_MACH)
                                fprintf (acfg->fp, "    .thumb_func %s\n", debug_sym);
                                fprintf (acfg->fp, "    .no_dead_strip %s\n", debug_sym);
 #endif
@@ -4824,10 +5228,17 @@ emit_plt (MonoAotCompile *acfg)
        emit_label (acfg, symbol);
 }
 
+/*
+ * emit_trampoline_full:
+ *
+ *   If EMIT_TINFO is TRUE, emit additional information which can be used to create a MonoJitInfo for this trampoline by
+ * create_jit_info_for_trampoline ().
+ */
 static G_GNUC_UNUSED void
-emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
+emit_trampoline_full (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info, gboolean emit_tinfo)
 {
        char start_symbol [256];
+       char end_symbol [256];
        char symbol [256];
        guint32 buf_size, info_offset;
        MonoJumpInfo *patch_info;
@@ -4869,6 +5280,11 @@ emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
 
        emit_symbol_size (acfg, start_symbol, ".");
 
+       if (emit_tinfo) {
+               sprintf (end_symbol, "%snamede_%s", acfg->temp_prefix, name);
+               emit_label (acfg, end_symbol);
+       }
+
        /* Emit info */
 
        /* Sort relocations */
@@ -4895,6 +5311,22 @@ emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
 
        emit_int32 (acfg, info_offset);
 
+       if (emit_tinfo) {
+               guint8 *encoded;
+               guint32 encoded_len;
+               guint32 uw_offset;
+
+               /*
+                * Emit additional information which can be used to reconstruct a partial MonoTrampInfo.
+                */
+               encoded = mono_unwind_ops_encode (info->unwind_ops, &encoded_len);
+               uw_offset = get_unwind_info_offset (acfg, encoded, encoded_len);
+               g_free (encoded);
+
+               emit_symbol_diff (acfg, end_symbol, start_symbol, 0);
+               emit_int32 (acfg, uw_offset);
+       }
+
        /* Emit debug info */
        if (unwind_ops) {
                char symbol2 [256];
@@ -4907,6 +5339,12 @@ emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
        }
 }
 
+static G_GNUC_UNUSED void
+emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
+{
+       emit_trampoline_full (acfg, got_offset, info, FALSE);
+}
+
 static void
 emit_trampolines (MonoAotCompile *acfg)
 {
@@ -4936,7 +5374,8 @@ emit_trampolines (MonoAotCompile *acfg)
                 * method.
                 */
                for (tramp_type = 0; tramp_type < MONO_TRAMPOLINE_NUM; ++tramp_type) {
-                       mono_arch_create_generic_trampoline (tramp_type, &info, TRUE);
+                       /* we overload the boolean here to indicate the slightly different trampoline needed, see mono_arch_create_generic_trampoline() */
+                       mono_arch_create_generic_trampoline (tramp_type, &info, acfg->aot_opts.use_trampolines_page? 2: TRUE);
                        emit_trampoline (acfg, acfg->got_offset, info);
                }
 
@@ -4964,6 +5403,17 @@ emit_trampolines (MonoAotCompile *acfg)
                mono_arch_get_throw_corlib_exception (&info, TRUE);
                emit_trampoline (acfg, acfg->got_offset, info);
 
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+               mono_arch_get_gsharedvt_trampoline (&info, TRUE);
+               if (info) {
+                       emit_trampoline_full (acfg, acfg->got_offset, info, TRUE);
+
+                       /* Create a separate out trampoline for more information in stack traces */
+                       info->name = g_strdup ("gsharedvt_out_trampoline");
+                       emit_trampoline_full (acfg, acfg->got_offset, info, TRUE);
+               }
+#endif
+
 #if defined(MONO_ARCH_HAVE_GET_TRAMPOLINES)
                {
                        GSList *l = mono_arch_get_trampolines (TRUE);
@@ -5049,6 +5499,9 @@ emit_trampolines (MonoAotCompile *acfg)
                        case MONO_AOT_TRAMP_IMT_THUNK:
                                sprintf (symbol, "imt_thunks");
                                break;
+                       case MONO_AOT_TRAMP_GSHAREDVT_ARG:
+                               sprintf (symbol, "gsharedvt_arg_trampolines");
+                               break;
                        default:
                                g_assert_not_reached ();
                        }
@@ -5079,6 +5532,10 @@ emit_trampolines (MonoAotCompile *acfg)
                                        arch_emit_imt_thunk (acfg, tramp_got_offset, &tramp_size);
                                        tramp_got_offset += 1;
                                        break;
+                               case MONO_AOT_TRAMP_GSHAREDVT_ARG:
+                                       arch_emit_gsharedvt_arg_trampoline (acfg, tramp_got_offset, &tramp_size);                               
+                                       tramp_got_offset += 2;
+                                       break;
                                default:
                                        g_assert_not_reached ();
                                }
@@ -5096,6 +5553,8 @@ emit_trampolines (MonoAotCompile *acfg)
                        emit_label (acfg, end_symbol);
                }
 
+               arch_emit_specific_trampoline_pages (acfg);
+
                /* Reserve some entries at the end of the GOT for our use */
                acfg->num_trampoline_got_entries = tramp_got_offset - acfg->got_offset;
        }
@@ -5223,12 +5682,16 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->asm_writer = TRUE;
                } else if (str_begins_with (arg, "nodebug")) {
                        opts->nodebug = TRUE;
+               } else if (str_begins_with (arg, "nopagetrampolines")) {
+                       opts->use_trampolines_page = FALSE;
                } else if (str_begins_with (arg, "ntrampolines=")) {
                        opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
                } else if (str_begins_with (arg, "nrgctx-trampolines=")) {
                        opts->nrgctx_trampolines = atoi (arg + strlen ("nrgctx-trampolines="));
                } else if (str_begins_with (arg, "nimt-trampolines=")) {
                        opts->nimt_trampolines = atoi (arg + strlen ("nimt-trampolines="));
+               } else if (str_begins_with (arg, "ngsharedvt-trampolines=")) {
+                       opts->ngsharedvt_arg_trampolines = atoi (arg + strlen ("ngsharedvt-trampolines="));
                } else if (str_begins_with (arg, "autoreg")) {
                        opts->autoreg = TRUE;
                } else if (str_begins_with (arg, "tool-prefix=")) {
@@ -5239,10 +5702,18 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->direct_pinvoke = TRUE;
                } else if (str_begins_with (arg, "direct-icalls")) {
                        opts->direct_icalls = TRUE;
+#if defined(TARGET_ARM)
+               } else if (str_begins_with (arg, "iphone-abi")) {
+                       // older full-aot users did depend on this.
+#endif
+               } else if (str_begins_with (arg, "no-direct-calls")) {
+                       opts->no_direct_calls = TRUE;
                } else if (str_begins_with (arg, "print-skipped")) {
                        opts->print_skipped_methods = TRUE;
                } else if (str_begins_with (arg, "stats")) {
                        opts->stats = TRUE;
+               } else if (str_begins_with (arg, "no-instances")) {
+                       opts->no_instances = TRUE;
                } else if (str_begins_with (arg, "log-generics")) {
                        opts->log_generics = TRUE;
                } else if (str_begins_with (arg, "mtriple=")) {
@@ -5254,6 +5725,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                } else if (str_begins_with (arg, "info")) {
                        printf ("AOT target setup: %s.\n", AOT_TARGET_STR);
                        exit (0);
+               } else if (str_begins_with (arg, "gc-maps")) {
+                       mini_gc_enable_gc_maps_for_aot ();
                } else if (str_begins_with (arg, "help") || str_begins_with (arg, "?")) {
                        printf ("Supported options for --aot:\n");
                        printf ("    outfile=\n");
@@ -5271,11 +5744,14 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        printf ("    ntrampolines=\n");
                        printf ("    nrgctx-trampolines=\n");
                        printf ("    nimt-trampolines=\n");
+                       printf ("    ngsharedvt-trampolines=\n");
                        printf ("    autoreg\n");
                        printf ("    tool-prefix=\n");
                        printf ("    readonly-value=\n");
                        printf ("    soft-debug\n");
+                       printf ("    gc-maps\n");
                        printf ("    print-skipped\n");
+                       printf ("    no-instances\n");
                        printf ("    stats\n");
                        printf ("    info\n");
                        printf ("    help/?\n");
@@ -5286,6 +5762,11 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                }
        }
 
+       if (opts->use_trampolines_page) {
+               opts->ntrampolines = 0;
+               opts->nrgctx_trampolines = 0;
+               opts->nimt_trampolines = 0;
+       }
        g_strfreev (args);
 }
 
@@ -5315,13 +5796,8 @@ can_encode_class (MonoAotCompile *acfg, MonoClass *klass)
 }
 
 static gboolean
-can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
+can_encode_method (MonoAotCompile *acfg, MonoMethod *method)
 {
-       switch (patch_info->type) {
-       case MONO_PATCH_INFO_METHOD:
-       case MONO_PATCH_INFO_METHODCONST: {
-               MonoMethod *method = patch_info->data.method;
-
                if (method->wrapper_type) {
                        switch (method->wrapper_type) {
                        case MONO_WRAPPER_NONE:
@@ -5339,6 +5815,7 @@ can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
                        case MONO_WRAPPER_REMOTING_INVOKE:
                        case MONO_WRAPPER_UNKNOWN:
                        case MONO_WRAPPER_WRITE_BARRIER:
+                       case MONO_WRAPPER_DELEGATE_INVOKE:
                                break;
                        case MONO_WRAPPER_MANAGED_TO_MANAGED:
                        case MONO_WRAPPER_CASTCLASS: {
@@ -5364,7 +5841,18 @@ can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
                                }
                        }
                }
-               break;
+               return TRUE;
+}
+
+static gboolean
+can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
+{
+       switch (patch_info->type) {
+       case MONO_PATCH_INFO_METHOD:
+       case MONO_PATCH_INFO_METHODCONST: {
+               MonoMethod *method = patch_info->data.method;
+
+               return can_encode_method (acfg, method);
        }
        case MONO_PATCH_INFO_VTABLE:
        case MONO_PATCH_INFO_CLASS_INIT:
@@ -5380,6 +5868,8 @@ can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
        case MONO_PATCH_INFO_RGCTX_FETCH: {
                MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
 
+               if (!can_encode_method (acfg, entry->method))
+                       return FALSE;
                if (!can_encode_patch (acfg, entry->data))
                        return FALSE;
                break;
@@ -5451,7 +5941,8 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
         */
        cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), FALSE, TRUE, 0);
        if (cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
-               //printf ("F: %s\n", mono_method_full_name (method, TRUE));
+               if (acfg->aot_opts.print_skipped_methods)
+                       printf ("Skip (gshared failure): %s (%s)\n", mono_method_full_name (method, TRUE), cfg->exception_message);
                InterlockedIncrement (&acfg->stats.genericcount);
                return;
        }
@@ -5537,14 +6028,14 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
         * encountered.
         */
        depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method));
-       if (depth < 32) {
+       if (!acfg->aot_opts.no_instances && depth < 32) {
                for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                        switch (patch_info->type) {
                        case MONO_PATCH_INFO_METHOD: {
                                MonoMethod *m = patch_info->data.method;
                                if (m->is_inflated) {
                                        if (!(mono_class_generic_sharing_enabled (m->klass) &&
-                                                 mono_method_is_generic_sharable_impl (m, FALSE)) &&
+                                                 mono_method_is_generic_sharable_impl_full (m, FALSE, FALSE, FALSE)) &&
                                                !method_has_type_vars (m)) {
                                                if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
                                                        if (acfg->aot_opts.full_aot)
@@ -5832,7 +6323,7 @@ mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
        plt_entry = get_plt_entry (llvm_acfg, ji);
        plt_entry->llvm_used = TRUE;
 
-#if defined(__APPLE__)
+#if defined(TARGET_MACH)
        return g_strdup_printf (plt_entry->llvm_symbol + strlen (llvm_acfg->llvm_label_prefix));
 #else
        return g_strdup_printf (plt_entry->llvm_symbol);
@@ -5862,7 +6353,7 @@ mono_aot_patch_info_dup (MonoJumpInfo* ji)
 static void
 emit_llvm_file (MonoAotCompile *acfg)
 {
-       char *command, *opts;
+       char *command, *opts, *tempbc;
        int i;
        MonoJumpInfo *patch_info;
 
@@ -5896,7 +6387,7 @@ emit_llvm_file (MonoAotCompile *acfg)
                 */
                if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
                        /* For the generic + rgctx trampolines */
-                       acfg->final_got_size += 200;
+                       acfg->final_got_size += 400;
                        /* For the specific trampolines */
                        for (ntype = 0; ntype < MONO_AOT_TRAMP_NUM; ++ntype)
                                acfg->final_got_size += acfg->num_trampolines [ntype] * 2;
@@ -5904,7 +6395,9 @@ emit_llvm_file (MonoAotCompile *acfg)
        }
 
 
-       mono_llvm_emit_aot_module ("temp.bc", acfg->final_got_size);
+       tempbc = g_strdup_printf ("%s.bc", acfg->tmpfname);
+       mono_llvm_emit_aot_module (tempbc, acfg->final_got_size);
+       g_free (tempbc);
 
        /*
         * FIXME: Experiment with adding optimizations, the -std-compile-opts set takes
@@ -5923,7 +6416,7 @@ emit_llvm_file (MonoAotCompile *acfg)
        opts = g_strdup ("-instcombine -simplifycfg");
        opts = g_strdup ("-simplifycfg -domtree -domfrontier -scalarrepl -instcombine -simplifycfg -domtree -domfrontier -scalarrepl -simplify-libcalls -instcombine -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loop-simplify -domfrontier -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -iv-users -indvars -loop-deletion -loop-simplify -lcssa -loop-unroll -instcombine -memdep -gvn -memdep -memcpyopt -sccp -instcombine -domtree -memdep -dse -adce -simplifycfg -preverify -domtree -verify");
 #if 1
-       command = g_strdup_printf ("%sopt -f %s -o temp.opt.bc temp.bc", acfg->aot_opts.llvm_path, opts);
+       command = g_strdup_printf ("%sopt -f %s -o %s.opt.bc %s.bc", acfg->aot_opts.llvm_path, opts, acfg->tmpfname, acfg->tmpfname);
        printf ("Executing opt: %s\n", command);
        if (system (command) != 0) {
                exit (1);
@@ -5946,7 +6439,7 @@ emit_llvm_file (MonoAotCompile *acfg)
                g_string_append_printf (acfg->llc_args, " -relocation-model=pic");
        unlink (acfg->tmpfname);
 
-       command = g_strdup_printf ("%sllc %s -disable-gnu-eh-frame -enable-mono-eh-frame -o %s temp.opt.bc", acfg->aot_opts.llvm_path, acfg->llc_args->str, acfg->tmpfname);
+       command = g_strdup_printf ("%sllc %s -disable-gnu-eh-frame -enable-mono-eh-frame -o %s %s.opt.bc", acfg->aot_opts.llvm_path, acfg->llc_args->str, acfg->tmpfname, acfg->tmpfname);
 
        printf ("Executing llc: %s\n", command);
 
@@ -6022,7 +6515,7 @@ emit_code (MonoAotCompile *acfg)
                method = cfg->orig_method;
 
                /* Emit unbox trampoline */
-               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
                        sprintf (symbol, "ut_%d", get_method_index (acfg, method));
 
                        emit_section_change (acfg, ".text", 0);
@@ -6064,6 +6557,46 @@ emit_code (MonoAotCompile *acfg)
                }
        }
 
+#ifdef MONOTOUCH
+       if (acfg->direct_method_addresses) {
+               acfg->flags |= MONO_AOT_FILE_FLAG_DIRECT_METHOD_ADDRESSES;
+
+               sprintf (symbol, "method_addresses");
+               emit_section_change (acfg, RODATA_SECT, 1);
+               emit_alignment (acfg, 8);
+               emit_label (acfg, symbol);
+
+               for (i = 0; i < acfg->nmethods; ++i) {
+                       if (acfg->cfgs [i]) {
+                               emit_pointer (acfg, acfg->cfgs [i]->asm_symbol);
+                       } else {
+                               emit_pointer (acfg, NULL);
+                       }
+               }
+
+               /* Empty */
+               sprintf (symbol, "code_offsets");
+               emit_section_change (acfg, RODATA_SECT, 1);
+               emit_alignment (acfg, 8);
+               emit_label (acfg, symbol);
+       } else {
+               sprintf (symbol, "code_offsets");
+               emit_section_change (acfg, RODATA_SECT, 1);
+               emit_alignment (acfg, 8);
+               emit_label (acfg, symbol);
+
+               acfg->stats.offsets_size += acfg->nmethods * 4;
+
+               sprintf (end_symbol, "methods");
+               for (i = 0; i < acfg->nmethods; ++i) {
+                       if (acfg->cfgs [i]) {
+                               emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, end_symbol, 0);
+                       } else {
+                               emit_int32 (acfg, 0xffffffff);
+                       }
+               }
+       }
+#else
        sprintf (symbol, "code_offsets");
        emit_section_change (acfg, RODATA_SECT, 1);
        emit_alignment (acfg, 8);
@@ -6079,6 +6612,7 @@ emit_code (MonoAotCompile *acfg)
                        emit_int32 (acfg, 0xffffffff);
                }
        }
+#endif
        emit_line (acfg);
 
        /* Emit a sorted table mapping methods to their unbox trampolines */
@@ -6100,12 +6634,15 @@ emit_code (MonoAotCompile *acfg)
 
                method = cfg->orig_method;
 
-               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
                        index = get_method_index (acfg, method);
                        sprintf (symbol, "ut_%d", index);
 
                        emit_int32 (acfg, index);
-                       emit_symbol_diff (acfg, symbol, end_symbol, 0);
+                       if (acfg->direct_method_addresses)
+                               emit_pointer (acfg, symbol);
+                       else
+                               emit_symbol_diff (acfg, symbol, end_symbol, 0);
                        /* Make sure the table is sorted by index */
                        g_assert (index > prev_index);
                        prev_index = index;
@@ -6861,7 +7398,7 @@ emit_globals (MonoAotCompile *acfg)
 
                sprintf (symbol, "name_%d", i);
                emit_section_change (acfg, RODATA_SECT, 1);
-#ifdef __APPLE__
+#ifdef TARGET_MACH
                emit_alignment (acfg, 4);
 #endif
                emit_label (acfg, symbol);
@@ -6987,6 +7524,9 @@ emit_file_info (MonoAotCompile *acfg)
        emit_pointer (acfg, "method_info_offsets");
        emit_pointer (acfg, "ex_info_offsets");
        emit_pointer (acfg, "code_offsets");
+#ifdef MONOTOUCH
+       emit_pointer (acfg, "method_addresses");
+#endif
        emit_pointer (acfg, "extra_method_info_offsets");
        emit_pointer (acfg, "extra_method_table");
        emit_pointer (acfg, "got_info_offsets");
@@ -7002,10 +7542,12 @@ emit_file_info (MonoAotCompile *acfg)
                emit_pointer (acfg, "specific_trampolines");
                emit_pointer (acfg, "static_rgctx_trampolines");
                emit_pointer (acfg, "imt_thunks");
+               emit_pointer (acfg, "gsharedvt_arg_trampolines");
        } else {
                emit_pointer (acfg, NULL);
                emit_pointer (acfg, NULL);
                emit_pointer (acfg, NULL);
+               emit_pointer (acfg, NULL);
        }
        if (acfg->thumb_mixed) {
                emit_pointer (acfg, "thumb_end");
@@ -7037,21 +7579,23 @@ emit_file_info (MonoAotCompile *acfg)
        for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
                emit_int32 (acfg, acfg->trampoline_size [i]);
 
-#if defined (TARGET_ARM) && defined (__APPLE__)
-       {
-               MonoType t;
-               int align = 0;
+#if defined (TARGET_ARM) && defined (TARGET_MACH)
+       {
+               MonoType t;
+               int align = 0;
 
-               t.type = MONO_TYPE_R8;
-               mono_type_size (&t, &align);
+               memset (&t, 0, sizeof (MonoType));
+               t.type = MONO_TYPE_R8;
+               mono_type_size (&t, &align);
 
-               emit_int32 (acfg, align);
+               emit_int32 (acfg, align);
 
-               t.type = MONO_TYPE_I8;
-               mono_type_size (&t, &align);
+               memset (&t, 0, sizeof (MonoType));
+               t.type = MONO_TYPE_I8;
+               mono_type_size (&t, &align);
 
-               emit_int32 (acfg, align);
-       }
+               emit_int32 (acfg, align);
+       }
 #else
        emit_int32 (acfg, __alignof__ (double));
        emit_int32 (acfg, __alignof__ (gint64));
@@ -7065,7 +7609,7 @@ emit_file_info (MonoAotCompile *acfg)
                 * mono_aot_register_module (). The symbol points to a pointer to the the file info
                 * structure.
                 */
-#if defined(__APPLE__) && !defined(__native_client_codegen__)
+#if defined(TARGET_MACH) && !defined(__native_client_codegen__)
                sprintf (symbol, "_mono_aot_module_%s_info", acfg->image->assembly->aname.name);
 #else
                sprintf (symbol, "mono_aot_module_%s_info", acfg->image->assembly->aname.name);
@@ -7102,7 +7646,7 @@ emit_dwarf_info (MonoAotCompile *acfg)
 {
 #ifdef EMIT_DWARF_INFO
        int i;
-       char symbol [128], symbol2 [128];
+       char symbol2 [128];
 
        /* DIEs for methods */
        for (i = 0; i < acfg->nmethods; ++i) {
@@ -7115,10 +7659,9 @@ emit_dwarf_info (MonoAotCompile *acfg)
                if (cfg->compile_llvm)
                        continue;
 
-               sprintf (symbol, "%s", cfg->asm_symbol);
                sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
 
-               mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, symbol, symbol2, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ()));
+               mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, cfg->asm_symbol, symbol2, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ()));
        }
 #endif
 }
@@ -7126,7 +7669,7 @@ emit_dwarf_info (MonoAotCompile *acfg)
 static void
 collect_methods (MonoAotCompile *acfg)
 {
-       int i;
+       int mindex, i;
        MonoImage *image = acfg->image;
 
        /* Collect methods */
@@ -7171,6 +7714,30 @@ collect_methods (MonoAotCompile *acfg)
                acfg->method_index ++;
        }
 
+       /* gsharedvt methods */
+       for (mindex = 0; mindex < image->tables [MONO_TABLE_METHOD].rows; ++mindex) {
+               MonoMethod *method;
+               guint32 token = MONO_TOKEN_METHOD_DEF | (mindex + 1);
+
+               if (!(acfg->opts & MONO_OPT_GSHAREDVT))
+                       continue;
+
+               method = mono_get_method (acfg->image, token, NULL);
+               if (!method)
+                       continue;
+               if (method->is_generic || method->klass->generic_container) {
+                       /* Create a vtype instantiation */
+                       MonoGenericContext ctx;
+                       MonoMethod *inflated, *gshared;
+
+                       create_gsharedvt_inst (acfg, method, &ctx);
+
+                       inflated = mono_class_inflate_generic_method (method, &ctx);
+                       gshared = mini_get_shared_method_full (inflated, FALSE, TRUE);
+                       add_extra_method (acfg, gshared);
+               }
+       }
+
        add_generic_instances (acfg);
 
        if (acfg->aot_opts.full_aot)
@@ -7252,7 +7819,7 @@ compile_asm (MonoAotCompile *acfg)
 #define LD_OPTIONS "-m elf64ppc"
 #elif defined(sparc) && SIZEOF_VOID_P == 8
 #define AS_OPTIONS "-xarch=v9"
-#elif defined(TARGET_X86) && defined(__APPLE__) && !defined(__native_client_codegen__)
+#elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
 #define AS_OPTIONS "-arch i386 -W"
 #else
 #define AS_OPTIONS ""
@@ -7315,11 +7882,11 @@ compile_asm (MonoAotCompile *acfg)
 
 #if defined(sparc)
        command = g_strdup_printf ("ld -shared -G -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
-#elif defined(__ppc__) && defined(__APPLE__)
+#elif defined(__ppc__) && defined(TARGET_MACH)
        command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
 #elif defined(HOST_WIN32)
        command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
-#elif defined(TARGET_X86) && defined(__APPLE__) && !defined(__native_client_codegen__)
+#elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
        command = g_strdup_printf ("gcc -m32 -dynamiclib -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
 #else
        command = g_strdup_printf ("%sld %s %s -shared -o %s %s.o", tool_prefix, EH_LD_OPTIONS, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
@@ -7334,13 +7901,13 @@ compile_asm (MonoAotCompile *acfg)
        }
 
        g_free (command);
-       unlink (objfile);
+
        /*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, SHARED_EXT);
        printf ("Stripping the binary: %s\n", com);
        system (com);
        g_free (com);*/
 
-#if defined(TARGET_ARM) && !defined(__APPLE__)
+#if defined(TARGET_ARM) && !defined(TARGET_MACH)
        /* 
         * 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.
@@ -7358,6 +7925,17 @@ compile_asm (MonoAotCompile *acfg)
 
        rename (tmp_outfile_name, outfile_name);
 
+#if defined(TARGET_MACH)
+       command = g_strdup_printf ("dsymutil %s", outfile_name);
+       printf ("Generating debug symbols: %s\n", command);
+       if (system (command) != 0) {
+               return 1;
+       }
+#endif
+
+       if (!acfg->aot_opts.save_temps)
+               unlink (objfile);
+
        g_free (tmp_outfile_name);
        g_free (outfile_name);
        g_free (objfile);
@@ -7472,7 +8050,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->aot_opts.ntrampolines = 1024;
        acfg->aot_opts.nrgctx_trampolines = 1024;
        acfg->aot_opts.nimt_trampolines = 128;
+       acfg->aot_opts.ngsharedvt_arg_trampolines = 128;
        acfg->aot_opts.llvm_path = g_strdup ("");
+#if MONOTOUCH
+       acfg->aot_opts.use_trampolines_page = TRUE;
+#endif
 
        mono_aot_parse_options (aot_options, &acfg->aot_opts);
 
@@ -7530,6 +8112,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        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 ? acfg->aot_opts.nimt_trampolines : 0;
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+       if (acfg->opts & MONO_OPT_GSHAREDVT)
+               acfg->num_trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = acfg->aot_opts.full_aot ? acfg->aot_opts.ngsharedvt_arg_trampolines : 0;
+#endif
 
        acfg->temp_prefix = img_writer_get_temp_label_prefix (NULL);
 
@@ -7673,6 +8259,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
                        if (COMPILE_LLVM (cfg))
                                cfg->asm_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, cfg->llvm_method_name);
+                       else if (acfg->global_symbols)
+                               cfg->asm_symbol = get_debug_sym (cfg->method, "", acfg->method_label_hash);
                        else
                                cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, acfg->llvm_label_prefix, method_index);
                }
@@ -7694,6 +8282,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                 */
                sprintf (symbol, "thumb_end");
                emit_section_change (acfg, ".text", 0);
+               emit_alignment (acfg, 8);
                emit_label (acfg, symbol);
                emit_zero_bytes (acfg, 16);
 
@@ -7754,6 +8343,20 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                g_assert (acfg->got_offset <= acfg->final_got_size);
 
        printf ("Code: %d Info: %d Ex Info: %d Unwind Info: %d Class Info: %d PLT: %d GOT Info: %d GOT: %d Offsets: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.unwind_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, (int)(acfg->got_offset * sizeof (gpointer)), acfg->stats.offsets_size);
+       printf ("Compiled: %d/%d (%d%%), No GOT slots: %d (%d%%), Direct calls: %d (%d%%)\n", 
+                       acfg->stats.ccount, acfg->stats.mcount, acfg->stats.mcount ? (acfg->stats.ccount * 100) / acfg->stats.mcount : 100,
+                       acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100,
+                       acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100);
+       if (acfg->stats.genericcount)
+               printf ("%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
+       if (acfg->stats.abscount)
+               printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
+       if (acfg->stats.lmfcount)
+               printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
+       if (acfg->stats.ocount)
+               printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
+       if (acfg->llvm)
+               printf ("Methods compiled with LLVM: %d (%d%%)\n", acfg->stats.llvm_count, acfg->stats.mcount ? (acfg->stats.llvm_count * 100) / acfg->stats.mcount : 100);
 
        TV_GETTIME (atv);
        res = img_writer_emit_writeout (acfg->w);
@@ -7778,20 +8381,6 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        TV_GETTIME (btv);
        acfg->stats.link_time = TV_ELAPSED (atv, btv);
 
-       printf ("Compiled %d out of %d methods (%d%%)\n", acfg->stats.ccount, acfg->stats.mcount, acfg->stats.mcount ? (acfg->stats.ccount * 100) / acfg->stats.mcount : 100);
-       if (acfg->stats.genericcount)
-               printf ("%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
-       if (acfg->stats.abscount)
-               printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
-       if (acfg->stats.lmfcount)
-               printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
-       if (acfg->stats.ocount)
-               printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
-       if (acfg->llvm)
-               printf ("Methods compiled with LLVM: %d (%d%%)\n", acfg->stats.llvm_count, acfg->stats.mcount ? (acfg->stats.llvm_count * 100) / acfg->stats.mcount : 100);
-       printf ("Methods without GOT slots: %d (%d%%)\n", acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100);
-       printf ("Direct calls: %d (%d%%)\n", acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100);
-
        if (acfg->aot_opts.stats) {
                int i;