2010-06-02 Zoltan Varga <vargaz@gmail.com>
authorZoltan Varga <vargaz@gmail.com>
Wed, 2 Jun 2010 02:23:28 +0000 (02:23 -0000)
committerZoltan Varga <vargaz@gmail.com>
Wed, 2 Jun 2010 02:23:28 +0000 (02:23 -0000)
* method-to-ir.c (set_rgctx_arg): New helper function to remove some duplicate code.
Use a separate generic class init trampoline for llvm, since it needs a different
signature.

* unwind.c (mono_unwind_decode_fde): Make this decode the mono specific LSDA which
includes the location of this/rgctx.

* mini-llvm.c aot-runtime.c: Enable generic sharing for llvm if using the LLVM mono
branch.

svn path=/trunk/mono/; revision=158309

mono/mini/ChangeLog
mono/mini/aot-runtime.c
mono/mini/method-to-ir.c
mono/mini/mini-llvm-cpp.cpp
mono/mini/mini-llvm-cpp.h
mono/mini/mini-llvm.c
mono/mini/mini-unwind.h
mono/mini/mini.c
mono/mini/mini.h
mono/mini/unwind.c

index 3aabf7a6c5edd0f97e580394bcd05e135ab74a5b..045ba355f62bf34a30ba6cbb1201f6095679d56f 100755 (executable)
@@ -1,3 +1,15 @@
+2010-06-02  Zoltan Varga  <vargaz@gmail.com>
+
+       * method-to-ir.c (set_rgctx_arg): New helper function to remove some duplicate code.
+       Use a separate generic class init trampoline for llvm, since it needs a different
+       signature.
+
+       * unwind.c (mono_unwind_decode_fde): Make this decode the mono specific LSDA which
+       includes the location of this/rgctx.
+
+       * mini-llvm.c aot-runtime.c: Enable generic sharing for llvm if using the LLVM mono
+       branch.
+
 2010-06-01  Zoltan Varga  <vargaz@gmail.com>
 
        * mini.c (mini_method_compile): Enable llvm+exceptions on LLVM SVN.
index cf2e59613a2f7bfa3988faadf8b969a8783ed037..3c2fa2993687179c25a5175018968e8e7837af0e 100644 (file)
@@ -1523,7 +1523,7 @@ decode_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
        guint32 eh_frame_ptr;
        int fde_count;
        gint32 *table;
-       int i, pos, left, right, offset, offset1, offset2;
+       int i, pos, left, right, offset, offset1, offset2, this_reg, this_offset;
        guint32 unw_len, code_len;
        MonoJitExceptionInfo *ei;
        guint32 ei_len;
@@ -1575,7 +1575,7 @@ decode_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
 
        eh_frame = amodule->eh_frame_hdr + table [(pos * 2) + 1];
 
-       unwind_info = mono_unwind_decode_fde (eh_frame, &unw_len, &code_len, &ei, &ei_len, &type_info);
+       unwind_info = mono_unwind_decode_fde (eh_frame, &unw_len, &code_len, &ei, &ei_len, &type_info, &this_reg, &this_offset);
 
        /*
         * LLVM might represent one IL region with multiple regions, so have to
index b3fe582ce9c8ee5be508cb61593781f571cb7c13..21baf62d00ba4f4c1d61cf288c15ead57c6c8b3b 100644 (file)
@@ -115,6 +115,7 @@ void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, Mono
 extern MonoMethodSignature *helper_sig_class_init_trampoline;
 extern MonoMethodSignature *helper_sig_domain_get;
 extern MonoMethodSignature *helper_sig_generic_class_init_trampoline;
+extern MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm;
 extern MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
 extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
 extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
@@ -2098,6 +2099,10 @@ emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
                MONO_ADD_INS (cfg->cbb, ins);
        }
 
+#ifdef ENABLE_LLVM
+       if (COMPILE_LLVM (cfg))
+               call->imt_arg_reg = method_reg;
+#endif
        mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
 #else
        mono_arch_emit_imt_argument (cfg, call, imt_arg);
@@ -2226,10 +2231,24 @@ mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, Mo
        return (MonoInst*)call;
 }
 
+static void
+set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
+{
+#ifdef MONO_ARCH_RGCTX_REG
+       mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
+       cfg->uses_rgctx_reg = TRUE;
+       call->rgctx_reg = TRUE;
+#ifdef ENABLE_LLVM
+       call->rgctx_arg_reg = rgctx_reg;
+#endif
+#else
+       NOT_IMPLEMENTED;
+#endif
+}      
+
 inline static MonoInst*
 mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg)
 {
-#ifdef MONO_ARCH_RGCTX_REG
        MonoCallInst *call;
        int rgctx_reg = -1;
 
@@ -2238,16 +2257,9 @@ mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **ar
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
        }
        call = (MonoCallInst*)mono_emit_calli (cfg, sig, args, addr);
-       if (rgctx_arg) {
-               mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
-               cfg->uses_rgctx_reg = TRUE;
-               call->rgctx_reg = TRUE;
-       }
+       if (rgctx_arg)
+               set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
        return (MonoInst*)call;
-#else
-       g_assert_not_reached ();
-       return NULL;
-#endif
 }
 
 static MonoInst*
@@ -2402,32 +2414,19 @@ static MonoInst*
 mono_emit_rgctx_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
                MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *vtable_arg)
 {
-#ifdef MONO_ARCH_RGCTX_REG
        int rgctx_reg = 0;
-#endif
        MonoInst *ins;
        MonoCallInst *call;
 
        if (vtable_arg) {
-#ifdef MONO_ARCH_RGCTX_REG
                rgctx_reg = mono_alloc_preg (cfg);
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
-#else
-               NOT_IMPLEMENTED;
-#endif
        }
        ins = mono_emit_method_call_full (cfg, method, sig, args, this, imt_arg);
 
        call = (MonoCallInst*)ins;
-       if (vtable_arg) {
-#ifdef MONO_ARCH_RGCTX_REG
-               mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
-               cfg->uses_rgctx_reg = TRUE;
-               call->rgctx_reg = TRUE;
-#else
-               NOT_IMPLEMENTED;
-#endif
-       }
+       if (vtable_arg)
+               set_rgctx_arg (cfg, call, rgctx_reg, vtable_arg);
 
        return ins;
 }
@@ -2793,7 +2792,10 @@ emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
                EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
        }
 
-       call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
+       if (COMPILE_LLVM (cfg))
+               call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
+       else
+               call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
 #ifdef MONO_ARCH_VTABLE_REG
        mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
        cfg->uses_vtable_reg = TRUE;
@@ -6491,19 +6493,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                INLINE_FAILURE;
 
                                if (vtable_arg) {
-#ifdef MONO_ARCH_RGCTX_REG
                                        MonoCallInst *call;
                                        int rgctx_reg = mono_alloc_preg (cfg);
 
                                        MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
                                        ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
                                        call = (MonoCallInst*)ins;
-                                       mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
-                                       cfg->uses_rgctx_reg = TRUE;
-                                       call->rgctx_reg = TRUE;
-#else
-                                       NOT_IMPLEMENTED;
-#endif
+                                       set_rgctx_arg (cfg, call, rgctx_reg, vtable_arg);
                                } else {
                                        if (addr->opcode == OP_AOTCONST && addr->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
                                                /* 
@@ -8116,28 +8112,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        depth, field->offset);
                                */
 
-                               if (mono_class_needs_cctor_run (klass, method)) {
-                                       MonoCallInst *call;
-                                       MonoInst *vtable;
-
-                                       vtable = emit_get_rgctx_klass (cfg, context_used,
-                                               klass, MONO_RGCTX_INFO_VTABLE);
-
-                                       // FIXME: This doesn't work since it tries to pass the argument
-                                       // in the normal way, instead of using MONO_ARCH_VTABLE_REG
-                                       /* 
-                                        * The vtable pointer is always passed in a register regardless of
-                                        * the calling convention, so assign it manually, and make a call
-                                        * using a signature without parameters.
-                                        */                                     
-                                       call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable);
-#ifdef MONO_ARCH_VTABLE_REG
-                                       mono_call_inst_add_outarg_reg (cfg, call, vtable->dreg, MONO_ARCH_VTABLE_REG, FALSE);
-                                       cfg->uses_vtable_reg = TRUE;
-#else
-                                       NOT_IMPLEMENTED;
-#endif
-                               }
+                               if (mono_class_needs_cctor_run (klass, method))
+                                       emit_generic_class_init (cfg, klass);
 
                                /*
                                 * The pointer we're computing here is
index 1374a58784fedab3a83c0999aee3a70726a42f28..6ef009c31dd88dc0241fa4ec694863eed40e5049 100644 (file)
@@ -28,6 +28,7 @@
 #include <llvm/ExecutionEngine/JITEventListener.h>
 #include <llvm/Target/TargetOptions.h>
 #include <llvm/Target/TargetData.h>
+#include <llvm/Target/TargetRegisterInfo.h>
 #include <llvm/Analysis/Verifier.h>
 #include <llvm/Transforms/Scalar.h>
 #include <llvm/Support/CommandLine.h>
@@ -36,6 +37,8 @@
 #include <llvm/CodeGen/Passes.h>
 #include <llvm/CodeGen/MachineFunctionPass.h>
 #include <llvm/CodeGen/MachineFunction.h>
+#include <llvm/CodeGen/MachineFrameInfo.h>
+#include <llvm/CodeGen/MonoMachineFunctionInfo.h>
 //#include <llvm/LinkAllPasses.h>
 
 #include "llvm-c/Core.h"
@@ -55,7 +58,6 @@ private:
 public:
        /* Callbacks installed by mono */
        AllocCodeMemoryCb *alloc_cb;
-       FunctionEmittedCb *emitted_cb;
 
        MonoJITMemoryManager ();
        ~MonoJITMemoryManager ();
@@ -164,7 +166,6 @@ void
 MonoJITMemoryManager::endFunctionBody(const Function *F, unsigned char *FunctionStart,
                                  unsigned char *FunctionEnd)
 {
-       emitted_cb (wrap (F), FunctionStart, FunctionEnd);
 }
 
 unsigned char *
@@ -244,6 +245,13 @@ mono_llvm_build_aligned_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
        return wrap(ins);
 }
 
+LLVMValueRef 
+mono_llvm_build_store (LLVMBuilderRef builder, LLVMValueRef Val, LLVMValueRef PointerVal,
+                                         gboolean is_volatile)
+{
+       return wrap(unwrap(builder)->CreateStore(unwrap(Val), unwrap(PointerVal), is_volatile));
+}
+
 void
 mono_llvm_replace_uses_of (LLVMValueRef var, LLVMValueRef v)
 {
@@ -255,6 +263,14 @@ static cl::list<const PassInfo*, bool, PassNameParser>
 PassList(cl::desc("Optimizations available:"));
 
 class MonoJITEventListener : public JITEventListener {
+
+public:
+       FunctionEmittedCb *emitted_cb;
+
+       MonoJITEventListener (FunctionEmittedCb *cb) {
+               emitted_cb = cb;
+       }
+
        virtual void NotifyFunctionEmitted(const Function &F,
                                                                           void *Code, size_t Size,
                                                                           const EmittedFunctionDetails &Details) {
@@ -273,10 +289,15 @@ class MonoJITEventListener : public JITEventListener {
                 *
                 */
                //#if defined(TARGET_X86) || defined(TARGET_AMD64)
+#ifndef LLVM_MONO_BRANCH
+               /* The LLVM mono branch contains a workaround, so this is not needed */
                if (Details.MF->getTarget ().getCodeModel () == CodeModel::Large) {
                        Details.MF->getTarget ().setCodeModel (CodeModel::Default);
                }
+#endif
                //#endif
+
+               emitted_cb (wrap (&F), Code, (char*)Code + Size);
        }
 };
 
@@ -292,7 +313,6 @@ mono_llvm_create_ee (LLVMModuleProviderRef MP, AllocCodeMemoryCb *alloc_cb, Func
 
   mono_mm = new MonoJITMemoryManager ();
   mono_mm->alloc_cb = alloc_cb;
-  mono_mm->emitted_cb = emitted_cb;
 
 #if LLVM_MAJOR_VERSION == 2 && LLVM_MINOR_VERSION < 8
    DwarfExceptionHandling = true;
@@ -308,7 +328,7 @@ mono_llvm_create_ee (LLVMModuleProviderRef MP, AllocCodeMemoryCb *alloc_cb, Func
          g_assert_not_reached ();
   }
   EE->InstallExceptionTableRegister (exception_cb);
-  EE->RegisterJITEventListener (new MonoJITEventListener ());
+  EE->RegisterJITEventListener (new MonoJITEventListener (emitted_cb));
 
   fpm = new FunctionPassManager (unwrap (MP));
 
index 18462f6e32637d6b00121f05743f9353039fcbd9..8bb8111a305f24e5d7301051a46f3a060c0c1b2b 100644 (file)
@@ -46,6 +46,10 @@ LLVMValueRef
 mono_llvm_build_aligned_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
                                                          const char *Name, gboolean is_volatile, int alignment);
 
+LLVMValueRef 
+mono_llvm_build_store (LLVMBuilderRef builder, LLVMValueRef Val, LLVMValueRef PointerVal,
+                                          gboolean is_volatile);
+
 void
 mono_llvm_replace_uses_of (LLVMValueRef var, LLVMValueRef v);
 
index 6084390650681ba9608c30c7e578ff24b7793acf..9257c6006c6185e0d9c01cec53f0a9b854aee502 100644 (file)
@@ -74,6 +74,7 @@ typedef struct {
        GHashTable *region_to_handler;
        LLVMBuilderRef alloca_builder;
        LLVMValueRef last_alloca;
+       LLVMValueRef rgctx_arg;
 
        char temp_name [32];
 } EmitContext;
@@ -850,6 +851,14 @@ sig_to_llvm_sig (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo *cinfo
 
        param_types = g_new0 (LLVMTypeRef, (sig->param_count * 2) + 2);
        pindex = 0;
+       if (cinfo && cinfo->rgctx_arg) {
+               param_types [pindex] = IntPtrType ();
+               pindex ++;
+       }
+       if (cinfo && cinfo->imt_arg) {
+               param_types [pindex] = IntPtrType ();
+               pindex ++;
+       }
        if (vretaddr) {
                ret_type = LLVMVoidType ();
                param_types [pindex ++] = IntPtrType ();
@@ -1370,6 +1379,45 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder, int *pindexes)
                if (!MONO_TYPE_ISSTRUCT (sig->params [i]))
                        emit_volatile_store (ctx, cfg->args [i + sig->hasthis]->dreg);
 
+       if (sig->hasthis && !cfg->rgctx_var) {
+#if LLVM_CHECK_VERSION (2, 8)
+               LLVMValueRef this_alloc, md_arg;
+               int md_kind;
+
+               /*
+                * The exception handling code needs the location where the this argument was
+                * stored for gshared methods. We create a separate alloca to hold it, and mark it
+                * with the "mono.this" custom metadata to tell llvm that it needs to save its
+                * location into the LSDA.
+                */
+               // FIXME: Do this for gshared only
+               this_alloc = mono_llvm_build_alloca (builder, IntPtrType (), LLVMConstInt (LLVMInt32Type (), 1, FALSE), 0, "");
+               /* This volatile store will keep the alloca alive */
+               mono_llvm_build_store (builder, ctx->values [cfg->args [0]->dreg], this_alloc, TRUE);
+
+               md_kind = LLVMGetMDKindID ("mono.this", strlen ("mono.this"));
+               md_arg = LLVMMDString ("this", 4);
+               LLVMSetMetadata (this_alloc, md_kind, LLVMMDNode (&md_arg, 1));
+#endif
+       }
+
+       if (cfg->rgctx_var) {
+               LLVMValueRef rgctx_alloc, store, md_arg;
+               int md_kind;
+
+               /*
+                * We handle the rgctx arg similarly to the this pointer.
+                */
+               g_assert (ctx->addresses [cfg->rgctx_var->dreg]);
+               rgctx_alloc = ctx->addresses [cfg->rgctx_var->dreg];
+               /* This volatile store will keep the alloca alive */
+               store = mono_llvm_build_store (builder, ctx->rgctx_arg, rgctx_alloc, TRUE);
+
+               md_kind = LLVMGetMDKindID ("mono.this", strlen ("mono.this"));
+               md_arg = LLVMMDString ("this", 4);
+               LLVMSetMetadata (rgctx_alloc, md_kind, LLVMMDNode (&md_arg, 1));
+       }
+
        /*
         * For finally clauses, create an indicator variable telling OP_ENDFINALLY whenever
         * it needs to continue normally, or return back to the exception handling system.
@@ -1504,12 +1552,20 @@ mono_llvm_emit_method (MonoCompile *cfg)
        ctx->linfo = linfo;
        CHECK_FAILURE (ctx);
 
+       if (cfg->rgctx_var) {
+               if (IS_LLVM_MONO_BRANCH)
+                       linfo->rgctx_arg = TRUE;
+               else
+                       LLVM_FAILURE (ctx, "rgctx arg");
+       }
        method_type = sig_to_llvm_sig (ctx, sig, linfo);
        CHECK_FAILURE (ctx);
 
        method = LLVMAddFunction (module, method_name, method_type);
        ctx->lmethod = method;
 
+       if (linfo->rgctx_arg)
+               LLVMSetFunctionCallConv (method, LLVMMono1CallConv);
        LLVMSetLinkage (method, LLVMPrivateLinkage);
 
        if (cfg->method->save_lmf)
@@ -1531,6 +1587,16 @@ mono_llvm_emit_method (MonoCompile *cfg)
         */
        pindexes = g_new0 (int, sig->param_count);
        pindex = 0;
+       if (linfo->rgctx_arg) {
+               ctx->rgctx_arg = LLVMGetParam (method, pindex);
+               /*
+                * We mark the rgctx parameter with the inreg attribute, which is mapped to
+                * MONO_ARCH_RGCTX_REG in the Mono calling convention in llvm, i.e.
+                * CC_X86_64_Mono in X86CallingConv.td.
+                */
+               LLVMAddAttribute (ctx->rgctx_arg, LLVMInRegAttribute);
+               pindex ++;
+       }
        if (cfg->vret_addr) {
                values [cfg->vret_addr->dreg] = LLVMGetParam (method, pindex);
                pindex ++;
@@ -2587,7 +2653,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                        index = LLVMConstInt (LLVMInt32Type (), ins->inst_offset / size, FALSE);                                
                                        addr = LLVMBuildGEP (builder, convert (ctx, values [ins->inst_destbasereg], LLVMPointerType (t, 0)), &index, 1, "");
                                }
-                               LLVMBuildStore (builder, convert (ctx, LLVMConstInt (LLVMInt32Type (), ins->inst_imm, FALSE), t), addr);
+                               LLVMBuildStore (builder, convert (ctx, LLVMConstInt (t, ins->inst_imm, FALSE), t), addr);
                                break;
                        }
 
@@ -2627,7 +2693,14 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                if (call->signature->call_convention != MONO_CALL_DEFAULT)
                                        LLVM_FAILURE (ctx, "non-default callconv");
 
+                               if (call->rgctx_arg_reg && !IS_LLVM_MONO_BRANCH)
+                                       LLVM_FAILURE (ctx, "rgctx reg in call");
+
                                cinfo = call->cinfo;
+                               if (call->rgctx_arg_reg)
+                                       cinfo->rgctx_arg = TRUE;
+                               if (call->imt_arg_reg)
+                                       cinfo->imt_arg = TRUE;
 
                                vretaddr = cinfo && cinfo->ret.storage == LLVMArgVtypeRetAddr;
 
@@ -2637,8 +2710,6 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                virtual = (ins->opcode == OP_VOIDCALL_MEMBASE || ins->opcode == OP_CALL_MEMBASE || ins->opcode == OP_VCALL_MEMBASE || ins->opcode == OP_LCALL_MEMBASE || ins->opcode == OP_FCALL_MEMBASE);
                                calli = (ins->opcode == OP_VOIDCALL_REG || ins->opcode == OP_CALL_REG || ins->opcode == OP_VCALL_REG || ins->opcode == OP_LCALL_REG || ins->opcode == OP_FCALL_REG);
 
-                               pindexes = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + 2) * sizeof (guint32));
-
                                /* FIXME: Avoid creating duplicate methods */
 
                                if (ins->flags & MONO_INST_HAS_METHOD) {
@@ -2729,7 +2800,11 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                        // generated by LLVM
                                        //LLVM_FAILURE (ctx, "virtual call");
 
-                                       if (call->method && call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                                       /*
+                                        * When using the llvm mono branch, we can support IMT directly, otherwise
+                                        * we need to call a trampoline.
+                                        */
+                                       if (call->method && call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE && !IS_LLVM_MONO_BRANCH) {
 #ifdef MONO_ARCH_HAVE_LLVM_IMT_TRAMPOLINE
                                                if (cfg->compile_aot) {
                                                        MonoJumpInfoImtTramp *imt_tramp = g_new0 (MonoJumpInfoImtTramp, 1);
@@ -2759,10 +2834,18 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                /* 
                                 * Collect and convert arguments
                                 */
-
-                               args = alloca (sizeof (LLVMValueRef) * ((sig->param_count * 2) + sig->hasthis + vretaddr));
+                               pindexes = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + 2) * sizeof (guint32));
+                               args = alloca (sizeof (LLVMValueRef) * ((sig->param_count * 2) + sig->hasthis + vretaddr + call->rgctx_reg));
                                l = call->out_ireg_args;
                                pindex = 0;
+
+                               if (IS_LLVM_MONO_BRANCH) {
+                                       if (call->rgctx_arg_reg)
+                                               args [pindex ++] = values [call->rgctx_arg_reg];
+                                       if (call->imt_arg_reg)
+                                               args [pindex ++] = values [call->imt_arg_reg];
+                               }
+
                                if (vretaddr) {
                                        if (!addresses [call->inst.dreg])
                                                addresses [call->inst.dreg] = build_alloca (ctx, sig->ret);
@@ -2817,6 +2900,21 @@ mono_llvm_emit_method (MonoCompile *cfg)
 
                                lcall = emit_call (ctx, bb, &builder, callee, args, pindex);
 
+#ifdef LLVM_MONO_BRANCH
+                               /*
+                                * Modify cconv and parameter attributes to pass rgctx/imt correctly.
+                                */
+                               if (call->rgctx_arg_reg)
+                                       LLVMSetInstructionCallConv (lcall, LLVMMono1CallConv);
+                               else if (call->imt_arg_reg)
+                                       LLVMSetInstructionCallConv (lcall, LLVMMono2CallConv);
+
+                               if (call->rgctx_arg_reg)
+                                       LLVMAddInstrAttribute (lcall, 1, LLVMInRegAttribute);
+                               if (call->imt_arg_reg)
+                                       LLVMAddInstrAttribute (lcall, 1 + (call->rgctx_arg_reg ? 1 : 0), LLVMInRegAttribute);
+#endif
+
                                /* Add byval attributes if needed */
                                for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
                                        LLVMArgInfo *ainfo = call->cinfo ? &call->cinfo->args [i] : NULL;
@@ -2982,7 +3080,7 @@ mono_llvm_emit_method (MonoCompile *cfg)
                                g_assert (ins->inst_offset == 0);
 
                                args [0] = convert (ctx, lhs, LLVMPointerType (LLVMInt64Type (), 0));
-                               args [1] = rhs;
+                               args [1] = convert (ctx, rhs, LLVMInt64Type ());
                                values [ins->dreg] = LLVMBuildCall (builder, LLVMGetNamedFunction (module, "llvm.atomic.swap.i64.p0i64"), args, 2, dname);
                                break;
                        }
@@ -3744,6 +3842,7 @@ exception_cb (void *data)
        MonoJitExceptionInfo *ei;
        guint32 ei_len, i;
        gpointer *type_info;
+       int this_reg, this_offset;
 
        cfg = TlsGetValue (current_cfg_tls_id);
        g_assert (cfg);
@@ -3754,7 +3853,7 @@ exception_cb (void *data)
         * An alternative would be to save it directly, and modify our unwinder to work
         * with it.
         */
-       cfg->encoded_unwind_ops = mono_unwind_decode_fde ((guint8*)data, &cfg->encoded_unwind_ops_len, NULL, &ei, &ei_len, &type_info);
+       cfg->encoded_unwind_ops = mono_unwind_decode_fde ((guint8*)data, &cfg->encoded_unwind_ops_len, NULL, &ei, &ei_len, &type_info, &this_reg, &this_offset);
 
        cfg->llvm_ex_info = mono_mempool_alloc0 (cfg->mempool, ei_len * sizeof (MonoJitExceptionInfo));
        cfg->llvm_ex_info_len = ei_len;
@@ -3767,6 +3866,8 @@ exception_cb (void *data)
                cfg->llvm_ex_info [i].flags = clause->flags;
                cfg->llvm_ex_info [i].data.catch_class = clause->data.catch_class;
        }
+       cfg->llvm_this_reg = this_reg;
+       cfg->llvm_this_offset = this_offset;
 
        g_free (ei);
 }
index e143468fd9dd60218879a0cf8647136dee274629..c99da3c312739249434ac23162e688a39ba3bfd9 100644 (file)
@@ -89,6 +89,9 @@ typedef struct {
 int
 mono_hw_reg_to_dwarf_reg (int reg) MONO_INTERNAL;
 
+int
+mono_dwarf_reg_to_hw_reg (int reg) MONO_INTERNAL;
+
 int
 mono_unwind_get_dwarf_data_align (void) MONO_INTERNAL;
 
@@ -111,7 +114,7 @@ guint32 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len) MO
 
 guint8* mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len) MONO_INTERNAL;
 
-guint8* mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info) MONO_INTERNAL;
+guint8* mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset) MONO_INTERNAL;
 
 GSList* mono_unwind_get_cie_program (void) MONO_INTERNAL;
 
index 53213e08db27050045bd6d7515602180126cc763..5f41555fdf84ce179b4acb5c6e9befbfd3ef2115 100644 (file)
@@ -72,6 +72,7 @@ static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 op
 MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
 MonoMethodSignature *helper_sig_domain_get = NULL;
 MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
+MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm = NULL;
 MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
 MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
 MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
@@ -1343,6 +1344,7 @@ create_helper_signature (void)
        helper_sig_domain_get = mono_create_icall_signature ("ptr");
        helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
        helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
+       helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
        helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
        helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
        helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
@@ -3482,12 +3484,18 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                                mini_method_get_context (method_to_compile)->method_inst ||
                                method_to_compile->klass->valuetype) {
                        inst = cfg->rgctx_var;
-                       g_assert (inst->opcode == OP_REGOFFSET);
+                       if (!COMPILE_LLVM (cfg))
+                               g_assert (inst->opcode == OP_REGOFFSET);
                } else {
                        inst = cfg->args [0];
                }
 
-               if (inst->opcode == OP_REGVAR) {
+               if (COMPILE_LLVM (cfg)) {
+                       g_assert (cfg->llvm_this_reg != -1);
+                       gi->this_in_reg = 0;
+                       gi->this_reg = cfg->llvm_this_reg;
+                       gi->this_offset = cfg->llvm_this_offset;
+               } else if (inst->opcode == OP_REGVAR) {
                        gi->this_in_reg = 1;
                        gi->this_reg = inst->dreg;
                } else {
@@ -3805,9 +3813,19 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
        cfg->method_to_register = method_to_register;
 
+       mono_error_init (&err);
+       sig = mono_method_signature_checked (cfg->method, &err);        
+       if (!sig) {
+               cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+               cfg->exception_message = g_strdup (mono_error_get_message (&err));
+               mono_error_cleanup (&err);
+               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+                       MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
+               return cfg;
+       }
+
        if (cfg->compile_llvm) {
-               /* No way to obtain the location info for 'this' */
-               if (try_generic_shared) {
+               if (try_generic_shared && !IS_LLVM_MONO_BRANCH) {
                        cfg->exception_message = g_strdup ("gshared");
                        cfg->disable_llvm = TRUE;
                }
@@ -3824,17 +3842,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                }
        }
 
-       mono_error_init (&err);
-       sig = mono_method_signature_checked (cfg->method, &err);        
-       if (!sig) {
-               cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
-               cfg->exception_message = g_strdup (mono_error_get_message (&err));
-               mono_error_cleanup (&err);
-               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
-                       MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
-               return cfg;
-       }
-
        header = cfg->header;
        if (!header) {
                MonoLoaderError *error;
index 85640593e382a9358bed09fbc783782eb3a6b89b..8b665054fe057cc03f3a41452d8c732385516d6a 100644 (file)
@@ -80,6 +80,17 @@ typedef gint64 mgreg_t;
 #define LLVM_CHECK_VERSION(major,minor) 0
 #endif
 
+/* 
+ * Whenever we are using mono's LLVM branch.
+ * This can be used in if statements, code which references new definitions from the branch
+ * still needs an #ifdef LLVM_MONO_BRANCH.
+ */
+#ifdef LLVM_MONO_BRANCH
+#define IS_LLVM_MONO_BRANCH 1
+#else
+#define IS_LLVM_MONO_BRANCH 0
+#endif
+
 #define NOT_IMPLEMENTED do { g_assert_not_reached (); } while (0)
 
 /* for 32 bit systems */
@@ -581,6 +592,10 @@ typedef struct {
 
 typedef struct {
        LLVMArgInfo ret;
+       /* Whenever there is an rgctx argument */
+       gboolean rgctx_arg;
+       /* Whenever there is an IMT argument */
+       gboolean imt_arg;
        /* args [0] is for the this argument if it exists */
        LLVMArgInfo args [1];
 } LLVMCallInfo;
@@ -671,6 +686,7 @@ struct MonoCallInst {
        GSList *out_freg_args;
 #ifdef ENABLE_LLVM
        LLVMCallInfo *cinfo;
+       int rgctx_arg_reg, imt_arg_reg;
 #endif
 };
 
@@ -1163,6 +1179,7 @@ typedef struct {
 
        MonoJitExceptionInfo *llvm_ex_info;
        guint32 llvm_ex_info_len;
+       int llvm_this_reg, llvm_this_offset;
 
        GSList *try_block_holes;
 } MonoCompile;
index 1eee23b487f3e804323c4d7385b8eddf32bae887..2b128dedf759eb4e37e800e2134c665be4677679 100644 (file)
@@ -11,6 +11,7 @@
 #include "mini-unwind.h"
 
 #include <mono/utils/mono-counters.h>
+#include <mono/utils/freebsd-dwarf.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/mono-endian.h>
 
@@ -117,7 +118,7 @@ init_reg_map (void)
        dwarf_reg_to_hw_reg_inited = TRUE;
 }
 
-static inline int
+int
 mono_dwarf_reg_to_hw_reg (int reg)
 {
        if (!dwarf_reg_to_hw_reg_inited)
@@ -654,7 +655,7 @@ read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp)
  *   Decode the Language Specific Data Area generated by LLVM.
  */
 static void
-decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info)
+decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
 {
        gint32 ttype_offset, call_site_length;
        gint32 ttype_encoding, call_site_encoding;
@@ -667,9 +668,34 @@ decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32
         */
        p = lsda;
 
-       /* Read @LPStart */
-       g_assert (*p == DW_EH_PE_omit);
-       p ++;
+       if (*p == DW_EH_PE_udata4) {
+               /* This is the modified LSDA generated by the LLVM mono branch */
+               guint32 mono_magic, version;
+               gint32 op, reg, offset;
+
+               p ++;
+               mono_magic = decode_uleb128 (p, &p);
+               g_assert (mono_magic == 0x4d4fef4f);
+               version = decode_uleb128 (p, &p);
+               g_assert (version == 1);
+
+               /* 'this' location */
+               op = *p;
+               g_assert (op == DW_OP_bregx);
+               p ++;
+               reg = decode_uleb128 (p, &p);
+               offset = decode_sleb128 (p, &p);
+
+               *this_reg = mono_dwarf_reg_to_hw_reg (reg);
+               *this_offset = offset;
+       } else {
+               /* Read @LPStart */
+               g_assert (*p == DW_EH_PE_omit);
+               p ++;
+
+               *this_reg = -1;
+               *this_offset = -1;
+       }
 
        /* Read @TType */
        ttype_encoding = *p;
@@ -765,7 +791,7 @@ decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32
  * LSDA.
  */
 guint8*
-mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info)
+mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
 {
        guint8 *p, *cie, *fde_current, *fde_aug, *code, *fde_cfi, *cie_cfi;
        gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len, fde_data_len;
@@ -779,6 +805,9 @@ mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJi
         * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
         */
 
+       *this_reg = -1;
+       *this_offset = -1;
+
        /* Decode FDE */
 
        p = fde;
@@ -879,7 +908,7 @@ mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJi
                if (lsda_offset != 0) {
                        lsda = fde_aug + *(gint32*)fde_aug;
 
-                       decode_lsda (lsda, code, ex_info, ex_info_len, type_info);
+                       decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset);
                }
        }