/** * get_throw_trampoline: * * Returns a function pointer which can be used to raise * exceptions. The returned function has the following * signature: void (*func) (MonoException *exc); or * void (*func) (guint32 ex_token, guint8* ip); * */ static gpointer get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm, gboolean resume_unwind, const char *tramp_name, MonoTrampInfo **info, gboolean aot) { guint8 *start; guint8 *code; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; int cfa_offset; 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); cfa_offset = MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t); mono_add_unwind_op_def_cfa (unwind_ops, code, start, ARMREG_SP, cfa_offset); mono_add_unwind_op_offset (unwind_ops, code, start, ARMREG_LR, - sizeof (mgreg_t)); /* Save fp regs */ ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, sizeof (double) * 16); cfa_offset += sizeof (double) * 16; mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, cfa_offset); #if defined(ARM_FPU_VFP) ARM_FSTMD (code, ARM_VFP_D0, 16, ARMREG_SP); #endif /* Param area */ ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8); cfa_offset += 8; mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, cfa_offset); /* call throw_exception (exc, ip, sp, int_regs, fp_regs) */ /* caller sp */ ARM_ADD_REG_IMM8 (code, ARMREG_R2, ARMREG_SP, cfa_offset); /* exc is already in place in r0 */ if (corlib) { /* The caller ip is already in R1 */ if (llvm) /* Negate the ip adjustment done in mono_arm_throw_exception */ ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4); } else { ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR); /* caller ip */ } /* int regs */ ARM_ADD_REG_IMM8 (code, ARMREG_R3, ARMREG_SP, (cfa_offset - (MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t)))); /* we encode rethrow in the ip */ ARM_ORR_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, rethrow); /* fp regs */ ARM_ADD_REG_IMM8 (code, ARMREG_LR, ARMREG_SP, 8); ARM_STR_IMM (code, ARMREG_LR, ARMREG_SP, 0); if (aot) { const char *icall_name; if (resume_unwind) icall_name = "mono_arm_resume_unwind"; else if (corlib) icall_name = "mono_arm_throw_exception_by_token"; else icall_name = "mono_arm_throw_exception"; ji = mono_patch_info_list_prepend (ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name); ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0); ARM_B (code, 0); *(gpointer*)(gpointer)code = NULL; code += 4; ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_PC, ARMREG_IP); } else { code = mono_arm_emit_load_imm (code, ARMREG_IP, GPOINTER_TO_UINT (resume_unwind ? (gpointer)mono_arm_resume_unwind : (corlib ? (gpointer)mono_arm_throw_exception_by_token : (gpointer)mono_arm_throw_exception))); } ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); /* we should never reach this breakpoint */ ARM_DBRK (code); g_assert ((code - start) < size); mono_arch_flush_icache (start, code - start); if (info) *info = mono_tramp_info_create (tramp_name, start, code - start, ji, unwind_ops); return start; }
/** * get_throw_trampoline: * * Returns a function pointer which can be used to raise * exceptions. The returned function has the following * signature: void (*func) (MonoException *exc); or * void (*func) (guint32 ex_token, guint8* ip); * */ static gpointer get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm, gboolean resume_unwind, const char *tramp_name, MonoTrampInfo **info, gboolean aot) { guint8 *start; guint8 *code; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; 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 */ /* exc is already in place in r0 */ if (corlib) { /* The caller ip is already in R1 */ if (llvm) /* Negate the ip adjustment done in mono_arm_throw_exception */ ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4); } else { ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR); /* caller ip */ } /* FIXME: pointer to the saved fp regs */ /*pos = alloc_size - sizeof (double) * MONO_SAVED_FREGS; ppc_addi (code, ppc_r7, ppc_sp, pos);*/ /* pointer to the saved int regs */ ARM_MOV_REG_REG (code, ARMREG_R3, ARMREG_SP); /* the pushed regs */ /* we encode rethrow in the ip, so we avoid args on the stack */ ARM_ORR_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, rethrow); if (aot) { ji = mono_patch_info_list_prepend (ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, corlib ? "mono_arm_throw_exception_by_token" : "mono_arm_throw_exception"); ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0); ARM_B (code, 0); *(gpointer*)(gpointer)code = NULL; code += 4; ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_PC, ARMREG_IP); } else { code = mono_arm_emit_load_imm (code, ARMREG_IP, GPOINTER_TO_UINT (resume_unwind ? (gpointer)mono_arm_resume_unwind : (corlib ? (gpointer)mono_arm_throw_exception_by_token : (gpointer)mono_arm_throw_exception))); } ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); /* we should never reach this breakpoint */ ARM_DBRK (code); g_assert ((code - start) < size); mono_arch_flush_icache (start, code - start); if (info) *info = mono_tramp_info_create (g_strdup_printf (tramp_name), start, code - start, ji, unwind_ops); return start; }