Merge pull request #2820 from kumpera/license-change-rebased
[mono.git] / mono / mini / aot-compiler.c
index 48354b70578e4718dfc13425014d86b3caaa45f4..dd2780edac9e524123b6483fca0e54cb4e5ff95b 100644 (file)
@@ -8,6 +8,7 @@
  * (C) 2002 Ximian, Inc.
  * Copyright 2003-2011 Novell, Inc 
  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include "config.h"
@@ -40,6 +41,7 @@
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/metadata-internals.h>
+#include <mono/metadata/reflection-internals.h>
 #include <mono/metadata/marshal.h>
 #include <mono/metadata/gc-internals.h>
 #include <mono/metadata/mempool-internals.h>
@@ -152,8 +154,8 @@ typedef struct MonoAotStats {
        int methods_without_got_slots, direct_calls, all_calls, llvm_count;
        int got_slots, offsets_size;
        int method_categories [METHOD_CAT_NUM];
-       int got_slot_types [MONO_PATCH_INFO_NONE];
-       int got_slot_info_sizes [MONO_PATCH_INFO_NONE];
+       int got_slot_types [MONO_PATCH_INFO_NUM];
+       int got_slot_info_sizes [MONO_PATCH_INFO_NUM];
        int jit_time, gen_time, link_time;
 } MonoAotStats;
 
@@ -856,7 +858,331 @@ arch_init (MonoAotCompile *acfg)
 
 #ifdef TARGET_ARM64
 
-#include "../../../mono-extensions/mono/mini/aot-compiler-arm64.c"
+
+/* Load the contents of GOT_SLOT into dreg, clobbering ip0 */
+static void
+arm64_emit_load_got_slot (MonoAotCompile *acfg, int dreg, int got_slot)
+{
+       int offset;
+
+       g_assert (acfg->fp);
+       emit_unset_mode (acfg);
+       /* r16==ip0 */
+       offset = (int)(got_slot * sizeof (gpointer));
+#ifdef TARGET_MACH
+       /* clang's integrated assembler */
+       fprintf (acfg->fp, "adrp x16, %s@PAGE+%d\n", acfg->got_symbol, offset & 0xfffff000);
+       fprintf (acfg->fp, "add x16, x16, %s@PAGEOFF\n", acfg->got_symbol);
+       fprintf (acfg->fp, "ldr x%d, [x16, #%d]\n", dreg, offset & 0xfff);
+#else
+       /* Linux GAS */
+       fprintf (acfg->fp, "adrp x16, %s+%d\n", acfg->got_symbol, offset & 0xfffff000);
+       fprintf (acfg->fp, "add x16, x16, :lo12:%s\n", acfg->got_symbol);
+       fprintf (acfg->fp, "ldr x%d, [x16, %d]\n", dreg, offset & 0xfff);
+#endif
+}
+
+static void
+arm64_emit_objc_selector_ref (MonoAotCompile *acfg, guint8 *code, int index, int *code_size)
+{
+       int reg;
+
+       g_assert (acfg->fp);
+       emit_unset_mode (acfg);
+
+       /* ldr rt, target */
+       reg = arm_get_ldr_lit_reg (code);
+
+       fprintf (acfg->fp, "adrp x%d, L_OBJC_SELECTOR_REFERENCES_%d@PAGE\n", reg, index);
+       fprintf (acfg->fp, "add x%d, x%d, L_OBJC_SELECTOR_REFERENCES_%d@PAGEOFF\n", reg, reg, index);
+       fprintf (acfg->fp, "ldr x%d, [x%d]\n", reg, reg);
+
+       *code_size = 12;
+}
+
+static void
+arm64_emit_direct_call (MonoAotCompile *acfg, const char *target, gboolean external, gboolean thumb, MonoJumpInfo *ji, int *call_size)
+{
+       g_assert (acfg->fp);
+       emit_unset_mode (acfg);
+       if (ji && ji->relocation == MONO_R_ARM64_B) {
+               fprintf (acfg->fp, "b %s\n", target);
+       } else {
+               if (ji)
+                       g_assert (ji->relocation == MONO_R_ARM64_BL);
+               fprintf (acfg->fp, "bl %s\n", target);
+       }
+       *call_size = 4;
+}
+
+static void
+arm64_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *code_size)
+{
+       int reg;
+
+       /* ldr rt, target */
+       reg = arm_get_ldr_lit_reg (code);
+       arm64_emit_load_got_slot (acfg, reg, got_slot);
+       *code_size = 12;
+}
+
+static void
+arm64_emit_plt_entry (MonoAotCompile *acfg, const char *got_symbol, int offset, int info_offset)
+{
+       arm64_emit_load_got_slot (acfg, ARMREG_R16, offset / sizeof (gpointer));
+       fprintf (acfg->fp, "br x16\n");
+       /* Used by mono_aot_get_plt_info_offset () */
+       fprintf (acfg->fp, "%s %d\n", acfg->inst_directive, info_offset);
+}
+
+static void
+arm64_emit_tramp_page_common_code (MonoAotCompile *acfg, int pagesize, int arg_reg, int *size)
+{
+       guint8 buf [256];
+       guint8 *code;
+       int imm;
+
+       /* The common code */
+       code = buf;
+       imm = pagesize;
+       /* The trampoline address is in IP0 */
+       arm_movzx (code, ARMREG_IP1, imm & 0xffff, 0);
+       arm_movkx (code, ARMREG_IP1, (imm >> 16) & 0xffff, 16);
+       /* Compute the data slot address */
+       arm_subx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
+       /* Trampoline argument */
+       arm_ldrx (code, arg_reg, ARMREG_IP0, 0);
+       /* Address */
+       arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 8);
+       arm_brx (code, ARMREG_IP0);
+
+       /* Emit it */
+       emit_code_bytes (acfg, buf, code - buf);
+
+       *size = code - buf;
+}
+
+static void
+arm64_emit_tramp_page_specific_code (MonoAotCompile *acfg, int pagesize, int common_tramp_size, int specific_tramp_size)
+{
+       guint8 buf [256];
+       guint8 *code;
+       int i, count;
+
+       count = (pagesize - common_tramp_size) / specific_tramp_size;
+       for (i = 0; i < count; ++i) {
+               code = buf;
+               arm_adrx (code, ARMREG_IP0, code);
+               /* Branch to the generic code */
+               arm_b (code, code - 4 - (i * specific_tramp_size) - common_tramp_size);
+               /* This has to be 2 pointers long */
+               arm_nop (code);
+               arm_nop (code);
+               g_assert (code - buf == specific_tramp_size);
+               emit_code_bytes (acfg, buf, code - buf);
+       }
+}
+
+static void
+arm64_emit_specific_trampoline_pages (MonoAotCompile *acfg)
+{
+       guint8 buf [128];
+       guint8 *code;
+       guint8 *labels [16];
+       int common_tramp_size;
+       int specific_tramp_size = 2 * 8;
+       int imm, pagesize;
+       char symbol [128];
+
+       if (!acfg->aot_opts.use_trampolines_page)
+               return;
+
+#ifdef TARGET_MACH
+       /* Have to match the target pagesize */
+       pagesize = 16384;
+#else
+       pagesize = mono_pagesize ();
+#endif
+       acfg->tramp_page_size = pagesize;
+
+       /* The specific trampolines */
+       sprintf (symbol, "%sspecific_trampolines_page", acfg->user_symbol_prefix);
+       emit_alignment (acfg, pagesize);
+       emit_global (acfg, symbol, TRUE);
+       emit_label (acfg, symbol);
+
+       /* The common code */
+       arm64_emit_tramp_page_common_code (acfg, pagesize, ARMREG_IP1, &common_tramp_size);
+       acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_SPECIFIC] = common_tramp_size;
+
+       arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
+
+       /* The rgctx trampolines */
+       /* These are the same as the specific trampolines, but they load the argument into MONO_ARCH_RGCTX_REG */
+       sprintf (symbol, "%srgctx_trampolines_page", acfg->user_symbol_prefix);
+       emit_alignment (acfg, pagesize);
+       emit_global (acfg, symbol, TRUE);
+       emit_label (acfg, symbol);
+
+       /* The common code */
+       arm64_emit_tramp_page_common_code (acfg, pagesize, MONO_ARCH_RGCTX_REG, &common_tramp_size);
+       acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_STATIC_RGCTX] = common_tramp_size;
+
+       arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
+
+       /* The gsharedvt arg trampolines */
+       /* These are the same as the specific trampolines */
+       sprintf (symbol, "%sgsharedvt_arg_trampolines_page", acfg->user_symbol_prefix);
+       emit_alignment (acfg, pagesize);
+       emit_global (acfg, symbol, TRUE);
+       emit_label (acfg, symbol);
+
+       arm64_emit_tramp_page_common_code (acfg, pagesize, ARMREG_IP1, &common_tramp_size);
+       acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_GSHAREDVT_ARG] = common_tramp_size;
+
+       arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
+
+       /* The IMT trampolines */
+       sprintf (symbol, "%simt_trampolines_page", acfg->user_symbol_prefix);
+       emit_alignment (acfg, pagesize);
+       emit_global (acfg, symbol, TRUE);
+       emit_label (acfg, symbol);
+
+       code = buf;
+       imm = pagesize;
+       /* The trampoline address is in IP0 */
+       arm_movzx (code, ARMREG_IP1, imm & 0xffff, 0);
+       arm_movkx (code, ARMREG_IP1, (imm >> 16) & 0xffff, 16);
+       /* Compute the data slot address */
+       arm_subx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
+       /* Trampoline argument */
+       arm_ldrx (code, ARMREG_IP1, ARMREG_IP0, 0);
+
+       /* Same as arch_emit_imt_thunk () */
+       labels [0] = code;
+       arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 0);
+       arm_cmpx (code, ARMREG_IP0, MONO_ARCH_RGCTX_REG);
+       labels [1] = code;
+       arm_bcc (code, ARMCOND_EQ, 0);
+
+       /* End-of-loop check */
+       labels [2] = code;
+       arm_cbzx (code, ARMREG_IP0, 0);
+
+       /* Loop footer */
+       arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 2 * 8);
+       arm_b (code, labels [0]);
+
+       /* Match */
+       mono_arm_patch (labels [1], code, MONO_R_ARM64_BCC);
+       /* Load vtable slot addr */
+       arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
+       /* Load vtable slot */
+       arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0);
+       arm_brx (code, ARMREG_IP0);
+
+       /* No match */
+       mono_arm_patch (labels [2], code, MONO_R_ARM64_CBZ);
+       /* Load fail addr */
+       arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
+       arm_brx (code, ARMREG_IP0);
+
+       emit_code_bytes (acfg, buf, code - buf);
+
+       common_tramp_size = code - buf;
+       acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_IMT_THUNK] = common_tramp_size;
+
+       arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
+}
+
+static void
+arm64_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+       /* Load argument from second GOT slot */
+       arm64_emit_load_got_slot (acfg, ARMREG_R17, offset + 1);
+       /* Load generic trampoline address from first GOT slot */
+       arm64_emit_load_got_slot (acfg, ARMREG_R16, offset);
+       fprintf (acfg->fp, "br x16\n");
+       *tramp_size = 7 * 4;
+}
+
+static void
+arm64_emit_unbox_trampoline (MonoAotCompile *acfg, MonoCompile *cfg, MonoMethod *method, const char *call_target)
+{
+       emit_unset_mode (acfg);
+       fprintf (acfg->fp, "add x0, x0, %d\n", (int)(sizeof (MonoObject)));
+       fprintf (acfg->fp, "b %s\n", call_target);
+}
+
+static void
+arm64_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+       /* Similar to the specific trampolines, but use the rgctx reg instead of ip1 */
+
+       /* Load argument from first GOT slot */
+       g_assert (MONO_ARCH_RGCTX_REG == 27);
+       arm64_emit_load_got_slot (acfg, ARMREG_R27, offset);
+       /* Load generic trampoline address from second GOT slot */
+       arm64_emit_load_got_slot (acfg, ARMREG_R16, offset + 1);
+       fprintf (acfg->fp, "br x16\n");
+       *tramp_size = 7 * 4;
+}
+
+static void
+arm64_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+       guint8 buf [128];
+       guint8 *code, *labels [16];
+
+       /* Load parameter from GOT slot into ip1 */
+       arm64_emit_load_got_slot (acfg, ARMREG_R17, offset);
+
+       code = buf;
+       labels [0] = code;
+       arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 0);
+       arm_cmpx (code, ARMREG_IP0, MONO_ARCH_RGCTX_REG);
+       labels [1] = code;
+       arm_bcc (code, ARMCOND_EQ, 0);
+
+       /* End-of-loop check */
+       labels [2] = code;
+       arm_cbzx (code, ARMREG_IP0, 0);
+
+       /* Loop footer */
+       arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 2 * 8);
+       arm_b (code, labels [0]);
+
+       /* Match */
+       mono_arm_patch (labels [1], code, MONO_R_ARM64_BCC);
+       /* Load vtable slot addr */
+       arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
+       /* Load vtable slot */
+       arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0);
+       arm_brx (code, ARMREG_IP0);
+
+       /* No match */
+       mono_arm_patch (labels [2], code, MONO_R_ARM64_CBZ);
+       /* Load fail addr */
+       arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
+       arm_brx (code, ARMREG_IP0);
+
+       emit_code_bytes (acfg, buf, code - buf);
+
+       *tramp_size = code - buf + (3 * 4);
+}
+
+static void
+arm64_emit_gsharedvt_arg_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+       /* Similar to the specific trampolines, but the address is in the second slot */
+       /* Load argument from first GOT slot */
+       arm64_emit_load_got_slot (acfg, ARMREG_R17, offset);
+       /* Load generic trampoline address from second GOT slot */
+       arm64_emit_load_got_slot (acfg, ARMREG_R16, offset + 1);
+       fprintf (acfg->fp, "br x16\n");
+       *tramp_size = 7 * 4;
+}
+
 
 #endif
 
@@ -3121,7 +3447,7 @@ is_plt_patch (MonoJumpInfo *patch_info)
        case MONO_PATCH_INFO_METHOD:
        case MONO_PATCH_INFO_INTERNAL_METHOD:
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
-       case MONO_PATCH_INFO_ICALL_ADDR:
+       case MONO_PATCH_INFO_ICALL_ADDR_CALL:
        case MONO_PATCH_INFO_RGCTX_FETCH:
                return TRUE;
        default:
@@ -3609,7 +3935,7 @@ add_wrappers (MonoAotCompile *acfg)
                /* Assembly runtime-invoke (string, bool) [DoAssemblyResolve] */
                csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
                csig->hasthis = 1;
-               csig->ret = &(mono_class_from_name (
+               csig->ret = &(mono_class_load_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;
@@ -3745,7 +4071,11 @@ add_wrappers (MonoAotCompile *acfg)
                        if (method)
                                add_method (acfg, mono_marshal_get_delegate_end_invoke (method));
 
-                       cattr = mono_custom_attrs_from_class (klass);
+                       cattr = mono_custom_attrs_from_class_checked (klass, &error);
+                       if (!is_ok (&error)) {
+                               mono_error_cleanup (&error);
+                               continue;
+                       }
 
                        if (cattr) {
                                int j;
@@ -3910,7 +4240,12 @@ add_wrappers (MonoAotCompile *acfg)
                 * attribute named MonoPInvokeCallbackAttribute. We search for the attribute by
                 * name to avoid defining a new assembly to contain it.
                 */
-               cattr = mono_custom_attrs_from_method (method);
+               cattr = mono_custom_attrs_from_method_checked (method, &error);
+               if (!is_ok (&error)) {
+                       char *name = mono_method_get_full_name (method);
+                       report_loader_error (acfg, &error, "Failed to load custom attributes from method %s due to %s\n", name, mono_error_get_message (&error));
+                       g_free (name);
+               }
 
                if (cattr) {
                        for (j = 0; j < cattr->num_attrs; ++j)
@@ -3950,8 +4285,9 @@ add_wrappers (MonoAotCompile *acfg)
                                slen = mono_metadata_decode_value (p, &p);
                                n = (char *)g_memdup (p, slen + 1);
                                n [slen] = 0;
-                               t = mono_reflection_type_from_name (n, acfg->image);
+                               t = mono_reflection_type_from_name_checked (n, acfg->image, &error);
                                g_assert (t);
+                               mono_error_assert_ok (&error);
                                g_free (n);
 
                                klass = mono_class_from_mono_type (t);
@@ -4156,7 +4492,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
        if (!klass->generic_class && !klass->rank)
                return;
 
-       if (klass->exception_type)
+       if (mono_class_has_failure (klass))
                return;
 
        if (!acfg->ginst_hash)
@@ -4246,6 +4582,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
 
                /* Add the T[]/InternalEnumerator class */
                if (!strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IEnumerator`1")) {
+                       MonoError error;
                        MonoClass *nclass;
 
                        iter = NULL;
@@ -4254,7 +4591,8 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
                                        break;
                        }
                        g_assert (nclass);
-                       nclass = mono_class_inflate_generic_class (nclass, mono_generic_class_get_context (klass->generic_class));
+                       nclass = mono_class_inflate_generic_class_checked (nclass, mono_generic_class_get_context (klass->generic_class), &error);
+                       mono_error_assert_ok (&error); /* FIXME don't swallow the error */
                        add_generic_class (acfg, nclass, FALSE, "ICollection<T>");
                }
 
@@ -4272,43 +4610,58 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
 
        /* Add an instance of GenericComparer<T> which is created dynamically by Comparer<T> */
        if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "Comparer`1")) {
+               MonoError error;
                MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
-               MonoClass *icomparable, *gcomparer;
+               MonoClass *icomparable, *gcomparer, *icomparable_inst;
                MonoGenericContext ctx;
                MonoType *args [16];
 
                memset (&ctx, 0, sizeof (ctx));
 
-               icomparable = mono_class_from_name (mono_defaults.corlib, "System", "IComparable`1");
-               g_assert (icomparable);
+               icomparable = mono_class_load_from_name (mono_defaults.corlib, "System", "IComparable`1");
+
                args [0] = &tclass->byval_arg;
                ctx.class_inst = mono_metadata_get_generic_inst (1, args);
 
-               if (mono_class_is_assignable_from (mono_class_inflate_generic_class (icomparable, &ctx), tclass)) {
-                       gcomparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "GenericComparer`1");
-                       g_assert (gcomparer);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (gcomparer, &ctx), FALSE, "Comparer<T>");
+               icomparable_inst = mono_class_inflate_generic_class_checked (icomparable, &ctx, &error);
+               mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+
+               if (mono_class_is_assignable_from (icomparable_inst, tclass)) {
+                       MonoClass *gcomparer_inst;
+                       gcomparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "GenericComparer`1");
+                       gcomparer_inst = mono_class_inflate_generic_class_checked (gcomparer, &ctx, &error);
+                       mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+
+                       add_generic_class (acfg, gcomparer_inst, FALSE, "Comparer<T>");
                }
        }
 
        /* Add an instance of GenericEqualityComparer<T> which is created dynamically by EqualityComparer<T> */
        if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "EqualityComparer`1")) {
+               MonoError error;
                MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
-               MonoClass *iface, *gcomparer;
+               MonoClass *iface, *gcomparer, *iface_inst;
                MonoGenericContext ctx;
                MonoType *args [16];
 
                memset (&ctx, 0, sizeof (ctx));
 
-               iface = mono_class_from_name (mono_defaults.corlib, "System", "IEquatable`1");
+               iface = mono_class_load_from_name (mono_defaults.corlib, "System", "IEquatable`1");
                g_assert (iface);
                args [0] = &tclass->byval_arg;
                ctx.class_inst = mono_metadata_get_generic_inst (1, args);
 
-               if (mono_class_is_assignable_from (mono_class_inflate_generic_class (iface, &ctx), tclass)) {
-                       gcomparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "GenericEqualityComparer`1");
-                       g_assert (gcomparer);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (gcomparer, &ctx), FALSE, "EqualityComparer<T>");
+               iface_inst = mono_class_inflate_generic_class_checked (iface, &ctx, &error);
+               mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+
+               if (mono_class_is_assignable_from (iface_inst, tclass)) {
+                       MonoClass *gcomparer_inst;
+                       MonoError error;
+
+                       gcomparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "GenericEqualityComparer`1");
+                       gcomparer_inst = mono_class_inflate_generic_class_checked (gcomparer, &ctx, &error);
+                       mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+                       add_generic_class (acfg, gcomparer_inst, FALSE, "EqualityComparer<T>");
                }
        }
 
@@ -4320,13 +4673,17 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
                MonoType *args [16];
 
                if (mono_class_is_enum (tclass)) {
+                       MonoClass *enum_comparer_inst;
+                       MonoError error;
+
                        memset (&ctx, 0, sizeof (ctx));
                        args [0] = &tclass->byval_arg;
                        ctx.class_inst = mono_metadata_get_generic_inst (1, args);
 
-                       enum_comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "EnumEqualityComparer`1");
-                       g_assert (enum_comparer);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (enum_comparer, &ctx), FALSE, "EqualityComparer<T>");
+                       enum_comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "EnumEqualityComparer`1");
+                       enum_comparer_inst = mono_class_inflate_generic_class_checked (enum_comparer, &ctx, &error);
+                       mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+                       add_generic_class (acfg, enum_comparer_inst, FALSE, "EqualityComparer<T>");
                }
        }
 
@@ -4338,13 +4695,17 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
                MonoType *args [16];
 
                if (mono_class_is_enum (tclass)) {
+                       MonoClass *comparer_inst;
+                       MonoError error;
+
                        memset (&ctx, 0, sizeof (ctx));
                        args [0] = &tclass->byval_arg;
                        ctx.class_inst = mono_metadata_get_generic_inst (1, args);
 
-                       comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "ObjectComparer`1");
-                       g_assert (comparer);
-                       add_generic_class (acfg, mono_class_inflate_generic_class (comparer, &ctx), FALSE, "Comparer<T>");
+                       comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "ObjectComparer`1");
+                       comparer_inst = mono_class_inflate_generic_class_checked (comparer, &ctx, &error);
+                       mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+                       add_generic_class (acfg, comparer_inst, FALSE, "Comparer<T>");
                }
        }
 }
@@ -4362,15 +4723,20 @@ add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int
        memset (&ctx, 0, sizeof (ctx));
 
        for (i = 0; i < ninsts; ++i) {
+               MonoError error;
+               MonoClass *generic_inst;
                args [0] = insts [i];
                ctx.class_inst = mono_metadata_get_generic_inst (1, args);
-               add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx), force, "");
+               generic_inst = mono_class_inflate_generic_class_checked (klass, &ctx, &error);
+               mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+               add_generic_class (acfg, generic_inst, force, "");
        }
 }
 
 static void
 add_types_from_method_header (MonoAotCompile *acfg, MonoMethod *method)
 {
+       MonoError error;
        MonoMethodHeader *header;
        MonoMethodSignature *sig;
        int j, depth;
@@ -4385,14 +4751,14 @@ add_types_from_method_header (MonoAotCompile *acfg, MonoMethod *method)
                                add_generic_class_with_depth (acfg, mono_class_from_mono_type (sig->params [j]), depth + 1, "arg");
        }
 
-       header = mono_method_get_header (method);
+       header = mono_method_get_header_checked (method, &error);
 
        if (header) {
                for (j = 0; j < header->num_locals; ++j)
                        if (header->locals [j]->type == MONO_TYPE_GENERICINST)
                                add_generic_class_with_depth (acfg, mono_class_from_mono_type (header->locals [j]), depth + 1, "local");
        } else {
-               mono_loader_clear_error ();
+               mono_error_cleanup (&error); /* FIXME report the error */
        }
 }
 
@@ -4561,10 +4927,10 @@ add_generic_instances (MonoAotCompile *acfg)
                insts [ninsts ++] = &mono_defaults.boolean_class->byval_arg;
 
                /* Add GenericComparer<T> instances for primitive types for Enum.ToString () */
-               klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
+               klass = mono_class_try_load_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
                if (klass)
                        add_instances_of (acfg, klass, insts, ninsts, TRUE);
-               klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericEqualityComparer`1");
+               klass = mono_class_try_load_from_name (acfg->image, "System.Collections.Generic", "GenericEqualityComparer`1");
                if (klass)
                        add_instances_of (acfg, klass, insts, ninsts, TRUE);
 
@@ -4579,24 +4945,20 @@ add_generic_instances (MonoAotCompile *acfg)
                        insts [ninsts ++] = &mono_defaults.uint32_class->byval_arg;
                        insts [ninsts ++] = &mono_defaults.uint16_class->byval_arg;
                        insts [ninsts ++] = &mono_defaults.byte_class->byval_arg;
-                       enum_comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "EnumEqualityComparer`1");
-                       g_assert (enum_comparer);
+                       enum_comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "EnumEqualityComparer`1");
                        add_instances_of (acfg, enum_comparer, insts, ninsts, FALSE);
 
                        ninsts = 0;
                        insts [ninsts ++] = &mono_defaults.int16_class->byval_arg;
-                       enum_comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "ShortEnumEqualityComparer`1");
-                       g_assert (enum_comparer);
+                       enum_comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "ShortEnumEqualityComparer`1");
                        add_instances_of (acfg, enum_comparer, insts, ninsts, FALSE);
 
                        ninsts = 0;
                        insts [ninsts ++] = &mono_defaults.sbyte_class->byval_arg;
-                       enum_comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "SByteEnumEqualityComparer`1");
-                       g_assert (enum_comparer);
+                       enum_comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "SByteEnumEqualityComparer`1");
                        add_instances_of (acfg, enum_comparer, insts, ninsts, FALSE);
 
-                       enum_comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "LongEnumEqualityComparer`1");
-                       g_assert (enum_comparer);
+                       enum_comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "LongEnumEqualityComparer`1");
                        ninsts = 0;
                        insts [ninsts ++] = &mono_defaults.int64_class->byval_arg;
                        insts [ninsts ++] = &mono_defaults.uint64_class->byval_arg;
@@ -4605,13 +4967,15 @@ add_generic_instances (MonoAotCompile *acfg)
 
                /* Add instances of the array generic interfaces for primitive types */
                /* This will add instances of the InternalArray_ helper methods in Array too */
-               klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "ICollection`1");
+               klass = mono_class_try_load_from_name (acfg->image, "System.Collections.Generic", "ICollection`1");
                if (klass)
                        add_instances_of (acfg, klass, insts, ninsts, TRUE);
-               klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "IList`1");
+
+               klass = mono_class_try_load_from_name (acfg->image, "System.Collections.Generic", "IList`1");
                if (klass)
                        add_instances_of (acfg, klass, insts, ninsts, TRUE);
-               klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "IEnumerable`1");
+
+               klass = mono_class_try_load_from_name (acfg->image, "System.Collections.Generic", "IEnumerable`1");
                if (klass)
                        add_instances_of (acfg, klass, insts, ninsts, TRUE);
 
@@ -4642,7 +5006,7 @@ add_generic_instances (MonoAotCompile *acfg)
                        MonoGenericContext ctx;
                        MonoType *args [16];
                        MonoMethod *m;
-                       MonoClass *interlocked_klass = mono_class_from_name (mono_defaults.corlib, "System.Threading", "Interlocked");
+                       MonoClass *interlocked_klass = mono_class_load_from_name (mono_defaults.corlib, "System.Threading", "Interlocked");
                        gpointer iter = NULL;
 
                        while ((m = mono_class_get_methods (interlocked_klass, &iter))) {
@@ -4662,7 +5026,7 @@ add_generic_instances (MonoAotCompile *acfg)
                        MonoGenericContext ctx;
                        MonoType *args [16];
                        MonoMethod *m;
-                       MonoClass *volatile_klass = mono_class_from_name (mono_defaults.corlib, "System.Threading", "Volatile");
+                       MonoClass *volatile_klass = mono_class_try_load_from_name (mono_defaults.corlib, "System.Threading", "Volatile");
                        gpointer iter = NULL;
 
                        if (volatile_klass) {
@@ -4743,10 +5107,10 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc
                        if (direct_callable)
                                return TRUE;
                }
-       } else if ((patch_info->type == MONO_PATCH_INFO_ICALL_ADDR && patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+       } else if ((patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL && patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
                if (acfg->aot_opts.direct_pinvoke)
                        return TRUE;
-       } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR) {
+       } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL) {
                if (acfg->aot_opts.direct_icalls)
                        return TRUE;
                return FALSE;
@@ -4927,7 +5291,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
        GPtrArray *patches;
        MonoJumpInfo *patch_info;
        MonoDebugSourceLocation **locs = NULL;
-       gboolean skip;
+       gboolean skip, prologue_end = FALSE;
 #ifdef MONO_ARCH_AOT_SUPPORTED
        gboolean direct_call, external_call;
        guint32 got_slot;
@@ -4962,10 +5326,16 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                if (locs && locs [i]) {
                        MonoDebugSourceLocation *loc = locs [i];
                        int findex;
+                       const char *options;
 
                        findex = get_file_index (acfg, loc->source_file);
                        emit_unset_mode (acfg);
-                       fprintf (acfg->fp, ".loc %d %d 0\n", findex, loc->row);
+                       if (!prologue_end)
+                               options = " prologue_end";
+                       else
+                               options = "";
+                       prologue_end = TRUE;
+                       fprintf (acfg->fp, ".loc %d %d 0%s\n", findex, loc->row, options);
                        mono_debug_symfile_free_location (loc);
                }
 
@@ -5029,7 +5399,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                        }
 
                                        acfg->stats.all_calls ++;
-                               } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR) {
+                               } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL) {
                                        if (!got_only && is_direct_callable (acfg, method, patch_info)) {
                                                if (!(patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
                                                        direct_pinvoke = mono_lookup_icall_symbol (patch_info->data.method);
@@ -5343,6 +5713,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        case MONO_PATCH_INFO_METHOD:
        case MONO_PATCH_INFO_METHOD_JUMP:
        case MONO_PATCH_INFO_ICALL_ADDR:
+       case MONO_PATCH_INFO_ICALL_ADDR_CALL:
        case MONO_PATCH_INFO_METHOD_RGCTX:
        case MONO_PATCH_INFO_METHOD_CODE_SLOT:
                encode_method_ref (acfg, patch_info->data.method, p, &p);
@@ -5383,9 +5754,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                MonoClass *ex_class;
 
                ex_class =
-                       mono_class_from_name (mono_defaults.exception_class->image,
+                       mono_class_load_from_name (mono_defaults.exception_class->image,
                                                                  "System", (const char *)patch_info->data.target);
-               g_assert (ex_class);
                encode_klass_ref (acfg, ex_class, p, &p);
                break;
        }
@@ -5565,11 +5935,13 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
        buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
        p = buf = (guint8 *)g_malloc (buf_size);
 
-       if (mono_class_get_cctor (method->klass))
+       if (mono_class_get_cctor (method->klass)) {
+               encode_value (1, p, &p);
                encode_klass_ref (acfg, method->klass, p, &p);
-       else
+       } else {
                /* Not needed when loading the method */
                encode_value (0, p, &p);
+       }
 
        g_assert (!(cfg->opt & MONO_OPT_SHARED));
 
@@ -6017,7 +6389,8 @@ get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cac
        case MONO_PATCH_INFO_RGCTX_FETCH:
                debug_sym = g_strdup_printf ("%s_rgctx_fetch_%d", prefix, acfg->label_generator ++);
                break;
-       case MONO_PATCH_INFO_ICALL_ADDR: {
+       case MONO_PATCH_INFO_ICALL_ADDR:
+       case MONO_PATCH_INFO_ICALL_ADDR_CALL: {
                char *s = get_debug_sym (ji->data.method, "", cache);
                
                debug_sym = g_strdup_printf ("%s_icall_native_%s", prefix, s);
@@ -6628,6 +7001,15 @@ wrap_path (gchar * path)
        return clean;
 }
 
+// Duplicate a char range and add it to a ptrarray, but only if it is nonempty
+static void
+ptr_array_add_range_if_nonempty(GPtrArray *args, gchar const *start, gchar const *end)
+{
+       ptrdiff_t len = end-start;
+       if (len > 0)
+               g_ptr_array_add (args, g_strndup (start, len));
+}
+
 static GPtrArray *
 mono_aot_split_options (const char *aot_options)
 {
@@ -6683,6 +7065,7 @@ mono_aot_split_options (const char *aot_options)
 
        next:
                aot_options++;
+       restart:
                // If the next character is end of string, then process the last option.
                if (*(aot_options) == '\0') {
                        end_of_string = TRUE;
@@ -6691,11 +7074,11 @@ mono_aot_split_options (const char *aot_options)
                continue;
 
        new_opt:
-               g_ptr_array_add (args, g_strndup (opt_start, aot_options - opt_start));
+               ptr_array_add_range_if_nonempty (args, opt_start, aot_options);
                opt_start = ++aot_options;
                if (end_of_string)
                        break;
-               goto next;
+               goto restart; // Check for null and continue loop
        }
 
        return args;
@@ -7105,6 +7488,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
        gboolean skip;
        int index, depth;
        MonoMethod *wrapped;
+       GTimer *jit_timer;
        JitFlags flags;
 
        if (acfg->aot_opts.metadata_only)
@@ -7159,7 +7543,11 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                flags = (JitFlags)(flags | JIT_FLAG_LLVM_ONLY | JIT_FLAG_EXPLICIT_NULL_CHECKS);
        if (acfg->aot_opts.no_direct_calls)
                flags = (JitFlags)(flags | JIT_FLAG_NO_DIRECT_ICALLS);
+
+       jit_timer = mono_time_track_start ();
        cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), flags, 0, index);
+       mono_time_track_end (&mono_jit_stats.jit_time, jit_timer);
+
        mono_loader_clear_error ();
 
        if (cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
@@ -7407,6 +7795,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
        }
        /* Make a copy of the argument/local info */
        {
+               MonoError error;
                MonoInst **args, **locals;
                MonoMethodSignature *sig;
                MonoMethodHeader *header;
@@ -7420,7 +7809,8 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                }
                cfg->args = args;
 
-               header = mono_method_get_header (method);
+               header = mono_method_get_header_checked (method, &error);
+               mono_error_assert_ok (&error); /* FIXME don't swallow the error */
                locals = (MonoInst **)mono_mempool_alloc (acfg->mempool, sizeof (MonoInst*) * header->num_locals);
                for (i = 0; i < header->num_locals; ++i) {
                        locals [i] = (MonoInst *)mono_mempool_alloc (acfg->mempool, sizeof (MonoInst));
@@ -7458,6 +7848,8 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
 
        g_hash_table_insert (acfg->method_to_cfg, cfg->orig_method, cfg);
 
+       mono_update_jit_stats (cfg);
+
        /*
        if (cfg->orig_method->wrapper_type)
                g_ptr_array_add (acfg->extra_methods, cfg->orig_method);
@@ -7788,7 +8180,7 @@ mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer data)
                if (type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
                        /* Call to a C function implementing a jit icall */
                        sym = mono_lookup_jit_icall_symbol ((const char *)data);
-               } else if (type == MONO_PATCH_INFO_ICALL_ADDR) {
+               } else if (type == MONO_PATCH_INFO_ICALL_ADDR_CALL) {
                        MonoMethod *method = (MonoMethod *)data;
                        if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
                                sym = mono_lookup_icall_symbol (method);
@@ -7818,7 +8210,7 @@ mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
                if (type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
                        /* Call to a C function implementing a jit icall */
                        sym = mono_lookup_jit_icall_symbol ((const char *)data);
-               } else if (type == MONO_PATCH_INFO_ICALL_ADDR) {
+               } else if (type == MONO_PATCH_INFO_ICALL_ADDR_CALL) {
                        MonoMethod *method = (MonoMethod *)data;
                        if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
                                sym = mono_lookup_icall_symbol (method);
@@ -7920,7 +8312,6 @@ emit_llvm_file (MonoAotCompile *acfg)
         * then removing tailcallelim + the global opts.
         * strip-dead-prototypes deletes unused intrinsics definitions.
         */
-       //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 -domtree -verify");
        /* The dse pass is disabled because of #13734 and #17616 */
        /*
         * The dse bug is in DeadStoreElimination.cpp:isOverwrite ():
@@ -7936,7 +8327,11 @@ emit_llvm_file (MonoAotCompile *acfg)
                // FIXME: This doesn't work yet
                opts = g_strdup ("");
        else
+#if LLVM_API_VERSION > 100
+               opts = g_strdup ("-O2");
+#else
                opts = g_strdup ("-targetlibinfo -no-aa -basicaa -notti -instcombine -simplifycfg -inline-cost -inline -sroa -domtree -early-cse -lazy-value-info -correlated-propagation -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -indvars -loop-idiom -loop-deletion -loop-unroll -memdep -gvn -memdep -memcpyopt -sccp -instcombine -lazy-value-info -correlated-propagation -domtree -memdep -adce -simplifycfg -instcombine -strip-dead-prototypes -domtree -verify");
+#endif
        command = g_strdup_printf ("\"%sopt\" -f %s -o \"%s\" \"%s\"", acfg->aot_opts.llvm_path, opts, optbc, tempbc);
        aot_printf (acfg, "Executing opt: %s\n", command);
        if (execute_system (command) != 0)
@@ -7971,6 +8366,10 @@ emit_llvm_file (MonoAotCompile *acfg)
 
        g_string_append_printf (acfg->llc_args, " -mono-eh-frame-symbol=%s%s", acfg->user_symbol_prefix, acfg->llvm_eh_frame_symbol);
 
+#if LLVM_API_VERSION > 100
+       g_string_append_printf (acfg->llc_args, " -disable-tail-calls");
+#endif
+
 #if defined(TARGET_MACH) && defined(TARGET_ARM)
        /* ios requires PIC code now */
        g_string_append_printf (acfg->llc_args, " -relocation-model=pic");
@@ -8608,7 +9007,6 @@ emit_exception_info (MonoAotCompile *acfg)
        if (seq_points_to_file) {
                char *seq_points_aot_file = acfg->aot_opts.gen_seq_points_file_path ? acfg->aot_opts.gen_seq_points_file_path
                        : g_strdup_printf("%s%s", acfg->image->name, SEQ_POINT_AOT_EXT);
-               printf("%s\n", seq_points_aot_file);
                mono_seq_point_data_write (&sp_data, seq_points_aot_file);
                mono_seq_point_data_free (&sp_data);
                g_free (seq_points_aot_file);
@@ -9487,7 +9885,6 @@ compile_asm (MonoAotCompile *acfg)
 #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"
 #elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
@@ -9508,22 +9905,30 @@ compile_asm (MonoAotCompile *acfg)
 #define AS_NAME "as"
 #endif
 
-#ifndef LD_OPTIONS
-#define LD_OPTIONS ""
-#endif
-
 #if defined(sparc)
-#define LD_NAME "ld -shared -G"
+#define LD_NAME "ld"
+#define LD_OPTIONS "-shared -G"
 #elif defined(__ppc__) && defined(TARGET_MACH)
-#define LD_NAME "gcc -dynamiclib"
+#define LD_NAME "gcc"
+#define LD_OPTIONS "-dynamiclib"
 #elif defined(TARGET_AMD64) && defined(TARGET_MACH)
-#define LD_NAME "clang --shared"
+#define LD_NAME "clang"
+#define LD_OPTIONS "--shared"
 #elif defined(TARGET_WIN32) && !defined(TARGET_ANDROID)
-#define LD_NAME "gcc -shared --dll"
+#define LD_NAME "gcc"
+#define LD_OPTIONS "-shared"
 #elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
-#define LD_NAME "clang -m32 -dynamiclib"
+#define LD_NAME "clang"
+#define LD_OPTIONS "-m32 -dynamiclib"
 #elif defined(TARGET_ARM) && !defined(TARGET_ANDROID)
-#define LD_NAME "gcc --shared"
+#define LD_NAME "gcc"
+#define LD_OPTIONS "--shared"
+#elif defined(TARGET_POWERPC64)
+#define LD_OPTIONS "-m elf64ppc"
+#endif
+
+#ifndef LD_OPTIONS
+#define LD_OPTIONS ""
 #endif
 
        if (acfg->aot_opts.asm_only) {
@@ -9599,10 +10004,11 @@ compile_asm (MonoAotCompile *acfg)
                ld_flags = g_strdup_printf ("%s %s", ld_flags, "-lstdc++");
 
 #ifdef LD_NAME
-       command = g_strdup_printf ("%s -o %s %s %s %s", LD_NAME,
+       command = g_strdup_printf ("%s%s %s -o %s %s %s %s", tool_prefix, LD_NAME, LD_OPTIONS,
                wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
                wrap_path (g_strdup_printf ("%s.o", acfg->tmpfname)), ld_flags);
 #else
+       // Default (linux)
        command = g_strdup_printf ("\"%sld\" %s -shared -o %s %s %s %s", tool_prefix, LD_OPTIONS,
                wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
                wrap_path (g_strdup_printf ("%s.o", acfg->tmpfname)), ld_flags);
@@ -10007,11 +10413,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts));
        acfg->aot_opts.write_symbols = TRUE;
-       acfg->aot_opts.ntrampolines = 1024;
-       acfg->aot_opts.nrgctx_trampolines = 1024;
-       acfg->aot_opts.nimt_trampolines = 128;
+       acfg->aot_opts.ntrampolines = 4096;
+       acfg->aot_opts.nrgctx_trampolines = 4096;
+       acfg->aot_opts.nimt_trampolines = 512;
        acfg->aot_opts.nrgctx_fetch_trampolines = 128;
-       acfg->aot_opts.ngsharedvt_arg_trampolines = 128;
+       acfg->aot_opts.ngsharedvt_arg_trampolines = 512;
        acfg->aot_opts.llvm_path = g_strdup ("");
        acfg->aot_opts.temp_path = g_strdup ("");
 #ifdef MONOTOUCH
@@ -10035,7 +10441,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        //acfg->aot_opts.print_skipped_methods = TRUE;
 
-#if !defined(ENABLE_GSHAREDVT)
+#if !defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
        if (opts & MONO_OPT_GSHAREDVT) {
                aot_printerrf (acfg, "-O=gsharedvt not supported on this platform.\n");
                return 1;
@@ -10050,13 +10456,13 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 #endif
 
        if (acfg->aot_opts.llvm_only) {
-#ifndef ENABLE_GSHAREDVT
-               aot_printerrf (acfg, "--aot=llvmonly requires a runtime compiled with --enable-gsharedvt.\n");
+#ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
+               aot_printerrf (acfg, "--aot=llvmonly requires a runtime that supports gsharedvt.\n");
                return 1;
 #endif
        }
 
-#if defined(ENABLE_GSHAREDVT) && defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
+#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
        acfg->opts |= MONO_OPT_GSHAREDVT;
        opts |= MONO_OPT_GSHAREDVT;
 #endif
@@ -10272,13 +10678,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                }
        }
 
-       if (acfg->aot_opts.dwarf_debug && acfg->aot_opts.asm_only && acfg->aot_opts.gnu_asm) {
+       if (acfg->aot_opts.dwarf_debug && acfg->aot_opts.gnu_asm) {
                /*
                 * CLANG supports GAS .file/.loc directives, so emit line number information this way
-                * FIXME: CLANG only emits line number info for .loc directives followed by assembly, not
-                * .byte directives.
                 */
-               //acfg->gas_line_numbers = TRUE;
+               acfg->gas_line_numbers = TRUE;
        }
 
        if ((!acfg->aot_opts.nodebug || acfg->aot_opts.dwarf_debug) && acfg->has_jitted_code) {
@@ -10286,7 +10690,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        aot_printerrf (acfg, "The dwarf AOT option requires the --debug option.\n");
                        return 1;
                }
-               acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE, !acfg->gas_line_numbers);
+               acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, !acfg->gas_line_numbers);
        }
 
        if (acfg->w)
@@ -10419,7 +10823,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                int i;
 
                aot_printf (acfg, "GOT slot distribution:\n");
-               for (i = 0; i < MONO_PATCH_INFO_NONE; ++i)
+               for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
                        if (acfg->stats.got_slot_types [i])
                                aot_printf (acfg, "\t%s: %d (%d)\n", get_patch_name (i), acfg->stats.got_slot_types [i], acfg->stats.got_slot_info_sizes [i]);
                aot_printf (acfg, "\nMethod stats:\n");