Add an 'mtriple' aot option to set the target triple used by the AOT compiler in...
[mono.git] / mono / mini / aot-compiler.c
index f0d18dc0590e04e20d22f2ad3acf71f050da8213..ce86f494b773f37e3ed605b4a0718da146b46a54 100644 (file)
@@ -68,7 +68,7 @@
 
 #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
 
-#if defined(__linux__)
+#if defined(__linux__) || defined(__native_client_codegen__)
 #define RODATA_SECT ".rodata"
 #else
 #define RODATA_SECT ".text"
@@ -82,6 +82,8 @@
 #define SHARED_EXT ".dll"
 #elif defined(__ppc__) && defined(__MACH__)
 #define SHARED_EXT ".dylib"
+#elif defined(__APPLE__) && defined(TARGET_X86) && !defined(__native_client_codegen__)
+#define SHARED_EXT ".dylib"
 #else
 #define SHARED_EXT ".so"
 #endif
@@ -111,6 +113,7 @@ typedef struct MonoAotOptions {
        gboolean stats;
        char *tool_prefix;
        gboolean autoreg;
+       char *mtriple;
 } MonoAotOptions;
 
 typedef struct MonoAotStats {
@@ -178,6 +181,9 @@ typedef struct MonoAotCompile {
        gboolean llvm;
        MonoAotFileFlags flags;
        MonoDynamicStream blob;
+       MonoClass **typespec_classes;
+       GString *llc_args;
+       GString *as_args;
 } MonoAotCompile;
 
 typedef struct {
@@ -330,6 +336,14 @@ emit_byte (MonoAotCompile *acfg, guint8 val)
        img_writer_emit_byte (acfg->w, val); 
 }
 
+#ifdef __native_client_codegen__
+static inline void
+emit_nacl_call_alignment (MonoAotCompile *acfg)
+{
+       img_writer_emit_nacl_call_alignment (acfg->w);
+}
+#endif
+
 static G_GNUC_UNUSED void
 emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
 {
@@ -460,6 +474,10 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #else
 #define AOT_FUNC_ALIGNMENT 16
 #endif
+#if defined(TARGET_X86) && defined(__native_client_codegen__)
+#undef AOT_FUNC_ALIGNMENT
+#define AOT_FUNC_ALIGNMENT 32
+#endif
  
 #if defined(TARGET_POWERPC64) && !defined(__mono_ilp32__)
 #define PPC_LD_OP "ld"
@@ -469,22 +487,33 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #define PPC_LDX_OP "lwzx"
 #endif
 
-//#define TARGET_ARM
+static void
+arch_process_target_triple (MonoAotCompile *acfg)
+{
+       char *mtriple = acfg->aot_opts.mtriple;
+
+       if (!mtriple)
+               return;
+
+       acfg->llc_args = g_string_new ("");
+       acfg->as_args = g_string_new ("");
 
 #ifdef TARGET_ARM
-#define LLVM_LABEL_PREFIX "_"
+       if (strstr (acfg->aot_opts.mtriple, "darwin")) {
+               g_string_append (acfg->llc_args, "-mattr=+v6");
+               acfg->llvm_label_prefix = "_";
+       } else {
+#ifdef ARM_FPU_VFP
+               g_string_append (acfg->llc_args, " -mattr=+vfp2,+d16");
+               g_string_append (acfg->as_args, " -mfpu=vfp3");
 #else
-#define LLVM_LABEL_PREFIX ""
+               g_string_append (acfg->llc_args, " -soft-float");
 #endif
+       }
 
-#ifdef TARGET_ARM
-/* iphone */
-#define LLC_TARGET_ARGS "-march=arm -mattr=+v6 -mtriple=arm-apple-darwin"
-/* ELF */
-//#define LLC_TARGET_ARGS "-march=arm -mtriple=arm-linux-gnueabi -soft-float"
-#else
-#define LLC_TARGET_ARGS ""
+       mono_arch_set_target (mtriple);
 #endif
+}
 
 /*
  * arch_emit_direct_call:
@@ -654,12 +683,26 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
 #if defined(TARGET_X86)
                guint32 offset = (acfg->plt_got_offset_base + index) * sizeof (gpointer);
 
+#ifdef __native_client_codegen__
+               const guint8 kSizeOfNaClJmp = 11;
+               guint8 bytes[kSizeOfNaClJmp];
+               guint8 *pbytes = &bytes[0];
+               
+               x86_jump_membase32 (pbytes, X86_EBX, offset);
+               emit_bytes (acfg, bytes, kSizeOfNaClJmp);
+               /* four bytes of data, used by mono_arch_patch_plt_entry              */
+               /* For Native Client, make this work with data embedded in push.      */
+               emit_byte (acfg, 0x68);  /* hide data in a push */
+               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+               emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+#else
                /* jmp *<offset>(%ebx) */
                emit_byte (acfg, 0xff);
                emit_byte (acfg, 0xa3);
                emit_int32 (acfg, offset);
                /* Used by mono_aot_get_plt_info_offset */
                emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+#endif  /* __native_client_codegen__ */
 #elif defined(TARGET_AMD64)
                /*
                 * We can't emit jumps because they are 32 bits only so they can't be patched.
@@ -846,9 +889,16 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
        /* Branch to generic trampoline */
        x86_jump_reg (code, X86_ECX);
 
+#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 = 17;
+       *tramp_size = NACL_SIZE(17, kNaClAlignment);
        g_assert (code - buf == *tramp_size);
 #else
        g_assert_not_reached ();
@@ -862,14 +912,14 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
  * CALL_TARGET is the symbol pointing to the native code of METHOD.
  */
 static void
-arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGenericSharingContext *gsctx, const char *call_target)
+arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, const char *call_target)
 {
 #if defined(TARGET_AMD64)
        guint8 buf [32];
        guint8 *code;
        int this_reg;
 
-       this_reg = mono_arch_get_this_arg_reg (mono_method_signature (method), gsctx, NULL);
+       this_reg = mono_arch_get_this_arg_reg (NULL);
        code = buf;
        amd64_alu_reg_imm (code, X86_ADD, this_reg, sizeof (MonoObject));
 
@@ -1028,9 +1078,17 @@ arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_
        /* 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 = 15;
+       *tramp_size = NACL_SIZE (15, kNaClAlignment);
        g_assert (code - buf == *tramp_size);
 #else
        g_assert_not_reached ();
@@ -1099,9 +1157,17 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
        *tramp_size = code - buf + 7;
 #elif defined(TARGET_X86)
        guint8 *buf, *code;
+#ifdef __native_client_codegen__
+       guint8 *buf_alloc;
+#endif
        guint8 *labels [3];
 
+#ifdef __native_client_codegen__
+       buf_alloc = g_malloc (256 + kNaClAlignment);
+       code = buf = ((guint)buf_alloc + kNaClAlignment) & ~kNaClAlignmentMask;
+#else
        code = buf = g_malloc (256);
+#endif
 
        /* Allocate a temporary stack slot */
        x86_push_reg (code, X86_EAX);
@@ -1143,6 +1209,13 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
        mono_x86_patch (labels [1], code);
        x86_breakpoint (code);
 
+#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 = code - buf;
@@ -1379,6 +1452,7 @@ stream_init (MonoDynamicStream *sh)
        sh->data = g_malloc (4096);
 
        /* So offsets are > 0 */
+       sh->data [0] = 0;
        sh->index ++;
 }
 
@@ -1417,7 +1491,7 @@ add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
  * blob where the data was stored.
  */
 static guint32
-add_to_blob (MonoAotCompile *acfg, guint8 *data, guint32 data_len)
+add_to_blob (MonoAotCompile *acfg, const guint8 *data, guint32 data_len)
 {
        if (acfg->blob.alloc_size == 0)
                stream_init (&acfg->blob);
@@ -1508,16 +1582,21 @@ static guint32
 find_typespec_for_class (MonoAotCompile *acfg, MonoClass *klass)
 {
        int i;
-       MonoClass *k = NULL;
+       int len = acfg->image->tables [MONO_TABLE_TYPESPEC].rows;
 
        /* FIXME: Search referenced images as well */
-       for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
-               k = mono_class_get_full (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL);
-               if (k == klass)
+       if (!acfg->typespec_classes) {
+               acfg->typespec_classes = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoClass*) * len);
+               for (i = 0; i < len; ++i) {
+                       acfg->typespec_classes [i] = mono_class_get_full (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL);
+               }
+       }
+       for (i = 0; i < len; ++i) {
+               if (acfg->typespec_classes [i] == klass)
                        break;
        }
 
-       if (i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows)
+       if (i < len)
                return MONO_TOKEN_TYPE_SPEC | (i + 1);
        else
                return 0;
@@ -1724,14 +1803,20 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                case MONO_WRAPPER_ALLOC: {
                        AllocatorWrapperInfo *info = mono_marshal_get_wrapper_info (method);
 
+                       /* The GC name is saved once in MonoAotFileInfo */
                        g_assert (info->alloc_type != -1);
                        encode_value (info->alloc_type, p, &p);
                        break;
                }
                case MONO_WRAPPER_WRITE_BARRIER:
                        break;
-               case MONO_WRAPPER_STELEMREF:
+               case MONO_WRAPPER_STELEMREF: {
+                       MonoClass *klass = mono_marshal_get_wrapper_info (method);
+
+                       /* Make sure this is the 'normal' stelemref wrapper, not the virtual one */
+                       g_assert (!klass);
                        break;
+               }
                case MONO_WRAPPER_UNKNOWN:
                        if (strcmp (method->name, "FastMonitorEnter") == 0)
                                encode_value (MONO_AOT_WRAPPER_MONO_ENTER, p, &p);
@@ -2187,6 +2272,8 @@ add_wrappers (MonoAotCompile *acfg)
 
                /* Skip methods which can not be handled by get_runtime_invoke () */
                sig = mono_method_signature (method);
+               if (!sig)
+                       continue;
                if ((sig->ret->type == MONO_TYPE_PTR) ||
                        (sig->ret->type == MONO_TYPE_TYPEDBYREF))
                        skip = TRUE;
@@ -2323,6 +2410,17 @@ add_wrappers (MonoAotCompile *acfg)
                if (method)
                        add_method (acfg, method);
 #endif
+
+               /* Stelemref wrappers */
+               /* There is only a constant number of these, iterating over all types should handle them all */
+               for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
+                       MonoClass *klass;
+               
+                       token = MONO_TOKEN_TYPE_DEF | (i + 1);
+                       klass = mono_class_get (acfg->image, token);
+                       if (klass)
+                               add_method (acfg, mono_marshal_get_virtual_stelemref (mono_array_class_get (klass, 1)));
+               }
        }
 
        /* 
@@ -2511,8 +2609,12 @@ method_has_type_vars (MonoMethod *method)
 static void add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth);
 
 static void
-add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
+add_generic_class (MonoAotCompile *acfg, MonoClass *klass, gboolean force)
 {
+       /* This might lead to a huge code blowup so only do it if neccesary */
+       if (!acfg->aot_opts.full_aot && !force)
+               return;
+
        add_generic_class_with_depth (acfg, klass, 0);
 }
 
@@ -2590,7 +2692,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth)
                        }
                        g_assert (nclass);
                        nclass = mono_class_inflate_generic_class (nclass, mono_generic_class_get_context (klass->generic_class));
-                       add_generic_class (acfg, nclass);
+                       add_generic_class (acfg, nclass, FALSE);
                }
 
                iter = NULL;
@@ -2621,13 +2723,34 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth)
                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));
+                       add_generic_class (acfg, mono_class_inflate_generic_class (gcomparer, &ctx), FALSE);
+               }
+       }
+
+       /* 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")) {
+               MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
+               MonoClass *iface, *gcomparer;
+               MonoGenericContext ctx;
+               MonoType *args [16];
+
+               memset (&ctx, 0, sizeof (ctx));
+
+               iface = mono_class_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);
                }
        }
 }
 
 static void
-add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int ninsts)
+add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int ninsts, gboolean force)
 {
        int i;
        MonoGenericContext ctx;
@@ -2638,7 +2761,7 @@ add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int
        for (i = 0; i < ninsts; ++i) {
                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));
+               add_generic_class (acfg, mono_class_inflate_generic_class (klass, &ctx), force);
        }
 }
 
@@ -2661,6 +2784,9 @@ add_generic_instances (MonoAotCompile *acfg)
                token = MONO_TOKEN_METHOD_SPEC | (i + 1);
                method = mono_get_method (acfg->image, token, NULL);
 
+               if (!method)
+                       continue;
+
                if (method->klass->image != acfg->image)
                        continue;
 
@@ -2765,7 +2891,7 @@ add_generic_instances (MonoAotCompile *acfg)
                if (!klass || klass->rank)
                        continue;
 
-               add_generic_class (acfg, klass);
+               add_generic_class (acfg, klass, FALSE);
        }
 
        /* Add types of args/locals */
@@ -2779,7 +2905,7 @@ add_generic_instances (MonoAotCompile *acfg)
                if (sig) {
                        for (j = 0; j < sig->param_count; ++j)
                                if (sig->params [j]->type == MONO_TYPE_GENERICINST)
-                                       add_generic_class (acfg, mono_class_from_mono_type (sig->params [j]));
+                                       add_generic_class (acfg, mono_class_from_mono_type (sig->params [j]), FALSE);
                }
 
                header = mono_method_get_header (method);
@@ -2787,7 +2913,7 @@ add_generic_instances (MonoAotCompile *acfg)
                if (header) {
                        for (j = 0; j < header->num_locals; ++j)
                                if (header->locals [j]->type == MONO_TYPE_GENERICINST)
-                                       add_generic_class (acfg, mono_class_from_mono_type (header->locals [j]));
+                                       add_generic_class (acfg, mono_class_from_mono_type (header->locals [j]), FALSE);
                }
        }
 
@@ -2812,22 +2938,22 @@ add_generic_instances (MonoAotCompile *acfg)
                /* Add GenericComparer<T> instances for primitive types for Enum.ToString () */
                klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
                if (klass)
-                       add_instances_of (acfg, klass, insts, ninsts);
+                       add_instances_of (acfg, klass, insts, ninsts, TRUE);
                klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "GenericEqualityComparer`1");
                if (klass)
-                       add_instances_of (acfg, klass, insts, ninsts);
+                       add_instances_of (acfg, klass, insts, ninsts, TRUE);
 
                /* 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");
                if (klass)
-                       add_instances_of (acfg, klass, insts, ninsts);
+                       add_instances_of (acfg, klass, insts, ninsts, TRUE);
                klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "IList`1");
                if (klass)
-                       add_instances_of (acfg, klass, insts, ninsts);
+                       add_instances_of (acfg, klass, insts, ninsts, TRUE);
                klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "IEnumerable`1");
                if (klass)
-                       add_instances_of (acfg, klass, insts, ninsts);
+                       add_instances_of (acfg, klass, insts, ninsts, TRUE);
 
                /* 
                 * Add a managed-to-native wrapper of Array.GetGenericValueImpl<object>, which is
@@ -3136,6 +3262,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
                break;
        case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
+       case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
                break;
        case MONO_PATCH_INFO_METHOD_REL:
                encode_value ((gint)patch_info->data.offset, p, &p);
@@ -3337,6 +3464,12 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
                        continue;
                }
 
+               if (patch_info->type == MONO_PATCH_INFO_GC_CARD_TABLE_ADDR) {
+                       /* Stored in a GOT slot initialized at module load time */
+                       patch_info->type = MONO_PATCH_INFO_NONE;
+                       continue;
+               }
+
                if (is_plt_patch (patch_info)) {
                        /* Calls are made through the PLT */
                        patch_info->type = MONO_PATCH_INFO_NONE;
@@ -3805,13 +3938,17 @@ emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
        ji = info->ji;
        unwind_ops = info->unwind_ops;
 
+#ifdef __native_client_codegen__
+       mono_nacl_fix_patches (code, ji);
+#endif
+
        /* Emit code */
 
        sprintf (start_symbol, "%s", name);
 
        emit_section_change (acfg, ".text", 0);
        emit_global (acfg, start_symbol, TRUE);
-       emit_alignment (acfg, 16);
+       emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
        emit_label (acfg, start_symbol);
 
        sprintf (symbol, "%snamed_%s", acfg->temp_prefix, name);
@@ -4010,7 +4147,7 @@ emit_trampolines (MonoAotCompile *acfg)
                        }
 
                        emit_global (acfg, symbol, TRUE);
-                       emit_alignment (acfg, 16);
+                       emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
                        emit_label (acfg, symbol);
 
                        acfg->trampoline_got_offset_base [ntype] = tramp_got_offset;
@@ -4034,6 +4171,10 @@ emit_trampolines (MonoAotCompile *acfg)
                                default:
                                        g_assert_not_reached ();
                                }
+#ifdef __native_client_codegen__
+                               /* align to avoid 32-byte boundary crossings */
+                               emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+#endif
 
                                if (!acfg->trampoline_size [ntype]) {
                                        g_assert (tramp_size);
@@ -4106,6 +4247,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->print_skipped_methods = TRUE;
                } else if (str_begins_with (arg, "stats")) {
                        opts->stats = TRUE;
+               } else if (str_begins_with (arg, "mtriple=")) {
+                       opts->mtriple = g_strdup (arg + strlen ("mtriple="));
                } else {
                        fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
                        exit (1);
@@ -4212,9 +4355,6 @@ can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
        return TRUE;
 }
 
-static void
-add_generic_class (MonoAotCompile *acfg, MonoClass *klass);
-
 /*
  * compile_method:
  *
@@ -4396,6 +4536,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                switch (patch_info->type) {
                case MONO_PATCH_INFO_GOT_OFFSET:
                case MONO_PATCH_INFO_NONE:
+               case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
                        break;
                case MONO_PATCH_INFO_IMAGE:
                        /* The assembly is stored in GOT slot 0 */
@@ -4661,7 +4802,7 @@ emit_llvm_file (MonoAotCompile *acfg)
        char *command, *opts;
        int i;
        MonoJumpInfo *patch_info;
-       const char *llc_extra_args;
+       const char *llc_args;
 
        /*
         * When using LLVM, we let llvm emit the got since the LLVM IL needs to refer
@@ -4726,11 +4867,17 @@ emit_llvm_file (MonoAotCompile *acfg)
 
 #if !LLVM_CHECK_VERSION(2, 8)
        /* LLVM 2.8 removed the -f flag ??? */
-       llc_extra_args = "-f";
+       llc_args = "-f";
 #else
-       llc_extra_args = "";
+       llc_args = "";
 #endif
-       command = g_strdup_printf ("llc %s %s -relocation-model=pic -unwind-tables -o %s temp.opt.bc", LLC_TARGET_ARGS, llc_extra_args, acfg->tmpfname);
+
+       if (!acfg->aot_opts.mtriple) {
+               fprintf (stderr, "The mtriple= option is required when compiling using LLVM.\n");
+               exit (1);
+       }
+
+       command = g_strdup_printf ("llc -mtriple=%s %s %s -relocation-model=pic -unwind-tables -o %s temp.opt.bc", acfg->aot_opts.mtriple, llc_args, acfg->llc_args ? acfg->llc_args->str : "", acfg->tmpfname);
 
        printf ("Executing llc: %s\n", command);
 
@@ -4810,12 +4957,15 @@ emit_code (MonoAotCompile *acfg)
                        }
 
                        emit_section_change (acfg, ".text", 0);
+#ifdef __native_client_codegen__
+                       emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+#endif
                        emit_global (acfg, symbol, TRUE);
                        emit_label (acfg, symbol);
 
                        sprintf (call_target, "%s", cfg->asm_symbol);
 
-                       arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
+                       arch_emit_unbox_trampoline (acfg, cfg->orig_method, call_target);
                }
 
                if (cfg->compile_llvm)
@@ -4934,17 +5084,21 @@ mono_aot_method_hash (MonoMethod *method)
 {
        MonoMethodSignature *sig;
        MonoClass *klass;
-       int i;
+       int i, hindex;
        int hashes_count;
        guint32 *hashes_start, *hashes;
        guint32 a, b, c;
+       MonoGenericInst *ginst = NULL;
 
        /* Similar to the hash in mono_method_get_imt_slot () */
 
        sig = mono_method_signature (method);
 
-       hashes_count = sig->param_count + 5;
-       hashes_start = malloc (hashes_count * sizeof (guint32));
+       if (method->is_inflated)
+               ginst = ((MonoMethodInflated*)method)->context.method_inst;
+
+       hashes_count = sig->param_count + 5 + (ginst ? ginst->type_argc : 0);
+       hashes_start = g_malloc0 (hashes_count * sizeof (guint32));
        hashes = hashes_start;
 
        /* Some wrappers are assigned to random classes */
@@ -4970,10 +5124,16 @@ mono_aot_method_hash (MonoMethod *method)
                hashes [2] = mono_metadata_str_hash (method->name);
        hashes [3] = method->wrapper_type;
        hashes [4] = mono_aot_type_hash (sig->ret);
+       hindex = 5;
        for (i = 0; i < sig->param_count; i++) {
-               hashes [5 + i] = mono_aot_type_hash (sig->params [i]);
+               hashes [hindex ++] = mono_aot_type_hash (sig->params [i]);
        }
-       
+       if (ginst) {
+               for (i = 0; i < ginst->type_argc; ++i)
+                       hashes [hindex ++] = mono_aot_type_hash (ginst->type_argv [i]);
+       }               
+       g_assert (hindex == hashes_count);
+
        /* Setup internal state */
        a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
 
@@ -5682,7 +5842,7 @@ emit_globals (MonoAotCompile *acfg)
                 * Emit a global symbol which can be passed by an embedding app to
                 * mono_aot_register_module ().
                 */
-#if defined(__MACH__)
+#if defined(__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);
@@ -5742,6 +5902,15 @@ emit_file_info (MonoAotCompile *acfg)
 {
        char symbol [128];
        int i;
+       int gc_name_offset;
+       const char *gc_name;
+
+       /*
+        * The managed allocators are GC specific, so can't use an AOT image created by one GC
+        * in another.
+        */
+       gc_name = mono_gc_get_gc_name ();
+       gc_name_offset = add_to_blob (acfg, (guint8*)gc_name, strlen (gc_name) + 1);
 
        sprintf (symbol, "mono_aot_file_info");
        emit_section_change (acfg, ".data", 0);
@@ -5749,13 +5918,14 @@ emit_file_info (MonoAotCompile *acfg)
        emit_label (acfg, symbol);
        emit_global (acfg, symbol, FALSE);
 
-       /* The data emitted here must match MonoAotFileInfo in aot-runtime.c. */
+       /* The data emitted here must match MonoAotFileInfo. */
        emit_int32 (acfg, acfg->plt_got_offset_base);
        emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
        emit_int32 (acfg, acfg->plt_offset);
        emit_int32 (acfg, acfg->nmethods);
        emit_int32 (acfg, acfg->flags);
        emit_int32 (acfg, acfg->opts);
+       emit_int32 (acfg, gc_name_offset);
 
        for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
                emit_int32 (acfg, acfg->num_trampolines [i]);
@@ -5934,10 +6104,18 @@ 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__)
+#define AS_OPTIONS "-arch i386 -W"
 #else
 #define AS_OPTIONS ""
 #endif
 
+#ifdef __native_client_codegen__
+#define AS_NAME "nacl-as"
+#else
+#define AS_NAME "as"
+#endif
+
 #ifndef LD_OPTIONS
 #define LD_OPTIONS ""
 #endif
@@ -5963,7 +6141,7 @@ compile_asm (MonoAotCompile *acfg)
        } else {
                objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
        }
-       command = g_strdup_printf ("%sas %s %s -o %s", tool_prefix, AS_OPTIONS, acfg->tmpfname, objfile);
+       command = g_strdup_printf ("%s%s %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS, acfg->as_args ? acfg->as_args->str : "", objfile, acfg->tmpfname);
        printf ("Executing the native assembler: %s\n", command);
        if (system (command) != 0) {
                g_free (command);
@@ -5993,6 +6171,8 @@ compile_asm (MonoAotCompile *acfg)
        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__)
+       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);
 #endif
@@ -6159,13 +6339,14 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        fprintf (stderr, "The soft-debug AOT option requires the --debug option.\n");
                        return 1;
                }
+               acfg->flags |= MONO_AOT_FILE_FLAG_DEBUG;
        }
 
-#ifdef ENABLE_LLVM
-       acfg->llvm = TRUE;
-       acfg->aot_opts.asm_writer = TRUE;
-       acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM;
-#endif
+       if (mono_use_llvm) {
+               acfg->llvm = TRUE;
+               acfg->aot_opts.asm_writer = TRUE;
+               acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM;
+       }
 
        if (acfg->aot_opts.full_aot)
                acfg->flags |= MONO_AOT_FILE_FLAG_FULL_AOT;
@@ -6200,8 +6381,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
         * symbols.
         */
        acfg->llvm_label_prefix = "";
-       if (acfg->llvm)
-               acfg->llvm_label_prefix = LLVM_LABEL_PREFIX;
+
+       arch_process_target_triple (acfg);
 
        acfg->method_index = 1;
 
@@ -6214,8 +6395,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->plt_offset = 1;
 
 #ifdef ENABLE_LLVM
-       llvm_acfg = acfg;
-       mono_llvm_create_aot_module (acfg->got_symbol_base);
+       if (acfg->llvm) {
+               llvm_acfg = acfg;
+               mono_llvm_create_aot_module (acfg->got_symbol_base);
+       }
 #endif
 
        /* GOT offset 0 is reserved for the address of the current assembly */
@@ -6232,6 +6415,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
                ji->type = MONO_PATCH_INFO_MSCORLIB_GOT_ADDR;
                get_got_offset (acfg, ji);
+
+               /* This is very common */
+               ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
+               ji->type = MONO_PATCH_INFO_GC_CARD_TABLE_ADDR;
+               get_got_offset (acfg, ji);
        }
 
        TV_GETTIME (atv);
@@ -6254,9 +6442,9 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                } else {
                        acfg->tmpfname = g_strdup ("temp.s");
                }
-       }
 
-       emit_llvm_file (acfg);
+               emit_llvm_file (acfg);
+       }
 #endif
 
        if (!acfg->aot_opts.asm_only && !acfg->aot_opts.asm_writer && bin_writer_supported ()) {
@@ -6311,7 +6499,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        MonoCompile *cfg = acfg->cfgs [i];
                        int method_index = get_method_index (acfg, cfg->orig_method);
 
-                       cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, LLVM_LABEL_PREFIX, method_index);
+                       cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, acfg->llvm_label_prefix, method_index);
                }
        }