* mini-arm.c: Always use V5 for passing IMT/RGCTX when running under LLVM.
* method-to-ir.c (emit_imt_argument): Fix LLVM support for architectures
without IMT_REG defined (ARM).
* exceptions-arm.c: Add LLVM throw exception trampolines, add xdebug info for
the trampolines.
svn path=/trunk/mono/; revision=159857
+2010-07-04 Zoltan Varga <vargaz@gmail.com>
+
+ * mini-arm.c: Always use V5 for passing IMT/RGCTX when running under LLVM.
+
+ * method-to-ir.c (emit_imt_argument): Fix LLVM support for architectures
+ without IMT_REG defined (ARM).
+
+ * exceptions-arm.c: Add LLVM throw exception trampolines, add xdebug info for
+ the trampolines.
+
2010-07-03 Zoltan Varga <vargaz@gmail.com>
* mini-llvm.c (process_bb): Disable OP_MEMORY_BARRIER on arm.
}
/**
- * arch_get_throw_exception_generic:
+ * get_throw_trampoline:
*
* Returns a function pointer which can be used to raise
* exceptions. The returned function has the following
*
*/
static gpointer
-mono_arch_get_throw_exception_generic (int size, gboolean corlib, gboolean rethrow, MonoTrampInfo **info, gboolean aot)
+get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, const char *tramp_name, MonoTrampInfo **info, gboolean aot)
{
guint8 *start;
guint8 *code;
code = start = mono_global_codeman_reserve (size);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, start, ARMREG_SP, 0);
+
/* save all the regs on the stack */
ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
ARM_PUSH (code, MONO_ARM_REGSAVE_MASK);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, start, ARMREG_SP, 10 * 4);
+ mono_add_unwind_op_offset (unwind_ops, code, start, ARMREG_LR, -4);
+
/* call throw_exception (exc, ip, sp, int_regs, fp_regs) */
/* caller sp */
ARM_ADD_REG_IMM8 (code, ARMREG_R2, ARMREG_SP, 10 * 4); /* 10 saved regs */
g_assert ((code - start) < size);
mono_arch_flush_icache (start, code - start);
+ mono_save_trampoline_xdebug_info (tramp_name, start, code - start, unwind_ops);
+
if (info)
- *info = mono_tramp_info_create (g_strdup_printf (corlib ? "throw_corlib_exception" : (rethrow ? "rethrow_exception" : "throw_exception")), start, code - start, ji, unwind_ops);
+ *info = mono_tramp_info_create (g_strdup_printf (tramp_name), start, code - start, ji, unwind_ops);
return start;
}
gpointer
mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
{
- return mono_arch_get_throw_exception_generic (132, FALSE, TRUE, info, aot);
+ return get_throw_trampoline (132, FALSE, TRUE, "rethrow_exception", info, aot);
}
/**
gpointer
mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
{
- return mono_arch_get_throw_exception_generic (132, FALSE, FALSE, info, aot);
+ return get_throw_trampoline (132, FALSE, FALSE, "throw_exception", info, aot);
}
/**
gpointer
mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
{
- return mono_arch_get_throw_exception_generic (168, TRUE, FALSE, info, aot);
+ return get_throw_trampoline (168, TRUE, FALSE, "throw_corlib_exception", info, aot);
}
+void
+mono_arch_exceptions_init (void)
+{
+ guint8 *tramp;
+
+ if (mono_aot_only) {
+ } else {
+ /* LLVM uses the normal trampolines, but with a different name */
+ tramp = get_throw_trampoline (168, TRUE, FALSE, "llvm_throw_corlib_exception", NULL, FALSE);
+ mono_register_jit_icall (tramp, "mono_arch_llvm_throw_corlib_exception", NULL, TRUE);
+
+ tramp = get_throw_trampoline (168, TRUE, FALSE, "llvm_throw_corlib_exception_abs", NULL, FALSE);
+ mono_register_jit_icall (tramp, "mono_arch_llvm_throw_corlib_exception_abs", NULL, TRUE);
+
+ /*
+ tramp = get_throw_trampoline (NULL, FALSE, TRUE, TRUE, TRUE, "mono_llvm_resume_unwind_trampoline", FALSE);
+ mono_register_jit_icall (tramp, "mono_llvm_resume_unwind_trampoline", NULL, TRUE);
+ */
+ }
+}
+
/*
* mono_arch_find_jit_info_ext:
*
emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
{
#ifdef MONO_ARCH_IMT_REG
- int method_reg = alloc_preg (cfg);
+ int method_reg;
+#endif
+
+ if (COMPILE_LLVM (cfg)) {
+ method_reg = alloc_preg (cfg);
+
+ if (imt_arg) {
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
+ } else if (cfg->compile_aot) {
+ MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
+ } else {
+ MonoInst *ins;
+ MONO_INST_NEW (cfg, ins, OP_PCONST);
+ ins->inst_p0 = call->method;
+ ins->dreg = method_reg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ }
+
+#ifdef ENABLE_LLVM
+ call->imt_arg_reg = method_reg;
+#endif
+ return;
+ }
+
+#ifdef MONO_ARCH_IMT_REG
+ method_reg = alloc_preg (cfg);
if (imt_arg) {
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
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);
regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V2));
regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V3));
regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V4));
- if (!(cfg->compile_aot || cfg->uses_rgctx_reg))
+ if (!(cfg->compile_aot || cfg->uses_rgctx_reg || COMPILE_LLVM (cfg)))
/* V5 is reserved for passing the vtable/rgctx/IMT method */
regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V5));
/*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V6));*/
cfg->used_int_regs |= 1 << frame_reg;
}
- if (cfg->compile_aot || cfg->uses_rgctx_reg)
+ if (cfg->compile_aot || cfg->uses_rgctx_reg || COMPILE_LLVM (cfg))
/* V5 is reserved for passing the vtable/rgctx/IMT method */
cfg->used_int_regs |= (1 << ARMREG_V5);
mono_call_inst_add_outarg_reg (cfg, call, method_reg, ARMREG_V5, FALSE);
}
- } else if (cfg->generic_context || imt_arg) {
+ } else if (cfg->generic_context || imt_arg || mono_use_llvm) {
/* Always pass in a register for simplicity */
call->dynamic_imt_arg = TRUE;
{
guint32 *code_ptr = (guint32*)code;
code_ptr -= 2;
+
+ if (mono_use_llvm)
+ /* Passed in V5 */
+ return (MonoMethod*)regs [ARMREG_V5];
+
/* The IMT value is stored in the code stream right after the LDC instruction. */
if (!IS_LDR_PC (code_ptr [0])) {
g_warning ("invalid code stream, instruction before IMT value is not a LDC in %s() (code %p value 0: 0x%x -1: 0x%x -2: 0x%x)", __FUNCTION__, code, code_ptr [2], code_ptr [1], code_ptr [0]);
vtable_target = code;
ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
- /* R0 == 0 means we are called from AOT code. In this case, V5 contains the IMT method */
- ARM_CMP_REG_IMM8 (code, ARMREG_R0, 0);
- ARM_MOV_REG_REG_COND (code, ARMREG_R0, ARMREG_V5, ARMCOND_EQ);
+ if (mono_use_llvm) {
+ /* LLVM always passes the IMT method in R5 */
+ ARM_MOV_REG_REG (code, ARMREG_R0, ARMREG_V5);
+ } else {
+ /* R0 == 0 means we are called from AOT code. In this case, V5 contains the IMT method */
+ ARM_CMP_REG_IMM8 (code, ARMREG_R0, 0);
+ ARM_MOV_REG_REG_COND (code, ARMREG_R0, ARMREG_V5, ARMCOND_EQ);
+ }
for (i = 0; i < count; ++i) {
MonoIMTCheckItem *item = imt_entries [i];
#define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
#define MONO_ARCH_HAVE_FIND_JIT_INFO_EXT 1
+#define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
/* ARM doesn't have too many registers, so we have to use a callee saved one */
#define MONO_ARCH_RGCTX_REG ARMREG_V5
#define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->ebp))
#define MONO_CONTEXT_GET_SP(ctx) ((gpointer)((ctx)->esp))
+#define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->regs [0] = (gsize)exc; } while (0)
+
#define MONO_INIT_CONTEXT_FROM_FUNC(ctx,func) do { \
MONO_CONTEXT_SET_BP ((ctx), __builtin_frame_address (0)); \
MONO_CONTEXT_SET_SP ((ctx), __builtin_frame_address (0)); \