Merge pull request #3247 from lateralusX/jlorenss/win-x64-lmf-exception
[mono.git] / mono / mini / mini-llvm.c
index d6e2677cd237c65c788902a67174e02c426ce9d9..e2f963bff0461fef64bb49cb4b48b6efddff8916 100644 (file)
@@ -72,6 +72,7 @@ typedef struct {
        gboolean external_symbols;
        gboolean emit_dwarf;
        int max_got_offset;
+       LLVMValueRef personality;
 
        /* For AOT */
        MonoAssembly *assembly;
@@ -94,6 +95,7 @@ typedef struct {
        LLVMContextRef context;
        LLVMValueRef sentinel_exception;
        void *di_builder, *cu;
+       GHashTable *objc_selector_to_var;
 } MonoLLVMModule;
 
 /*
@@ -1282,6 +1284,9 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *
                }
                break;
        }
+       case LLVMArgAsIArgs:
+               ret_type = LLVMArrayType (IntPtrType (), cinfo->ret.nslots);
+               break;
        case LLVMArgFpStruct: {
                /* Vtype returned as a fp struct */
                LLVMTypeRef members [16];
@@ -1744,26 +1749,14 @@ get_most_deep_clause (MonoCompile *cfg, EmitContext *ctx, MonoBasicBlock *bb)
 {
        // Since they're sorted by nesting we just need
        // the first one that the bb is a member of
-       MonoExceptionClause *last = NULL;
-
        for (int i = 0; i < cfg->header->num_clauses; i++) {
                MonoExceptionClause *curr = &cfg->header->clauses [i];
 
                if (MONO_OFFSET_IN_CLAUSE (curr, bb->real_offset))
                        return curr;
-               /*
-               if (MONO_OFFSET_IN_CLAUSE (curr, bb->real_offset)) {
-                       if (last && CLAUSE_END(last) > CLAUSE_END(curr))
-                               last = curr;
-                       else
-                               last = curr;
-               } else if(last) {
-                       break;
-               }
-               */
        }
 
-       return last;
+       return NULL;
 }
        
 static void
@@ -1881,7 +1874,7 @@ emit_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, LL
 }
 
 static LLVMValueRef
-emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, const char *name, gboolean is_faulting, BarrierKind barrier)
+emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, LLVMValueRef base, const char *name, gboolean is_faulting, BarrierKind barrier)
 {
        const char *intrins_name;
        LLVMValueRef args [16], res;
@@ -1891,7 +1884,9 @@ emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder
 #if LLVM_API_VERSION > 100
        if (is_faulting && bb->region != -1 && !ctx->cfg->llvm_only) {
                /* The llvm.mono.load/store intrinsics are not supported by this llvm version, emit an explicit null check instead */
-               LLVMValueRef cmp = LLVMBuildICmp (*builder_ref, LLVMIntEQ, addr, LLVMConstNull (LLVMTypeOf (addr)), "");
+               LLVMValueRef cmp;
+
+               cmp = LLVMBuildICmp (*builder_ref, LLVMIntEQ, base, LLVMConstNull (LLVMTypeOf (base)), "");
                emit_cond_system_exception (ctx, bb, "NullReferenceException", cmp);
                *builder_ref = ctx->builder;
                use_intrinsics = FALSE;
@@ -1963,26 +1958,29 @@ emit_load_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder
                 * LLVM will generate invalid code when encountering a load from a
                 * NULL address.
                 */
-                res = mono_llvm_build_load (*builder_ref, addr, name, is_faulting, barrier);
+               if (barrier != LLVM_BARRIER_NONE)
+                       res = mono_llvm_build_atomic_load (*builder_ref, addr, name, is_faulting, size, barrier);
+               else
+                       res = mono_llvm_build_load (*builder_ref, addr, name, is_faulting);
 
-                /* Mark it with a custom metadata */
-                /*
-                if (is_faulting)
-                        set_metadata_flag (res, "mono.faulting.load");
-                */
+               /* Mark it with a custom metadata */
+               /*
+                 if (is_faulting)
+                 set_metadata_flag (res, "mono.faulting.load");
+               */
 
-                return res;
+               return res;
        }
 }
 
 static LLVMValueRef
 emit_load (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef addr, const char *name, gboolean is_faulting)
 {
-       return emit_load_general (ctx, bb, builder_ref, size, addr, name, is_faulting, LLVM_BARRIER_NONE);
+       return emit_load_general (ctx, bb, builder_ref, size, addr, addr, name, is_faulting, LLVM_BARRIER_NONE);
 }
 
 static void
-emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, gboolean is_faulting, BarrierKind barrier)
+emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, LLVMValueRef base, gboolean is_faulting, BarrierKind barrier)
 {
        const char *intrins_name;
        LLVMValueRef args [16];
@@ -1991,7 +1989,7 @@ emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builde
 #if LLVM_API_VERSION > 100
        if (is_faulting && bb->region != -1 && !ctx->cfg->llvm_only) {
                /* The llvm.mono.load/store intrinsics are not supported by this llvm version, emit an explicit null check instead */
-               LLVMValueRef cmp = LLVMBuildICmp (*builder_ref, LLVMIntEQ, addr, LLVMConstNull (LLVMTypeOf (addr)), "");
+               LLVMValueRef cmp = LLVMBuildICmp (*builder_ref, LLVMIntEQ, base, LLVMConstNull (LLVMTypeOf (base)), "");
                emit_cond_system_exception (ctx, bb, "NullReferenceException", cmp);
                *builder_ref = ctx->builder;
                use_intrinsics = FALSE;
@@ -2045,14 +2043,17 @@ emit_store_general (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builde
                args [4] = LLVMConstInt (LLVMInt32Type (), ordering, FALSE);
                emit_call (ctx, bb, builder_ref, get_intrinsic (ctx, intrins_name), args, 5);
        } else {
-               mono_llvm_build_store (*builder_ref, value, addr, is_faulting, barrier);
+               if (barrier != LLVM_BARRIER_NONE)
+                       mono_llvm_build_aligned_store (*builder_ref, value, addr, barrier, size);
+               else
+                       mono_llvm_build_store (*builder_ref, value, addr, is_faulting, barrier);
        }
 }
 
 static void
-emit_store (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, gboolean is_faulting)
+emit_store (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, int size, LLVMValueRef value, LLVMValueRef addr, LLVMValueRef base, gboolean is_faulting)
 {
-       emit_store_general (ctx, bb, builder_ref, size, value, addr, is_faulting, LLVM_BARRIER_NONE);
+       emit_store_general (ctx, bb, builder_ref, size, value, addr, base, is_faulting, LLVM_BARRIER_NONE);
 }
 
 /*
@@ -3213,8 +3214,12 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                                        target =
                                                mono_create_jit_trampoline (mono_domain_get (),
                                                                                                        call->method, &error);
-                                       if (!mono_error_ok (&error))
-                                               mono_error_raise_exception (&error); /* FIXME: Don't raise here */
+                                       if (!is_ok (&error)) {
+                                               set_failure (ctx, mono_error_get_message (&error));
+                                               mono_error_cleanup (&error);
+                                               return;
+                                       }
+
                                        tramp_var = LLVMAddGlobal (ctx->lmodule, LLVMPointerType (llvm_sig, 0), name);
                                        LLVMSetInitializer (tramp_var, LLVMConstIntToPtr (LLVMConstInt (LLVMInt64Type (), (guint64)(size_t)target, FALSE), LLVMPointerType (llvm_sig, 0)));
                                        LLVMSetLinkage (tramp_var, LLVMExternalLinkage);
@@ -3224,15 +3229,17 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
 #else
                                target =
                                        mono_create_jit_trampoline (mono_domain_get (),
-                                                                                               call->method, &error);
-                               if (!mono_error_ok (&error))
-                                       mono_error_raise_exception (&error); /* FIXME: Don't raise here */
+                                                                   call->method, &error);
+                               if (!is_ok (&error)) {
+                                       g_free (name);
+                                       set_failure (ctx, mono_error_get_message (&error));
+                                       mono_error_cleanup (&error);
+                                       return;
+                               }
 
                                callee = LLVMAddFunction (ctx->lmodule, name, llvm_sig);
                                g_free (name);
 
-                               if (!mono_error_ok (&error))
-                                       mono_error_raise_exception (&error); /* FIXME: Don't raise here */
                                LLVMAddGlobalMapping (ctx->module->ee, callee, target);
 #endif
                        }
@@ -3360,7 +3367,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                if (!ctx->imt_rgctx_loc)
                        ctx->imt_rgctx_loc = build_alloca_llvm_type (ctx, ctx->module->ptr_type, sizeof (gpointer));
                LLVMBuildStore (builder, convert (ctx, ctx->values [call->rgctx_arg_reg], ctx->module->ptr_type), ctx->imt_rgctx_loc);
-               args [cinfo->rgctx_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE, LLVM_BARRIER_NONE);
+               args [cinfo->rgctx_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE);
 #else
                args [cinfo->rgctx_arg_pindex] = convert (ctx, values [call->rgctx_arg_reg], ctx->module->ptr_type);
 #endif
@@ -3373,7 +3380,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                if (!ctx->imt_rgctx_loc)
                        ctx->imt_rgctx_loc = build_alloca_llvm_type (ctx, ctx->module->ptr_type, sizeof (gpointer));
                LLVMBuildStore (builder, convert (ctx, ctx->values [call->imt_arg_reg], ctx->module->ptr_type), ctx->imt_rgctx_loc);
-               args [cinfo->imt_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE, LLVM_BARRIER_NONE);
+               args [cinfo->imt_arg_pindex] = mono_llvm_build_load (builder, ctx->imt_rgctx_loc, "", TRUE);
 #else
                args [cinfo->imt_arg_pindex] = convert (ctx, values [call->imt_arg_reg], ctx->module->ptr_type);
 #endif
@@ -3538,6 +3545,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref,
                        addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
                LLVMBuildStore (builder, lcall, addresses [call->inst.dreg]);
                break;
+       case LLVMArgAsIArgs:
        case LLVMArgFpStruct:
                if (!addresses [call->inst.dreg])
                        addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
@@ -3968,13 +3976,17 @@ emit_handler_start (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef builder
                g_assert (personality);
        } else {
 #if LLVM_API_VERSION > 100
-               LLVMTypeRef personality_type = LLVMFunctionType (LLVMInt32Type (), NULL, 0, TRUE);
-               personality = LLVMAddFunction (ctx->lmodule, "mono_personality", personality_type);
-               LLVMAddFunctionAttr (personality, LLVMNoUnwindAttribute);
-               LLVMBasicBlockRef entry_bb = LLVMAppendBasicBlock (personality, "ENTRY");
-               LLVMBuilderRef builder2 = LLVMCreateBuilder ();
-               LLVMPositionBuilderAtEnd (builder2, entry_bb);
-               LLVMBuildRet (builder2, LLVMConstInt (LLVMInt32Type (), 0, FALSE));
+               personality = ctx->module->personality;
+               if (!personality) {
+                       LLVMTypeRef personality_type = LLVMFunctionType (LLVMInt32Type (), NULL, 0, TRUE);
+                       personality = LLVMAddFunction (ctx->lmodule, "mono_personality", personality_type);
+                       LLVMAddFunctionAttr (personality, LLVMNoUnwindAttribute);
+                       LLVMBasicBlockRef entry_bb = LLVMAppendBasicBlock (personality, "ENTRY");
+                       LLVMBuilderRef builder2 = LLVMCreateBuilder ();
+                       LLVMPositionBuilderAtEnd (builder2, entry_bb);
+                       LLVMBuildRet (builder2, LLVMConstInt (LLVMInt32Type (), 0, FALSE));
+                       ctx->module->personality = personality;
+               }
 #else
                static gint32 mapping_inited;
 
@@ -4365,6 +4377,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                                LLVMBuildRetVoid (builder);
                                break;
                        }
+                       case LLVMArgAsIArgs:
                        case LLVMArgFpStruct: {
                                LLVMTypeRef ret_type = LLVMGetReturnType (LLVMGetElementType (LLVMTypeOf (method)));
                                LLVMValueRef retval;
@@ -5095,6 +5108,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        if ((ins->opcode == OP_LOADI8_MEM) || (ins->opcode == OP_LOAD_MEM) || (ins->opcode == OP_LOADI4_MEM) || (ins->opcode == OP_LOADU4_MEM) || (ins->opcode == OP_LOADU1_MEM) || (ins->opcode == OP_LOADU2_MEM)) {
                                addr = LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE);
+                               base = addr;
                        } else {
                                /* _MEMBASE */
                                base = lhs;
@@ -5113,7 +5127,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        addr = convert (ctx, addr, LLVMPointerType (t, 0));
 
-                       values [ins->dreg] = emit_load (ctx, bb, &builder, size, addr, dname, is_volatile);
+                       values [ins->dreg] = emit_load_general (ctx, bb, &builder, size, addr, base, dname, is_volatile, LLVM_BARRIER_NONE);
 
                        if (!is_volatile && (ins->flags & MONO_INST_INVARIANT_LOAD)) {
                                /*
@@ -5143,7 +5157,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_STORER8_MEMBASE_REG:
                case OP_STORE_MEMBASE_REG: {
                        int size = 8;
-                       LLVMValueRef index, addr;
+                       LLVMValueRef index, addr, base;
                        LLVMTypeRef t;
                        gboolean sext = FALSE, zext = FALSE;
                        gboolean is_volatile = (ins->flags & MONO_INST_FAULT);
@@ -5155,15 +5169,16 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
 
+                       base = values [ins->inst_destbasereg];
                        if (ins->inst_offset % size != 0) {
                                /* Unaligned store */
                                index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset, FALSE);
-                               addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
+                               addr = LLVMBuildGEP (builder, convert (ctx, base, LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
                        } else {
                                index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
-                               addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
+                               addr = LLVMBuildGEP (builder, convert (ctx, base, LLVMPointerType (t, 0)), &index, 1, "");
                        }
-                       emit_store (ctx, bb, &builder, size, convert (ctx, values [ins->sreg1], t), convert (ctx, addr, LLVMPointerType (t, 0)), is_volatile);
+                       emit_store (ctx, bb, &builder, size, convert (ctx, values [ins->sreg1], t), convert (ctx, addr, LLVMPointerType (t, 0)), base, is_volatile);
                        break;
                }
 
@@ -5173,27 +5188,28 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_STOREI8_MEMBASE_IMM:
                case OP_STORE_MEMBASE_IMM: {
                        int size = 8;
-                       LLVMValueRef index, addr;
+                       LLVMValueRef index, addr, base;
                        LLVMTypeRef t;
                        gboolean sext = FALSE, zext = FALSE;
                        gboolean is_volatile = (ins->flags & MONO_INST_FAULT);
 
                        t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
 
+                       base = values [ins->inst_destbasereg];
                        if (ins->inst_offset % size != 0) {
                                /* Unaligned store */
                                index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset, FALSE);
-                               addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
+                               addr = LLVMBuildGEP (builder, convert (ctx, base, LLVMPointerType (LLVMInt8Type (), 0)), &index, 1, "");
                        } else {
                                index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
-                               addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
+                               addr = LLVMBuildGEP (builder, convert (ctx, base, LLVMPointerType (t, 0)), &index, 1, "");
                        }
-                       emit_store (ctx, bb, &builder, size, convert (ctx, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), t), convert (ctx, addr, LLVMPointerType (t, 0)), is_volatile);
+                       emit_store (ctx, bb, &builder, size, convert (ctx, LLVMConstInt (IntPtrType (), ins->inst_imm, FALSE), t), convert (ctx, addr, LLVMPointerType (t, 0)), base, is_volatile);
                        break;
                }
 
                case OP_CHECK_THIS:
-                       emit_load (ctx, bb, &builder, sizeof (gpointer), convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), "", TRUE);
+                       emit_load_general (ctx, bb, &builder, sizeof (gpointer), convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), lhs, "", TRUE, LLVM_BARRIER_NONE);
                        break;
                case OP_OUTARG_VTRETADDR:
                        break;
@@ -5236,6 +5252,19 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        ji = mono_aot_patch_info_dup (tmp_ji);
                        g_free (tmp_ji);
 
+                       if (ji->type == MONO_PATCH_INFO_ICALL_ADDR) {
+                               char *symbol = mono_aot_get_direct_call_symbol (MONO_PATCH_INFO_ICALL_ADDR_CALL, ji->data.target);
+                               if (symbol) {
+                                       /*
+                                        * Avoid emitting a got entry for these since the method is directly called, and it might not be
+                                        * resolvable at runtime using dlsym ().
+                                        */
+                                       g_free (symbol);
+                                       values [ins->dreg] = LLVMConstInt (IntPtrType (), 0, FALSE);
+                                       break;
+                               }
+                       }
+
                        ji->next = cfg->patch_info;
                        cfg->patch_info = ji;
                                   
@@ -5423,9 +5452,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_ATOMIC_LOAD_U8:
                case OP_ATOMIC_LOAD_R4:
                case OP_ATOMIC_LOAD_R8: {
-                       set_failure (ctx, "atomic mono.load intrinsic");
-                       break;
-#if 0
+#if LLVM_API_VERSION > 100
                        int size;
                        gboolean sext, zext;
                        LLVMTypeRef t;
@@ -5447,13 +5474,16 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        addr = convert (ctx, addr, LLVMPointerType (t, 0));
 
-                       values [ins->dreg] = emit_load_general (ctx, bb, &builder, size, addr, dname, is_volatile, barrier);
+                       values [ins->dreg] = emit_load_general (ctx, bb, &builder, size, addr, lhs, dname, is_volatile, barrier);
 
                        if (sext)
                                values [ins->dreg] = LLVMBuildSExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
                        else if (zext)
                                values [ins->dreg] = LLVMBuildZExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
                        break;
+#else
+                       set_failure (ctx, "atomic mono.load intrinsic");
+                       break;
 #endif
                }
                case OP_ATOMIC_STORE_I1:
@@ -5466,15 +5496,19 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_ATOMIC_STORE_U8:
                case OP_ATOMIC_STORE_R4:
                case OP_ATOMIC_STORE_R8: {
-                       set_failure (ctx, "atomic mono.store intrinsic");
-                       break;
-#if 0
                        int size;
                        gboolean sext, zext;
                        LLVMTypeRef t;
                        gboolean is_volatile = (ins->flags & MONO_INST_FAULT);
                        BarrierKind barrier = (BarrierKind) ins->backend.memory_barrier_kind;
-                       LLVMValueRef index, addr, value;
+                       LLVMValueRef index, addr, value, base;
+
+#if LLVM_API_VERSION < 100
+                       if (!cfg->llvm_only) {
+                               set_failure (ctx, "atomic mono.store intrinsic");
+                               break;
+                       }
+#endif
 
                        if (!values [ins->inst_destbasereg]) {
                            set_failure (ctx, "inst_destbasereg");
@@ -5483,13 +5517,13 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        t = load_store_to_llvm_type (ins->opcode, &size, &sext, &zext);
 
+                       base = values [ins->inst_destbasereg];
                        index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);
-                       addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
+                       addr = LLVMBuildGEP (builder, convert (ctx, base, LLVMPointerType (t, 0)), &index, 1, "");
                        value = convert (ctx, values [ins->sreg1], t);
 
-                       emit_store_general (ctx, bb, &builder, size, value, addr, is_volatile, barrier);
+                       emit_store_general (ctx, bb, &builder, size, value, addr, base, is_volatile, barrier);
                        break;
-#endif
                }
                case OP_RELAXED_NOP: {
 #if defined(TARGET_AMD64) || defined(TARGET_X86)
@@ -5525,7 +5559,11 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        break;
                }
                case OP_TLS_GET_REG: {
-#if defined(TARGET_AMD64) && defined(TARGET_OSX)
+#if defined(TARGET_AMD64) && defined(__linux__)
+                       // 257 == FS segment register
+                       LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 257);
+                       values [ins->dreg] = LLVMBuildLoad (builder, LLVMBuildIntToPtr (builder, convert (ctx, lhs, LLVMInt64Type ()), ptrtype, ""), "");
+#elif defined(TARGET_AMD64) && defined(TARGET_OSX)
                        /* See emit_tls_get_reg () */
                        // 256 == GS segment register
                        LLVMTypeRef ptrtype = LLVMPointerType (IntPtrType (), 256);
@@ -5549,6 +5587,43 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 #endif
                        break;
                }
+               case OP_GC_SAFE_POINT: {
+                       LLVMValueRef val, cmp, callee;
+                       LLVMBasicBlockRef poll_bb, cont_bb;
+                       static LLVMTypeRef sig;
+                       const char *icall_name = "mono_threads_state_poll";
+
+                       if (!sig)
+                               sig = LLVMFunctionType0 (LLVMVoidType (), FALSE);
+
+                       /*
+                        * if (!*sreg1)
+                        *   mono_threads_state_poll ();
+                        * FIXME: Use a preserveall wrapper
+                        */
+                       val = mono_llvm_build_load (builder, convert (ctx, lhs, LLVMPointerType (IntPtrType (), 0)), "", TRUE);
+                       cmp = LLVMBuildICmp (builder, LLVMIntEQ, val, LLVMConstNull (LLVMTypeOf (val)), "");
+                       poll_bb = gen_bb (ctx, "POLL_BB");
+                       cont_bb = gen_bb (ctx, "CONT_BB");
+                       LLVMBuildCondBr (builder, cmp, cont_bb, poll_bb);
+
+                       ctx->builder = builder = create_builder (ctx);
+                       LLVMPositionBuilderAtEnd (builder, poll_bb);
+
+                       if (ctx->cfg->compile_aot) {
+                               callee = get_callee (ctx, sig, MONO_PATCH_INFO_INTERNAL_METHOD, icall_name);
+                       } else {
+                               gpointer target = resolve_patch (ctx->cfg, MONO_PATCH_INFO_INTERNAL_METHOD, icall_name);
+                               callee = emit_jit_callee (ctx, icall_name, sig, target);
+                       }
+                       LLVMBuildCall (builder, callee, NULL, 0, "");
+                       LLVMBuildBr (builder, cont_bb);
+
+                       ctx->builder = builder = create_builder (ctx);
+                       LLVMPositionBuilderAtEnd (builder, cont_bb);
+                       ctx->bblocks [bb->block_num].end_bblock = cont_bb;
+                       break;
+               }
 
                        /*
                         * Overflow opcodes.
@@ -5559,14 +5634,12 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_ISUB_OVF_UN:
                case OP_IMUL_OVF:
                case OP_IMUL_OVF_UN:
-#if SIZEOF_VOID_P == 8
                case OP_LADD_OVF:
                case OP_LADD_OVF_UN:
                case OP_LSUB_OVF:
                case OP_LSUB_OVF_UN:
                case OP_LMUL_OVF:
                case OP_LMUL_OVF_UN:
-#endif
                        {
                                LLVMValueRef args [2], val, ovf, func;
 
@@ -5716,6 +5789,38 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        }
                        break;
                }
+               case OP_OBJC_GET_SELECTOR: {
+                       const char *name = (const char*)ins->inst_p0;
+                       LLVMValueRef var;
+
+                       if (!ctx->module->objc_selector_to_var)
+                               ctx->module->objc_selector_to_var = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+                       var = g_hash_table_lookup (ctx->module->objc_selector_to_var, name);
+                       if (!var) {
+                               LLVMValueRef indexes [16];
+
+                               LLVMValueRef name_var = LLVMAddGlobal (ctx->lmodule, LLVMArrayType (LLVMInt8Type (), strlen (name) + 1), "@OBJC_METH_VAR_NAME");
+                               LLVMSetInitializer (name_var, mono_llvm_create_constant_data_array ((const uint8_t*)name, strlen (name) + 1));
+                               LLVMSetLinkage (name_var, LLVMPrivateLinkage);
+                               LLVMSetSection (name_var, "__TEXT,__objc_methname,cstring_literals");
+
+                               LLVMValueRef ref_var = LLVMAddGlobal (ctx->lmodule, LLVMPointerType (LLVMInt8Type (), 0), "@OBJC_SELECTOR_REFERENCES");
+
+                               indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, 0);
+                               indexes [1] = LLVMConstInt (LLVMInt32Type (), 0, 0);
+                               LLVMSetInitializer (ref_var, LLVMConstGEP (name_var, indexes, 2));
+                               LLVMSetLinkage (ref_var, LLVMPrivateLinkage);
+                               LLVMSetExternallyInitialized (ref_var, TRUE);
+                               LLVMSetSection (ref_var, "__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
+                               LLVMSetAlignment (ref_var, sizeof (mgreg_t));
+
+                               g_hash_table_insert (ctx->module->objc_selector_to_var, g_strdup (name), ref_var);
+                               var = ref_var;
+                       }
+
+                       values [ins->dreg] = LLVMBuildLoad (builder, var, "");
+                       break;
+               }
 
                        /* 
                         * SIMD
@@ -6606,7 +6711,10 @@ mono_llvm_emit_method (MonoCompile *cfg)
        ctx->is_linkonce = is_linkonce;
 
 #if LLVM_API_VERSION > 100
-       ctx->lmodule = LLVMModuleCreateWithName ("jit-module");
+       if (cfg->compile_aot)
+               ctx->lmodule = ctx->module->lmodule;
+       else
+               ctx->lmodule = LLVMModuleCreateWithName ("jit-module");
 #else
        ctx->lmodule = ctx->module->lmodule;
 #endif
@@ -6779,6 +6887,7 @@ emit_method_inner (EmitContext *ctx)
        names = g_new (char *, sig->param_count);
        mono_method_get_param_names (cfg->method, (const char **) names);
 
+       /* Set parameter names/attributes */
        for (i = 0; i < sig->param_count; ++i) {
                LLVMArgInfo *ainfo = &linfo->args [i + sig->hasthis];
                char *name;
@@ -6791,6 +6900,9 @@ emit_method_inner (EmitContext *ctx)
                        g_free (name);
                }
 
+               if (ainfo->storage == LLVMArgVtypeInReg && ainfo->pair_storage [0] == LLVMArgNone && ainfo->pair_storage [1] == LLVMArgNone)
+                       continue;
+
                values [cfg->args [i + sig->hasthis]->dreg] = LLVMGetParam (method, pindex);
                if (ainfo->storage == LLVMArgGsharedvtFixed || ainfo->storage == LLVMArgGsharedvtFixedVtype) {
                        if (names [i] && names [i][0] != '\0')
@@ -7062,6 +7174,12 @@ emit_method_inner (EmitContext *ctx)
 
                // FIXME: beforefieldinit
                if (ctx->has_got_access || mono_class_get_cctor (cfg->method->klass)) {
+                       /*
+                        * linkonce methods shouldn't have initialization,
+                        * because they might belong to assemblies which
+                        * haven't been loaded yet.
+                        */
+                       g_assert (!ctx->is_linkonce);
                        emit_init_method (ctx);
                } else {
                        LLVMBuildBr (ctx->builder, ctx->inited_bb);
@@ -7095,12 +7213,15 @@ emit_method_inner (EmitContext *ctx)
        if (cfg->compile_aot && !cfg->llvm_only)
                mark_as_used (ctx->module, method);
 
-       if (cfg->compile_aot && !cfg->llvm_only) {
+       if (!cfg->llvm_only) {
                LLVMValueRef md_args [16];
                LLVMValueRef md_node;
                int method_index;
 
-               method_index = mono_aot_get_method_index (cfg->orig_method);
+               if (cfg->compile_aot)
+                       method_index = mono_aot_get_method_index (cfg->orig_method);
+               else
+                       method_index = 1;
                md_args [0] = LLVMMDString (ctx->method_name, strlen (ctx->method_name));
                md_args [1] = LLVMConstInt (LLVMInt32Type (), method_index, FALSE);
                md_node = LLVMMDNode (md_args, 2);
@@ -7447,11 +7568,12 @@ decode_llvm_eh_info (EmitContext *ctx, gpointer eh_frame)
        p += 4;
        table = (gint32*)p;
 
-       g_assert (fde_count == 1);
+       g_assert (fde_count <= 2);
 
-       /* The only table entry */
+       /* The first entry is the real method */
+       g_assert (table [0] == 1);
        fde_offset = table [1];
-       table += 2;
+       table += fde_count * 2;
        /* Extra entry */
        cfg->code_len = table [0];
        fde_len = table [1] - fde_offset;
@@ -7715,7 +7837,9 @@ static void
 add_intrinsic (LLVMModuleRef module, int id)
 {
        const char *name;
+#if defined(TARGET_AMD64) || defined(TARGET_X86)
        LLVMTypeRef ret_type, arg_types [16];
+#endif
 
        name = g_hash_table_lookup (intrins_id_to_name, GINT_TO_POINTER (id));
        g_assert (name);
@@ -8556,6 +8680,9 @@ mono_llvm_emit_aot_module (const char *filename, const char *cu_name)
                while (g_hash_table_iter_next (&iter, (void**)&method, (void**)&callers)) {
                        LLVMValueRef lmethod;
 
+                       if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+                               continue;
+
                        lmethod = (LLVMValueRef)g_hash_table_lookup (module->method_to_lmethod, method);
                        if (lmethod) {
                                for (l = callers; l; l = l->next) {
@@ -8593,6 +8720,7 @@ mono_llvm_emit_aot_module (const char *filename, const char *cu_name)
                char *verifier_err;
 
                if (LLVMVerifyModule (module->lmodule, LLVMReturnStatusAction, &verifier_err)) {
+                       printf ("%s\n", verifier_err);
                        g_assert_not_reached ();
                }
        }