* 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
+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.
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;
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
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;
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);
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;
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*
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;
}
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;
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) {
/*
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
#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>
#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"
public:
/* Callbacks installed by mono */
AllocCodeMemoryCb *alloc_cb;
- FunctionEmittedCb *emitted_cb;
MonoJITMemoryManager ();
~MonoJITMemoryManager ();
MonoJITMemoryManager::endFunctionBody(const Function *F, unsigned char *FunctionStart,
unsigned char *FunctionEnd)
{
- emitted_cb (wrap (F), FunctionStart, FunctionEnd);
}
unsigned char *
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)
{
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) {
*
*/
//#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);
}
};
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;
g_assert_not_reached ();
}
EE->InstallExceptionTableRegister (exception_cb);
- EE->RegisterJITEventListener (new MonoJITEventListener ());
+ EE->RegisterJITEventListener (new MonoJITEventListener (emitted_cb));
fpm = new FunctionPassManager (unwrap (MP));
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);
GHashTable *region_to_handler;
LLVMBuilderRef alloca_builder;
LLVMValueRef last_alloca;
+ LLVMValueRef rgctx_arg;
char temp_name [32];
} EmitContext;
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 ();
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.
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)
*/
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 ++;
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;
}
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;
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) {
// 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);
/*
* 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);
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;
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;
}
MonoJitExceptionInfo *ei;
guint32 ei_len, i;
gpointer *type_info;
+ int this_reg, this_offset;
cfg = TlsGetValue (current_cfg_tls_id);
g_assert (cfg);
* 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;
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);
}
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;
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;
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;
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");
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 {
}
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;
}
}
}
- 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;
#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 */
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;
GSList *out_freg_args;
#ifdef ENABLE_LLVM
LLVMCallInfo *cinfo;
+ int rgctx_arg_reg, imt_arg_reg;
#endif
};
MonoJitExceptionInfo *llvm_ex_info;
guint32 llvm_ex_info_len;
+ int llvm_this_reg, llvm_this_offset;
GSList *try_block_holes;
} MonoCompile;
#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>
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)
* 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;
*/
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;
* 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;
* 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;
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);
}
}