示例#1
0
gpointer
mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
{
    guint8 *start, *code;
    MonoJumpInfo *ji = NULL;
    GSList *unwind_ops = NULL;
    int i, ctx_reg, size;
    guint8 *labels [16];

    size = 256;
    code = start = mono_global_codeman_reserve (size);

    arm_movx (code, ARMREG_IP0, ARMREG_R0);
    ctx_reg = ARMREG_IP0;

    /* Restore fregs */
    arm_ldrx (code, ARMREG_IP1, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, has_fregs));
    labels [0] = code;
    arm_cbzx (code, ARMREG_IP1, 0);
    for (i = 0; i < 32; ++i)
        arm_ldrfpx (code, i, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * 8));
    mono_arm_patch (labels [0], code, MONO_R_ARM64_CBZ);
    /* Restore gregs */
    // FIXME: Restore less registers
    // FIXME: fp should be restored later
    code = mono_arm_emit_load_regarray (code, 0xffffffff & ~(1 << ctx_reg) & ~(1 << ARMREG_SP), ctx_reg, MONO_STRUCT_OFFSET (MonoContext, regs));
    /* ip0/ip1 doesn't need to be restored */
    /* ip1 = pc */
    arm_ldrx (code, ARMREG_IP1, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, pc));
    /* ip0 = sp */
    arm_ldrx (code, ARMREG_IP0, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_SP * 8));
    /* Restore sp, ctx is no longer valid */
    arm_movspx (code, ARMREG_SP, ARMREG_IP0);
    /* Branch to pc */
    arm_brx (code, ARMREG_IP1);
    /* Not reached */
    arm_brk (code, 0);

    g_assert ((code - start) < size);
    mono_arch_flush_icache (start, code - start);
    mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

    if (info)
        *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops);

    return start;
}
示例#2
0
gpointer
mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
{
    guint8 *code;
    guint8* start;
    int i, size, offset, gregs_offset, fregs_offset, ctx_offset, num_fregs, frame_size;
    MonoJumpInfo *ji = NULL;
    GSList *unwind_ops = NULL;
    guint8 *labels [16];

    size = 512;
    start = code = mono_global_codeman_reserve (size);

    /* Compute stack frame size and offsets */
    offset = 0;
    /* frame block */
    offset += 2 * 8;
    /* gregs */
    gregs_offset = offset;
    offset += 32 * 8;
    /* fregs */
    num_fregs = 8;
    fregs_offset = offset;
    offset += num_fregs * 8;
    ctx_offset = offset;
    ctx_offset += 8;
    frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);

    /*
     * We are being called from C code, ctx is in r0, the address to call is in r1.
     * We need to save state, restore ctx, make the call, then restore the previous state,
     * returning the value returned by the call.
     */

    /* Setup a frame */
    arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -frame_size);
    arm_movspx (code, ARMREG_FP, ARMREG_SP);

    /* Save ctx */
    arm_strx (code, ARMREG_R0, ARMREG_FP, ctx_offset);
    /* Save gregs */
    code = mono_arm_emit_store_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS | (1 << ARMREG_FP), ARMREG_FP, gregs_offset);
    /* Save fregs */
    for (i = 0; i < num_fregs; ++i)
        arm_strfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8));

    /* Load regs from ctx */
    code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs));
    /* Load fregs */
    arm_ldrx (code, ARMREG_IP0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, has_fregs));
    labels [0] = code;
    arm_cbzx (code, ARMREG_IP0, 0);
    for (i = 0; i < num_fregs; ++i)
        arm_ldrfpx (code, ARMREG_D8 + i, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * 8));
    mono_arm_patch (labels [0], code, MONO_R_ARM64_CBZ);
    /* Load fp */
    arm_ldrx (code, ARMREG_FP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_FP * 8));

    /* Make the call */
    arm_blrx (code, ARMREG_R1);
    /* For filters, the result is in R0 */

    /* Restore fp */
    arm_ldrx (code, ARMREG_FP, ARMREG_SP, gregs_offset + (ARMREG_FP * 8));
    /* Load ctx */
    arm_ldrx (code, ARMREG_IP0, ARMREG_FP, ctx_offset);
    /* Save registers back to ctx */
    /* This isn't strictly neccessary since we don't allocate variables used in eh clauses to registers */
    code = mono_arm_emit_store_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_IP0, MONO_STRUCT_OFFSET (MonoContext, regs));

    /* Restore regs */
    code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_FP, gregs_offset);
    /* Restore fregs */
    for (i = 0; i < num_fregs; ++i)
        arm_ldrfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8));
    /* Destroy frame */
    code = mono_arm_emit_destroy_frame (code, frame_size, (1 << ARMREG_IP0));
    arm_retx (code, ARMREG_LR);

    g_assert ((code - start) < size);
    mono_arch_flush_icache (start, code - start);
    mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

    if (info)
        *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops);

    return start;
}
示例#3
0
gpointer
mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
{
	guint8 *code, *buf;
	int buf_len, cfa_offset;
	GSList *unwind_ops = NULL;
	MonoJumpInfo *ji = NULL;
	guint8 *br_out, *br [64], *br_ret [64], *bcc_ret [64];
	int i, n_arg_regs, n_arg_fregs, offset, arg_reg, info_offset, rgctx_arg_reg_offset;
	int caller_reg_area_offset, callee_reg_area_offset, callee_stack_area_offset;
	int br_ret_index, bcc_ret_index;

	buf_len = 2048;
	buf = code = mono_global_codeman_reserve (buf_len);

	/*
	 * We are being called by an gsharedvt arg trampoline, the info argument is in IP1.
	 */
	arg_reg = ARMREG_IP1;
	n_arg_regs = NUM_GSHAREDVT_ARG_GREGS;
	n_arg_fregs = NUM_GSHAREDVT_ARG_FREGS;

	/* Compute stack frame size and offsets */
	offset = 0;
	/* frame block */
	offset += 2 * 8;
	/* info argument */
	info_offset = offset;
	offset += 8;
	/* saved rgctx */
	rgctx_arg_reg_offset = offset;
	offset += 8;
	/* alignment */
	offset += 8;
	/* argument regs */
	caller_reg_area_offset = offset;
	offset += (n_arg_regs + n_arg_fregs) * 8;

	/* We need the argument regs to be saved at the top of the frame */
	g_assert (offset % MONO_ARCH_FRAME_ALIGNMENT == 0);

	cfa_offset = offset;

	/* Setup frame */
	arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -cfa_offset);
	mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, cfa_offset);
	mono_add_unwind_op_offset (unwind_ops, code, buf, ARMREG_FP, -cfa_offset + 0);
	mono_add_unwind_op_offset (unwind_ops, code, buf, ARMREG_LR, -cfa_offset + 8);
	arm_movspx (code, ARMREG_FP, ARMREG_SP);
	mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, ARMREG_FP);

	/* Save info argument */
	arm_strx (code, arg_reg, ARMREG_FP, info_offset);

	/* Save rgxctx */
	arm_strx (code, MONO_ARCH_RGCTX_REG, ARMREG_FP, rgctx_arg_reg_offset);

	/* Save argument regs below the stack arguments */
	for (i = 0; i < n_arg_regs; ++i)
		arm_strx (code, i, ARMREG_SP, caller_reg_area_offset + (i * 8));
	// FIXME: Only do this if fp regs are used
	for (i = 0; i < n_arg_fregs; ++i)
		arm_strfpx (code, i, ARMREG_SP, caller_reg_area_offset + ((n_arg_regs + i) * 8));

	/* Allocate callee area */
	arm_ldrw (code, ARMREG_IP0, arg_reg, MONO_STRUCT_OFFSET (GSharedVtCallInfo, stack_usage));
	arm_movspx (code, ARMREG_LR, ARMREG_SP);
	arm_subx (code, ARMREG_LR, ARMREG_LR, ARMREG_IP0);
	arm_movspx (code, ARMREG_SP, ARMREG_LR);
	/* Allocate callee register area just below the callee area so it can be accessed from start_gsharedvt_call using negative offsets */
	/* The + 8 is for alignment */
	callee_reg_area_offset = 8;
	callee_stack_area_offset = callee_reg_area_offset + (n_arg_regs * sizeof (gpointer));
	arm_subx_imm (code, ARMREG_SP, ARMREG_SP, ((n_arg_regs + n_arg_fregs) * sizeof (gpointer)) + 8);

	/*
	 * The stack now looks like this:
	 * <caller frame>
	 * <saved r0-r8>
	 * <our frame>
	 * <saved fp, lr> <- fp
	 * <callee area> <- sp
	 */

	/* Call start_gsharedvt_call () */
	/* arg1 == info */
	arm_ldrx (code, ARMREG_R0, ARMREG_FP, info_offset);
	/* arg2 = caller stack area */
	arm_addx_imm (code, ARMREG_R1, ARMREG_FP, caller_reg_area_offset);
	/* arg3 == callee stack area */
	arm_addx_imm (code, ARMREG_R2, ARMREG_SP, callee_reg_area_offset);
	/* arg4 = mrgctx reg */
	arm_ldrx (code, ARMREG_R3, ARMREG_FP, rgctx_arg_reg_offset);

	if (aot)
		code = mono_arm_emit_aotconst (&ji, code, buf, ARMREG_IP0, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_arm_start_gsharedvt_call");
	else
		code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)mono_arm_start_gsharedvt_call);
	arm_blrx (code, ARMREG_IP0);

	/* Make the real method call */
	/* R0 contains the addr to call */
	arm_movx (code, ARMREG_IP1, ARMREG_R0);
	/* Load rgxctx */
	arm_ldrx (code, MONO_ARCH_RGCTX_REG, ARMREG_FP, rgctx_arg_reg_offset);
	/* Load argument registers */
	// FIXME:
	for (i = 0; i < n_arg_regs; ++i)
		arm_ldrx (code, i, ARMREG_SP, callee_reg_area_offset + (i * 8));
	// FIXME: Only do this if needed
	for (i = 0; i < n_arg_fregs; ++i)
		arm_ldrfpx (code, i, ARMREG_SP, callee_reg_area_offset + ((n_arg_regs + i) * 8));
	/* Clear callee reg area */
	arm_addx_imm (code, ARMREG_SP, ARMREG_SP, ((n_arg_regs + n_arg_fregs) * sizeof (gpointer)) + 8);
	/* Make the call */
	arm_blrx (code, ARMREG_IP1);

	br_ret_index = 0;
	bcc_ret_index = 0;

	// FIXME: Use a switch
	/* Branch between IN/OUT cases */
	arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset);
	arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, gsharedvt_in));
	br_out = code;
	arm_cbzx (code, ARMREG_IP1, 0);

	/* IN CASE */

	/* IP1 == return marshalling type */
	arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset);
	arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal));

	/* Continue if no marshalling required */
	// FIXME: Use cmpx_imm
	code = mono_arm_emit_imm64 (code, ARMREG_IP0, GSHAREDVT_RET_NONE);
	arm_cmpx (code, ARMREG_IP0, ARMREG_IP1);
	bcc_ret [bcc_ret_index ++] = code;
	arm_bcc (code, ARMCOND_EQ, 0);

	/* Compute vret area address in LR */
	arm_ldrx (code, ARMREG_LR, ARMREG_FP, info_offset);
	arm_ldrw (code, ARMREG_LR, ARMREG_LR, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_slot));
	arm_subx_imm (code, ARMREG_LR, ARMREG_LR, n_arg_regs + n_arg_fregs);
	arm_lslx (code, ARMREG_LR, ARMREG_LR, 3);
	arm_movspx (code, ARMREG_IP0, ARMREG_SP);
	arm_addx (code, ARMREG_LR, ARMREG_IP0, ARMREG_LR);

	/* Branch to specific marshalling code */
	for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
		code = mono_arm_emit_imm64 (code, ARMREG_IP0, i);
		arm_cmpx (code, ARMREG_IP0, ARMREG_IP1);
		br [i] = code;
		arm_bcc (code, ARMCOND_EQ, 0);
	}

	arm_brk (code, 0);

	/*
	 * The address of the return value area is in LR, have to load it into
	 * registers.
	 */
	for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
		mono_arm_patch (br [i], code, MONO_R_ARM64_BCC);
		switch (i) {
		case GSHAREDVT_RET_NONE:
			break;
		case GSHAREDVT_RET_I8:
			arm_ldrx (code, ARMREG_R0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_I1:
			arm_ldrsbx (code, ARMREG_R0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_U1:
			arm_ldrb (code, ARMREG_R0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_I2:
			arm_ldrshx (code, ARMREG_R0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_U2:
			arm_ldrh (code, ARMREG_R0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_I4:
			arm_ldrswx (code, ARMREG_R0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_U4:
			arm_ldrw (code, ARMREG_R0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_R8:
			arm_ldrfpx (code, ARMREG_D0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_R4:
			arm_ldrfpw (code, ARMREG_D0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_IREGS_1:
		case GSHAREDVT_RET_IREGS_2:
		case GSHAREDVT_RET_IREGS_3:
		case GSHAREDVT_RET_IREGS_4:
		case GSHAREDVT_RET_IREGS_5:
		case GSHAREDVT_RET_IREGS_6:
		case GSHAREDVT_RET_IREGS_7:
		case GSHAREDVT_RET_IREGS_8: {
			int j;

			for (j = 0; j < i - GSHAREDVT_RET_IREGS_1 + 1; ++j)
				arm_ldrx (code, j, ARMREG_LR, j * 8);
			break;
		}
		case GSHAREDVT_RET_HFAR8_1:
		case GSHAREDVT_RET_HFAR8_2:
		case GSHAREDVT_RET_HFAR8_3:
		case GSHAREDVT_RET_HFAR8_4: {
			int j;

			for (j = 0; j < i - GSHAREDVT_RET_HFAR8_1 + 1; ++j)
				arm_ldrfpx (code, j, ARMREG_LR, j * 8);
			break;
		}
		case GSHAREDVT_RET_HFAR4_1:
		case GSHAREDVT_RET_HFAR4_2:
		case GSHAREDVT_RET_HFAR4_3:
		case GSHAREDVT_RET_HFAR4_4: {
			int j;

			for (j = 0; j < i - GSHAREDVT_RET_HFAR4_1 + 1; ++j)
				arm_ldrfpw (code, j, ARMREG_LR, j * 4);
			break;
		}
		default:
			g_assert_not_reached ();
			break;
		}
		br_ret [br_ret_index ++] = code;
		arm_b (code, 0);
	}

	/* OUT CASE */
	mono_arm_patch (br_out, code, MONO_R_ARM64_CBZ);

	/* Compute vret area address in LR */
	arm_ldrx (code, ARMREG_LR, ARMREG_FP, caller_reg_area_offset + (ARMREG_R8 * 8));

	/* IP1 == return marshalling type */
	arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset);
	arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal));

	/* Branch to specific marshalling code */
	for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
		code = mono_arm_emit_imm64 (code, ARMREG_IP0, i);
		arm_cmpx (code, ARMREG_IP0, ARMREG_IP1);
		br [i] = code;
		arm_bcc (code, ARMCOND_EQ, 0);
	}

	/*
	 * The return value is in registers, need to save to the return area passed by the caller in
	 * R8.
	 */
	for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
		mono_arm_patch (br [i], code, MONO_R_ARM64_BCC);
		switch (i) {
		case GSHAREDVT_RET_NONE:
			break;
		case GSHAREDVT_RET_I8:
			arm_strx (code, ARMREG_R0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_I1:
		case GSHAREDVT_RET_U1:
			arm_strb (code, ARMREG_R0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_I2:
		case GSHAREDVT_RET_U2:
			arm_strh (code, ARMREG_R0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_I4:
		case GSHAREDVT_RET_U4:
			arm_strw (code, ARMREG_R0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_R8:
			arm_strfpx (code, ARMREG_D0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_R4:
			arm_strfpw (code, ARMREG_D0, ARMREG_LR, 0);
			break;
		case GSHAREDVT_RET_IREGS_1:
		case GSHAREDVT_RET_IREGS_2:
		case GSHAREDVT_RET_IREGS_3:
		case GSHAREDVT_RET_IREGS_4:
		case GSHAREDVT_RET_IREGS_5:
		case GSHAREDVT_RET_IREGS_6:
		case GSHAREDVT_RET_IREGS_7:
		case GSHAREDVT_RET_IREGS_8: {
			int j;

			for (j = 0; j < i - GSHAREDVT_RET_IREGS_1 + 1; ++j)
				arm_strx (code, j, ARMREG_LR, j * 8);
			break;
		}
		case GSHAREDVT_RET_HFAR8_1:
		case GSHAREDVT_RET_HFAR8_2:
		case GSHAREDVT_RET_HFAR8_3:
		case GSHAREDVT_RET_HFAR8_4: {
			int j;

			for (j = 0; j < i - GSHAREDVT_RET_HFAR8_1 + 1; ++j)
				arm_strfpx (code, j, ARMREG_LR, j * 8);
			break;
		}
		case GSHAREDVT_RET_HFAR4_1:
		case GSHAREDVT_RET_HFAR4_2:
		case GSHAREDVT_RET_HFAR4_3:
		case GSHAREDVT_RET_HFAR4_4: {
			int j;

			for (j = 0; j < i - GSHAREDVT_RET_HFAR4_1 + 1; ++j)
				arm_strfpw (code, j, ARMREG_LR, j * 4);
			break;
		}
		default:
			arm_brk (code, i);
			break;
		}
		br_ret [br_ret_index ++] = code;
		arm_b (code, 0);
	}

	arm_brk (code, 0);

	for (i = 0; i < br_ret_index; ++i)
		mono_arm_patch (br_ret [i], code, MONO_R_ARM64_B);
	for (i = 0; i < bcc_ret_index; ++i)
		mono_arm_patch (bcc_ret [i], code, MONO_R_ARM64_BCC);

	/* Normal return */
	arm_movspx (code, ARMREG_SP, ARMREG_FP);
	arm_ldpx_post (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, offset);
	arm_retx (code, ARMREG_LR);

	g_assert ((code - buf) < buf_len);

	if (info)
		*info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops);

	mono_arch_flush_icache (buf, code - buf);
	return buf;
}