예제 #1
0
gpointer
mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr)
{
	guint8 *code, *start;
	int this_pos = s390_r2;
	MonoDomain *domain = mono_domain_get ();
	char trampName[128];

	start = code = mono_domain_code_reserve (domain, 28);

	S390_SET  (code, s390_r1, addr);
	s390_aghi (code, this_pos, sizeof(MonoObject));
	s390_br   (code, s390_r1);

	g_assert ((code - start) <= 28);

	mono_arch_flush_icache (start, code - start);

	if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION)
		mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, method);

	snprintf(trampName, sizeof(trampName), "%s_unbox_trampoline", method->name);

	mono_tramp_info_register (mono_tramp_info_create (trampName, start, code - start, NULL, NULL), domain);

	return start;
}
예제 #2
0
/*
 * arch_get_restore_context:
 *
 * Returns a pointer to a method which restores a previously saved sigcontext.
 * The first argument in r3 is the pointer to the context.
 */
gpointer
mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
{
	guint8 *start, *code;
	int size = MONO_PPC_32_64_CASE (128, 172) + PPC_FTNPTR_SIZE;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;

	code = start = mono_global_codeman_reserve (size);
	if (!aot)
		code = mono_ppc_create_pre_code_ftnptr (code);
	restore_regs_from_context (ppc_r3, ppc_r4, ppc_r5);
	/* restore also the stack pointer */
	ppc_ldptr (code, ppc_sp, G_STRUCT_OFFSET (MonoContext, sc_sp), ppc_r3);
	//ppc_break (code);
	/* jump to the saved IP */
	ppc_mtctr (code, ppc_r4);
	ppc_bcctr (code, PPC_BR_ALWAYS, 0);
	/* never reached */
	ppc_break (code);

	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;
}
예제 #3
0
gpointer
mono_arch_get_static_rgctx_trampoline (MonoMethod *m, 
					MonoMethodRuntimeGenericContext *mrgctx, 
					gpointer addr)
{
	guint8 *code, *start;
	gint32 displace;
	int buf_len;
	char trampName[128];

	MonoDomain *domain = mono_domain_get ();

	buf_len = 32;

	start = code = mono_domain_code_reserve (domain, buf_len);

	S390_SET  (code, MONO_ARCH_RGCTX_REG, mrgctx);
	displace = ((uintptr_t) addr - (uintptr_t) code) / 2;
	s390_jg   (code, displace);
	g_assert ((code - start) < buf_len);

	mono_arch_flush_icache (start, code - start);

	if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION)
		mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);

	snprintf(trampName, sizeof(trampName), "%s_rgctx_trampoline", m->name);

	mono_tramp_info_register (mono_tramp_info_create (trampName, start, code - start, NULL, NULL), domain);

	return(start);
}	
예제 #4
0
gpointer
mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
{
	guint8 *code, *buf, *tramp;
	gint32 displace;

	tramp = mono_get_trampoline_code (tramp_type);

	/*----------------------------------------------------------*/
	/* This is the method-specific part of the trampoline. Its  */
	/* purpose is to provide the generic part with the          */
	/* MonoMethod *method pointer. We'll use r1 to keep it.     */
	/*----------------------------------------------------------*/
	code = buf = mono_domain_code_reserve (domain, SPECIFIC_TRAMPOLINE_SIZE);

	S390_SET  (buf, s390_r1, arg1);
	displace = (tramp - buf) / 2;
	s390_jg   (buf, displace);

	/* Flush instruction cache, since we've generated code */
	mono_arch_flush_icache (code, buf - code);

	if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION)
		mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, 
		                               (void *) mono_get_generic_trampoline_simple_name (tramp_type));

	/* Sanity check */
	g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE);

	if (code_len)
		*code_len = buf - code;
	
	return code;
}	
예제 #5
0
gpointer
mono_arch_get_static_rgctx_trampoline (MonoMethod *m, 
					MonoMethodRuntimeGenericContext *mrgctx, 
					gpointer addr)
{
	guint8 *code, *start;
	gint32 displace;
	int buf_len;

	MonoDomain *domain = mono_domain_get ();

	buf_len = 32;

	start = code = mono_domain_code_reserve (domain, buf_len);

	S390_SET  (code, MONO_ARCH_RGCTX_REG, mrgctx);
	displace = ((uintptr_t) addr - (uintptr_t) code) / 2;
	s390_jg   (code, displace);
	g_assert ((code - start) < buf_len);

	mono_arch_flush_icache (start, code - start);
	mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);

	return(start);
}	
예제 #6
0
/*
 * mono_arch_get_call_filter:
 *
 * Returns a pointer to a method which calls an exception filter. We
 * also use this function to call finally handlers (we pass NULL as 
 * @exc object in this case).
 */
gpointer
mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
{
	guint8 *start, *code;
	int alloc_size, pos, i;
	int size = MONO_PPC_32_64_CASE (320, 500) + PPC_FTNPTR_SIZE;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;

	/* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
	code = start = mono_global_codeman_reserve (size);
	if (!aot)
		code = mono_ppc_create_pre_code_ftnptr (code);

	/* store ret addr */
	ppc_mflr (code, ppc_r0);
	ppc_stptr (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);

	alloc_size = REG_SAVE_STACK_FRAME_SIZE;

	/* allocate stack frame and set link from sp in ctx */
	g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
	ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoContext, sc_sp), ppc_r3);
	ppc_ldptr_indexed (code, ppc_r0, ppc_r0, ppc_r0);
	ppc_stptr_update (code, ppc_r0, -alloc_size, ppc_sp);

	code = emit_save_saved_regs (code, alloc_size);

	/* restore all the regs from ctx (in r3), but not r1, the stack pointer */
	restore_regs_from_context (ppc_r3, ppc_r6, ppc_r7);
	/* call handler at eip (r4) and set the first arg with the exception (r5) */
	ppc_mtctr (code, ppc_r4);
	ppc_mr (code, ppc_r3, ppc_r5);
	ppc_bcctrl (code, PPC_BR_ALWAYS, 0);

	/* epilog */
	ppc_ldptr (code, ppc_r0, alloc_size + PPC_RET_ADDR_OFFSET, ppc_sp);
	ppc_mtlr (code, ppc_r0);

	/* restore all the regs from the stack */
	pos = alloc_size;
	for (i = 31; i >= 14; --i) {
		pos -= sizeof (gdouble);
		ppc_lfd (code, i, pos, ppc_sp);
	}
	pos -= sizeof (gpointer) * MONO_SAVED_GREGS;
	ppc_load_multiple_regs (code, ppc_r13, pos, ppc_sp);

	ppc_addic (code, ppc_sp, ppc_sp, alloc_size);
	ppc_blr (code);

	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;
}
예제 #7
0
/*
 * mono_arch_get_restore_context:
 *
 * Returns a pointer to a method which restores a previously saved sigcontext.
 */
gpointer
mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
{
	guint8 *start = NULL;
	guint8 *code;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;

	/* restore_contect (MonoContext *ctx) */

	start = code = mono_global_codeman_reserve (256);

	amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG1, 8);

	/* Restore all registers except %rip and %r11 */
	amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, rax), 8);
	amd64_mov_reg_membase (code, AMD64_RCX, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, rcx), 8);
	amd64_mov_reg_membase (code, AMD64_RDX, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, rdx), 8);
	amd64_mov_reg_membase (code, AMD64_RBX, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, rbx), 8);
	amd64_mov_reg_membase (code, AMD64_RBP, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, rbp), 8);
	amd64_mov_reg_membase (code, AMD64_RSI, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, rsi), 8);
	amd64_mov_reg_membase (code, AMD64_RDI, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, rdi), 8);
	//amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, r8), 8);
	//amd64_mov_reg_membase (code, AMD64_R9, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, r9), 8);
	//amd64_mov_reg_membase (code, AMD64_R10, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, r10), 8);
	amd64_mov_reg_membase (code, AMD64_R12, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, r12), 8);
	amd64_mov_reg_membase (code, AMD64_R13, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, r13), 8);
	amd64_mov_reg_membase (code, AMD64_R14, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, r14), 8);
#if !defined(__native_client_codegen__)
	amd64_mov_reg_membase (code, AMD64_R15, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, r15), 8);
#endif

	/*
	 * The context resides on the stack, in the stack frame of the
	 * caller of this function.  The stack pointer that we need to
	 * restore is potentially many stack frames higher up, so the
	 * distance between them can easily be more than the red zone
	 * size.  Hence the stack pointer can be restored only after
	 * we have finished loading everything from the context.
	 */
	amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, rsp), 8);
	amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11,  MONO_STRUCT_OFFSET (MonoContext, rip), 8);
	amd64_mov_reg_reg (code, AMD64_RSP, AMD64_R8, 8);

	/* jump to the saved IP */
	amd64_jump_reg (code, AMD64_R11);

	nacl_global_codeman_validate(&start, 256, &code);

	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;
}
예제 #8
0
/*
 * mono_arch_get_restore_context:
 *
 * Returns a pointer to a method which restores a previously saved sigcontext.
 */
gpointer
mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
{
	guint8 *start = NULL;
	guint8 *code;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;
	int i, gregs_offset;

	/* restore_contect (MonoContext *ctx) */

	start = code = (guint8 *)mono_global_codeman_reserve (256);

	amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG1, 8);

	/* Restore all registers except %rip and %r11 */
	gregs_offset = MONO_STRUCT_OFFSET (MonoContext, gregs);
	for (i = 0; i < AMD64_NREG; ++i) {
#if defined(__native_client_codegen__)
		if (i == AMD64_R15)
			continue;
#endif
		if (i != AMD64_RIP && i != AMD64_RSP && i != AMD64_R8 && i != AMD64_R9 && i != AMD64_R10 && i != AMD64_R11)
			amd64_mov_reg_membase (code, i, AMD64_R11, gregs_offset + (i * 8), 8);
	}

	/*
	 * The context resides on the stack, in the stack frame of the
	 * caller of this function.  The stack pointer that we need to
	 * restore is potentially many stack frames higher up, so the
	 * distance between them can easily be more than the red zone
	 * size.  Hence the stack pointer can be restored only after
	 * we have finished loading everything from the context.
	 */
	amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11,  gregs_offset + (AMD64_RSP * 8), 8);
	amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11,  gregs_offset + (AMD64_RIP * 8), 8);
	amd64_mov_reg_reg (code, AMD64_RSP, AMD64_R8, 8);

	/* jump to the saved IP */
	amd64_jump_reg (code, AMD64_R11);

	nacl_global_codeman_validate (&start, 256, &code);

	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;
}
예제 #9
0
MonoContinuationRestore
mono_tasklets_arch_restore (void)
{
	static guint8* saved = NULL;
	guint8 *code, *start;
	int cont_reg = AMD64_R9; /* register usable on both call conventions */
	const guint kMaxCodeSize = 64;
	

	if (saved)
		return (MonoContinuationRestore)saved;
	code = start = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize);
	/* the signature is: restore (MonoContinuation *cont, int state, MonoLMF **lmf_addr) */
	/* cont is in AMD64_ARG_REG1 ($rcx or $rdi)
	 * state is in AMD64_ARG_REG2 ($rdx or $rsi)
	 * lmf_addr is in AMD64_ARG_REG3 ($r8 or $rdx)
	 * We move cont to cont_reg since we need both rcx and rdi for the copy
	 * state is moved to $rax so it's setup as the return value and we can overwrite $rsi
 	 */
	amd64_mov_reg_reg (code, cont_reg, MONO_AMD64_ARG_REG1, 8);
	amd64_mov_reg_reg (code, AMD64_RAX, MONO_AMD64_ARG_REG2, 8);
	/* setup the copy of the stack */
	amd64_mov_reg_membase (code, AMD64_RCX, cont_reg, MONO_STRUCT_OFFSET (MonoContinuation, stack_used_size), sizeof (int));
	amd64_shift_reg_imm (code, X86_SHR, AMD64_RCX, 3);
	x86_cld (code);
	amd64_mov_reg_membase (code, AMD64_RSI, cont_reg, MONO_STRUCT_OFFSET (MonoContinuation, saved_stack), sizeof (gpointer));
	amd64_mov_reg_membase (code, AMD64_RDI, cont_reg, MONO_STRUCT_OFFSET (MonoContinuation, return_sp), sizeof (gpointer));
	amd64_prefix (code, X86_REP_PREFIX);
	amd64_movsl (code);

	/* now restore the registers from the LMF */
	amd64_mov_reg_membase (code, AMD64_RCX, cont_reg, MONO_STRUCT_OFFSET (MonoContinuation, lmf), 8);
	amd64_mov_reg_membase (code, AMD64_RBP, AMD64_RCX, MONO_STRUCT_OFFSET (MonoLMF, rbp), 8);
	amd64_mov_reg_membase (code, AMD64_RSP, AMD64_RCX, MONO_STRUCT_OFFSET (MonoLMF, rsp), 8);

#ifdef WIN32
	amd64_mov_reg_reg (code, AMD64_R14, AMD64_ARG_REG3, 8);
#else
	amd64_mov_reg_reg (code, AMD64_R12, AMD64_ARG_REG3, 8);
#endif

	/* state is already in rax */
	amd64_jump_membase (code, cont_reg, MONO_STRUCT_OFFSET (MonoContinuation, return_ip));
	g_assert ((code - start) <= kMaxCodeSize);

	mono_arch_flush_icache (start, code - start);
	mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

	saved = start;
	return (MonoContinuationRestore)saved;
}
예제 #10
0
gpointer
mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot)
{
	guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
	guint8 *code, *buf;
	int tramp_size = 64;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;

	g_assert (!aot);

	code = buf = mono_global_codeman_reserve (tramp_size);

	/*
	 * This trampoline restore the call chain of the handler block 
	 * then jumps into the code that deals with it.
	 */

	if (mono_get_jit_tls_offset () != -1) {
		s390_ear  (code, s390_r1, 0);
		s390_sllg (code, s390_r1, s390_r1, 0, 32);
		s390_ear  (code, s390_r1, 1);
		S390_SET  (code, s390_r14, mono_get_jit_tls_offset());
		s390_lg   (code, s390_r14, s390_r1, 0, G_STRUCT_OFFSET(MonoJitTlsData, handler_block_return_address));
		/* 
		 * Simulate a call 
		 */
		S390_SET  (code, s390_r1, tramp);
		s390_br   (code, s390_r1);
	} else {
		/*
		 * Slow path uses a C helper
		 */
		S390_SET  (code, s390_r2, tramp);
		S390_SET  (code, s390_r1, handler_block_trampoline_helper);
		s390_br	  (code, s390_r1);
	}

	mono_arch_flush_icache (buf, code - buf);

	if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION)
		mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);

	g_assert (code - buf <= tramp_size);

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

	return buf;
}
예제 #11
0
gpointer
mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
{
	guint8 *code, *buf, *tramp;
	gint32 displace;

	tramp = mono_get_trampoline_code (tramp_type);

	/*----------------------------------------------------------*/
	/* This is the method-specific part of the trampoline. Its  */
	/* purpose is to provide the generic part with the          */
	/* MonoMethod *method pointer. We'll use r1 to keep it.     */
	/*----------------------------------------------------------*/
	code = buf = mono_domain_code_reserve (domain, SPECIFIC_TRAMPOLINE_SIZE);

	switch (tramp_type) {
	/*
	 * Monitor tramps have the object in r2
	 */
	case MONO_TRAMPOLINE_MONITOR_ENTER:
	case MONO_TRAMPOLINE_MONITOR_ENTER_V4:
	case MONO_TRAMPOLINE_MONITOR_EXIT:
		s390_lgr (buf, s390_r1, s390_r2);
		break;
	/*
	 * Generic class trampoline arg is in r2
	 */
	case MONO_TRAMPOLINE_GENERIC_CLASS_INIT:
		s390_lgr (buf, s390_r1, s390_r2);
		break;
	default :
		S390_SET  (buf, s390_r1, arg1);
	}
	displace = (tramp - buf) / 2;
	s390_jg   (buf, displace);

	/* Flush instruction cache, since we've generated code */
	mono_arch_flush_icache (code, buf - code);
	mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, 
				       (void *) mono_get_generic_trampoline_simple_name (tramp_type));

	/* Sanity check */
	g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE);

	if (code_len)
		*code_len = buf - code;
	
	return code;
}	
예제 #12
0
gpointer 
mono_arch_get_throw_exception_by_name (void)
{
	guint8 *start, *code;
	int size = 64;

	/* Not used on MIPS */	
	start = code = mono_global_codeman_reserve (size);
	mips_break (code, 0xfd);
	mono_arch_flush_icache (start, code - start);

	if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION)
		mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

	return start;
}
예제 #13
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;
}
예제 #14
0
/*
 * mono_x86_get_signal_exception_trampoline:
 *
 *   This x86 specific trampoline is used to call handle_signal_exception.
 */
gpointer
mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot)
{
	guint8 *start, *code;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;
	int stack_size;

	start = code = mono_global_codeman_reserve (128);

	/* FIXME no unwind before we push ip */
	/* Caller ip */
	x86_push_reg (code, X86_ECX);

	mono_add_unwind_op_def_cfa (unwind_ops, code, start, X86_ESP, 4);
	mono_add_unwind_op_offset (unwind_ops, code, start, X86_NREG, -4);

	/* Fix the alignment to be what apple expects */
	stack_size = 12;

	x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size);
	mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 4);

	/* Arg1 */
	x86_mov_membase_reg (code, X86_ESP, 0, X86_EAX, 4);
	/* Branch to target */
	x86_call_reg (code, X86_EDX);

	g_assert ((code - start) < 128);

	if (info)
		*info = mono_tramp_info_create ("x86_signal_exception_trampoline", start, code - start, ji, unwind_ops);
	else {
		GSList *l;

		for (l = unwind_ops; l; l = l->next)
			g_free (l->data);
		g_slist_free (unwind_ops);
	}

	mono_arch_flush_icache (start, code - start);

	if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION)
		mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

	return start;
}
예제 #15
0
/*
 * mono_arch_get_restore_context:
 *
 * Returns a pointer to a method which restores a previously saved MonoContext.
 * The first argument in a0 is the pointer to the MonoContext.
 */
gpointer
mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
{
	int i;
	guint8 *code;
	static guint8 start [512];
	static int inited = 0;
	guint32 iregs_to_restore;

	g_assert (!aot);
	if (info)
		*info = NULL;

	if (inited)
		return start;
	inited = 1;
	code = start;

	mips_move (code, mips_at, mips_a0);

	iregs_to_restore = (MONO_ARCH_CALLEE_SAVED_REGS \
			    | (1 << mips_sp) | (1 << mips_ra));
	for (i = 0; i < MONO_SAVED_GREGS; ++i) {
		//if (iregs_to_restore & (1 << i)) {
		if (i != mips_zero && i != mips_at) {
			MIPS_LW (code, i, mips_at, G_STRUCT_OFFSET (MonoContext, sc_regs[i]));
		}
	}

	/* Get the address to return to */
	mips_lw (code, mips_t9, mips_at, G_STRUCT_OFFSET (MonoContext, sc_pc));

	/* jump to the saved IP */
	mips_jr (code, mips_t9);
	mips_nop (code);

	/* never reached */
	mips_break (code, 0xff);

	g_assert ((code - start) < sizeof(start));
	mono_arch_flush_icache (start, code - start);

	if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION)
		mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

	return start;
}
예제 #16
0
/*
 * mono_win32_get_handle_stackoverflow (void):
 *
 * Returns a pointer to a method which restores the current context stack
 * and calls handle_exceptions, when done restores the original stack.
 */
static gpointer
mono_win32_get_handle_stackoverflow (void)
{
	static guint8 *start = NULL;
	guint8 *code;

	if (start)
		return start;

	/* restore_contect (void *sigctx) */
	start = code = mono_global_codeman_reserve (128);

	/* load context into ebx */
	x86_mov_reg_membase (code, X86_EBX, X86_ESP, 4, 4);

	/* move current stack into edi for later restore */
	x86_mov_reg_reg (code, X86_EDI, X86_ESP, 4);

	/* use the new freed stack from sigcontext */
	/* XXX replace usage of struct sigcontext with MonoContext so we can use MONO_STRUCT_OFFSET */
	x86_mov_reg_membase (code, X86_ESP, X86_EBX,  G_STRUCT_OFFSET (struct sigcontext, esp), 4);

	/* get the current domain */
	x86_call_code (code, mono_domain_get);

	/* get stack overflow exception from domain object */
	x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoDomain, stack_overflow_ex), 4);

	/* call mono_arch_handle_exception (sctx, stack_overflow_exception_obj) */
	x86_push_reg (code, X86_EAX);
	x86_push_reg (code, X86_EBX);
	x86_call_code (code, mono_arch_handle_exception);

	/* restore the SEH handler stack */
	x86_mov_reg_reg (code, X86_ESP, X86_EDI, 4);

	/* return */
	x86_ret (code);

	mono_arch_flush_icache (start, code - start);

	if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION)
		mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

	return start;
}
예제 #17
0
gpointer
mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info)
{
	guint8 *buf, *code;

	code = buf = mono_global_codeman_reserve (16);

	s390_br (code, s390_r14);

	mono_arch_flush_icache (buf, code - buf);
	mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);

	*info = mono_tramp_info_create ("nullified_class_init_trampoline", 
									buf, code - buf, NULL, NULL);

	return (buf);
}
예제 #18
0
gpointer
mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr)
{
	guint8 *code, *start;
	int this_pos = s390_r2;
	MonoDomain *domain = mono_domain_get ();

	start = code = mono_domain_code_reserve (domain, 28);

	S390_SET  (code, s390_r1, addr);
	s390_aghi (code, this_pos, sizeof(MonoObject));
	s390_br   (code, s390_r1);

	g_assert ((code - start) <= 28);

	mono_arch_flush_icache (start, code - start);
	mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, method);

	return start;
}
예제 #19
0
/*
 * mono_arch_get_gsharedvt_arg_trampoline:
 *
 *   See tramp-x86.c for documentation.
 */
gpointer
mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
{
	guint8 *code, *start;
	int buf_len;

	buf_len = 32;

	start = code = mono_domain_code_reserve (domain, buf_len);

	amd64_mov_reg_imm (code, AMD64_RAX, arg);
	amd64_jump_code (code, addr);
	g_assert ((code - start) < buf_len);

	mono_arch_flush_icache (start, code - start);
	mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);

	mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);

	return start;
}
예제 #20
0
gpointer
mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
{
	guint8	*tramp,
		*code, *buf;
	gint16	*jump_obj_null, 
		*jump_have_waiters, 
		*jump_sync_null, 
		*jump_not_owned, 
		*jump_cs_failed,
		*jump_next,
		*jump_sync_thin_hash = NULL;
	int	tramp_size,
		status_offset, nest_offset;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;
	int	obj_reg = s390_r2,
		sync_reg = s390_r3,
		status_reg = s390_r4;

	g_assert (obj_reg == MONO_ARCH_MONITOR_OBJECT_REG);

	mono_monitor_threads_sync_members_offset (&status_offset, &nest_offset);
	g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (status_offset) == sizeof (guint32));
	g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
	status_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (status_offset);
	nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);

	tramp_size = 160;

	code = buf = mono_global_codeman_reserve (tramp_size);

	unwind_ops = mono_arch_get_cie_program ();

	if (mono_thread_get_tls_offset () != -1) {
		/* MonoObject* obj is in obj_reg */
		/* is obj null? */
		s390_ltgr (code, obj_reg, obj_reg);
		/* if yes, jump to actual trampoline */
		s390_jz (code, 0); CODEPTR(code, jump_obj_null);

		/* load obj->synchronization to RCX */
		s390_lg (code, sync_reg, 0, obj_reg, MONO_STRUCT_OFFSET (MonoObject, synchronisation));

		if (mono_gc_is_moving ()) {
			/*if bit zero is set it's a thin hash*/
			s390_tmll (code, sync_reg, 1);
			s390_jo   (code, 0); CODEPTR(code, jump_sync_thin_hash);

			/* Clear bits used by the gc */
			s390_nill (code, sync_reg, ~0x3);
		}

		/* is synchronization null? */
		s390_ltgr (code, sync_reg, sync_reg);
		/* if yes, jump to actual trampoline */
		s390_jz (code, 0); CODEPTR(code, jump_sync_null);

		/* next case: synchronization is not null */
		/* load MonoInternalThread* into r5 */
		s390_ear (code, s390_r5, 0);
		s390_sllg(code, s390_r5, s390_r5, 0, 32);
		s390_ear (code, s390_r5, 1);
		/* load TID into r1 */
		s390_lg  (code, s390_r1, 0, s390_r5, mono_thread_get_tls_offset ());
		s390_lgf (code, s390_r1, 0, s390_r1, MONO_STRUCT_OFFSET (MonoInternalThread, small_id));
		/* is synchronization->owner == TID */
		s390_lgf (code, status_reg, 0, sync_reg, status_offset);
		s390_xr  (code, s390_r1, status_reg);
		s390_tmlh (code, s390_r1, OWNER_MASK);
		/* if not, jump to actual trampoline */
		s390_jno (code, 0); CODEPTR(code, jump_not_owned);

		/* next case: synchronization->owner == TID */
		/* is synchronization->nest == 1 */
		s390_lgf (code, s390_r0, 0, sync_reg, nest_offset);
		s390_chi (code, s390_r0, 1);
		/* if not, jump to next case */
		s390_jne (code, 0); CODEPTR(code, jump_next);
		/* if yes, is synchronization->entry_count greater than zero */
		s390_cfi (code, status_reg, ENTRY_COUNT_WAITERS);
		/* if not, jump to actual trampoline */
		s390_jnz (code, 0); CODEPTR(code, jump_have_waiters);
		/* if yes, try to set synchronization->owner to null and return */
		/* old status in s390_r0 */
		s390_lgfr (code, s390_r0, status_reg);
		/* form new status */
		s390_nilf (code, status_reg, ENTRY_COUNT_MASK);
		/* compare and exchange */
		s390_cs (code, s390_r0, status_reg, sync_reg, status_offset);
		/* if not successful, jump to actual trampoline */
		s390_jnz (code, 0); CODEPTR(code, jump_cs_failed);
		s390_br  (code, s390_r14);

		/* next case: synchronization->nest is not 1 */
		PTRSLOT (code, jump_next);
		/* decrease synchronization->nest and return */
		s390_lgf (code, s390_r0, 0, sync_reg, nest_offset);
		s390_ahi (code, s390_r0, -1);
		s390_st  (code, s390_r0, 0, sync_reg, nest_offset);
		s390_br  (code, s390_r14);

		PTRSLOT (code, jump_obj_null);
		if (jump_sync_thin_hash)
			PTRSLOT (code, jump_sync_thin_hash);
		PTRSLOT (code, jump_have_waiters);
		PTRSLOT (code, jump_not_owned);
		PTRSLOT (code, jump_cs_failed);
		PTRSLOT (code, jump_sync_null);
	}

	/* jump to the actual trampoline */
	tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_EXIT, mono_get_root_domain (), NULL);

	S390_SET (code, s390_r1, tramp);
	s390_br (code, s390_r1);

	mono_arch_flush_icache (code, code - buf);
	mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_MONITOR, NULL);
	g_assert (code - buf <= tramp_size);

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

	return buf;
}
예제 #21
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;
}
예제 #22
0
/*
 * get_throw_trampoline:
 *
 *  Generate a call to mono_x86_throw_exception/
 * mono_x86_throw_corlib_exception.
 * If LLVM is true, generate code which assumes the caller is LLVM generated code, 
 * which doesn't push the arguments.
 */
static guint8*
get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolean corlib, gboolean llvm_abs, gboolean resume_unwind, MonoTrampInfo **info, gboolean aot)
{
	guint8 *start, *code, *labels [16];
	int i, stack_size, stack_offset, arg_offsets [5], regs_offset;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;
	guint kMaxCodeSize = 192;

	start = code = mono_global_codeman_reserve (kMaxCodeSize);

	stack_size = 128;

	/* 
	 * On apple, the stack is misaligned by the pushing of the return address.
	 */
	if (!llvm && corlib)
		/* On OSX, we don't generate alignment code to save space */
		stack_size += 4;
	else
		stack_size += MONO_ARCH_FRAME_ALIGNMENT - 4;

	/*
	 * The stack looks like this:
	 * <pc offset> (only if corlib is TRUE)
	 * <exception object>/<type token>
	 * <return addr> <- esp (unaligned on apple)
	 */

	unwind_ops = mono_arch_get_cie_program ();

	/* Alloc frame */
	x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size);
	mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 4);

	arg_offsets [0] = 0;
	arg_offsets [1] = 4;
	arg_offsets [2] = 8;
	arg_offsets [3] = 12;
	regs_offset = 16;

	/* Save registers */
	for (i = 0; i < X86_NREG; ++i)
		if (i != X86_ESP)
			x86_mov_membase_reg (code, X86_ESP, regs_offset + (i * 4), i, 4);
	/* Calculate the offset between the current sp and the sp of the caller */
	if (llvm) {
		/* LLVM doesn't push the arguments */
		stack_offset = stack_size + 4;
	} else {
		if (corlib) {
			/* Two arguments */
			stack_offset = stack_size + 4 + 8;
#ifdef __APPLE__
			/* We don't generate stack alignment code on osx to save space */
#endif
		} else {
			/* One argument + stack alignment */
			stack_offset = stack_size + 4 + 4;
#ifdef __APPLE__
			/* Pop the alignment added by OP_THROW too */
			stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4;
#else
			if (mono_do_x86_stack_align)
				stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4;
#endif
		}
	}
	/* Save ESP */
	x86_lea_membase (code, X86_EAX, X86_ESP, stack_offset);
	x86_mov_membase_reg (code, X86_ESP, regs_offset + (X86_ESP * 4), X86_EAX, 4);

	/* Clear fp stack */
	labels [0] = code;
	x86_fnstsw (code);
	x86_shift_reg_imm (code, X86_SHR, X86_EAX, 11);
	x86_alu_reg_imm (code, X86_AND, X86_EAX, 7);
	x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0);
	labels [1] = code;
	x86_branch8 (code, X86_CC_EQ, 0, FALSE);
	x86_fstp (code, 0);
	x86_jump_code (code, labels [0]);
	mono_x86_patch (labels [1], code);

	/* Set arg1 == regs */
	x86_lea_membase (code, X86_EAX, X86_ESP, regs_offset);
	x86_mov_membase_reg (code, X86_ESP, arg_offsets [0], X86_EAX, 4);
	/* Set arg2 == exc/ex_token_index */
	if (resume_unwind)
		x86_mov_reg_imm (code, X86_EAX, 0);
	else
		x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 4, 4);
	x86_mov_membase_reg (code, X86_ESP, arg_offsets [1], X86_EAX, 4);
	/* Set arg3 == eip */
	if (llvm_abs)
		x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
	else
		x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size, 4);
	x86_mov_membase_reg (code, X86_ESP, arg_offsets [2], X86_EAX, 4);
	/* Set arg4 == rethrow/pc_offset */
	if (resume_unwind) {
		x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], 0, 4);
	} else if (corlib) {
		x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 8, 4);
		if (llvm_abs) {
			/* 
			 * The caller is LLVM code which passes the absolute address not a pc offset,
			 * so compensate by passing 0 as 'ip' and passing the negated abs address as
			 * the pc offset.
			 */
			x86_neg_reg (code, X86_EAX);
		}
		x86_mov_membase_reg (code, X86_ESP, arg_offsets [3], X86_EAX, 4);
	} else {
		x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], rethrow, 4);
	}
	/* Make the call */
	if (aot) {
		// This can be called from runtime code, which can't guarantee that
		// ebx contains the got address.
		// So emit the got address loading code too
		code = mono_arch_emit_load_got_addr (start, code, NULL, &ji);
		code = mono_arch_emit_load_aotconst (start, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, corlib ? "mono_x86_throw_corlib_exception" : "mono_x86_throw_exception");
		x86_call_reg (code, X86_EAX);
	} else {
		x86_call_code (code, resume_unwind ? (gpointer)(mono_x86_resume_unwind) : (corlib ? (gpointer)mono_x86_throw_corlib_exception : (gpointer)mono_x86_throw_exception));
	}
	x86_breakpoint (code);

	g_assert ((code - start) < kMaxCodeSize);

	if (info)
		*info = mono_tramp_info_create (name, start, code - start, ji, unwind_ops);
	else {
		GSList *l;

		for (l = unwind_ops; l; l = l->next)
			g_free (l->data);
		g_slist_free (unwind_ops);
	}

	mono_arch_flush_icache (start, code - start);
	mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

	return start;
}
예제 #23
0
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, *code;
    MonoJumpInfo *ji = NULL;
    GSList *unwind_ops = NULL;
    int i, offset, gregs_offset, fregs_offset, frame_size, num_fregs;

    code = start = mono_global_codeman_reserve (size);

    /* We are being called by JITted code, the exception object/type token is in R0 */

    /* 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;
    frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);

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

    /* Save gregs */
    code = mono_arm_emit_store_regarray (code, 0xffffffff, ARMREG_FP, gregs_offset);
    if (corlib && !llvm)
        /* The real LR is in R1 */
        arm_strx (code, ARMREG_R1, ARMREG_FP, gregs_offset + (ARMREG_LR * 8));
    /* Save fp/sp */
    arm_ldrx (code, ARMREG_IP0, ARMREG_FP, 0);
    arm_strx (code, ARMREG_IP0, ARMREG_FP, gregs_offset + (ARMREG_FP * 8));
    arm_addx_imm (code, ARMREG_IP0, ARMREG_FP, frame_size);
    arm_strx (code, ARMREG_IP0, ARMREG_FP, gregs_offset + (ARMREG_SP * 8));
    /* Save fregs */
    for (i = 0; i < num_fregs; ++i)
        arm_strfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8));

    /* Call the C trampoline function */
    /* Arg1 =  exception object/type token */
    arm_movx (code, ARMREG_R0, ARMREG_R0);
    /* Arg2 = caller ip */
    if (corlib) {
        if (llvm)
            arm_ldrx (code, ARMREG_R1, ARMREG_FP, gregs_offset + (ARMREG_LR * 8));
        else
            arm_movx (code, ARMREG_R1, ARMREG_R1);
    } else {
        arm_ldrx (code, ARMREG_R1, ARMREG_FP, 8);
    }
    /* Arg 3 = gregs */
    arm_addx_imm (code, ARMREG_R2, ARMREG_FP, gregs_offset);
    /* Arg 4 = fregs */
    arm_addx_imm (code, ARMREG_R3, ARMREG_FP, fregs_offset);
    /* Arg 5 = corlib */
    arm_movzx (code, ARMREG_R4, corlib ? 1 : 0, 0);
    /* Arg 6 = rethrow */
    arm_movzx (code, ARMREG_R5, rethrow ? 1 : 0, 0);
    /* Call the function */
    if (aot) {
        const char *icall_name;

        if (resume_unwind)
            icall_name = "mono_arm_resume_unwind";
        else
            icall_name = "mono_arm_throw_exception";

        code = mono_arm_emit_aotconst (&ji, code, start, ARMREG_LR, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name);
    } else {
        gpointer icall_func;

        if (resume_unwind)
            icall_func = mono_arm_resume_unwind;
        else
            icall_func = mono_arm_throw_exception;

        code = mono_arm_emit_imm64 (code, ARMREG_LR, (guint64)icall_func);
    }
    arm_blrx (code, ARMREG_LR);
    /* This shouldn't return */
    arm_brk (code, 0x0);

    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 (tramp_name, start, code - start, ji, unwind_ops);

    return start;
}
예제 #24
0
/*
 * mono_arch_get_restore_context:
 *
 * Returns a pointer to a method which restores a previously saved sigcontext.
 */
gpointer
mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
{
	guint8 *start = NULL;
	guint8 *code;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;

	/* restore_contect (MonoContext *ctx) */

	start = code = mono_global_codeman_reserve (128);
	
	/* load ctx */
	x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);

	/* restore EBX */
	x86_mov_reg_membase (code, X86_EBX, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, ebx), 4);

	/* restore EDI */
	x86_mov_reg_membase (code, X86_EDI, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, edi), 4);

	/* restore ESI */
	x86_mov_reg_membase (code, X86_ESI, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, esi), 4);

	/* restore EDX */
	x86_mov_reg_membase (code, X86_EDX, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, edx), 4);

	/*
	 * The context resides on the stack, in the stack frame of the
	 * caller of this function.  The stack pointer that we need to
	 * restore is potentially many stack frames higher up, so the
	 * distance between them can easily be more than the red zone
	 * size.  Hence the stack pointer can be restored only after
	 * we have finished loading everything from the context.
	 */

	/* load ESP into EBP */
	x86_mov_reg_membase (code, X86_EBP, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, esp), 4);
	/* load return address into ECX */
	x86_mov_reg_membase (code, X86_ECX, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, eip), 4);
	/* save the return addr to the restored stack - 4 */
	x86_mov_membase_reg (code, X86_EBP, -4, X86_ECX, 4);

	/* load EBP into ECX */
	x86_mov_reg_membase (code, X86_ECX, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, ebp), 4);
	/* save EBP to the restored stack - 8 */
	x86_mov_membase_reg (code, X86_EBP, -8, X86_ECX, 4);

	/* load EAX into ECX */
	x86_mov_reg_membase (code, X86_ECX, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, eax), 4);
	/* save EAX to the restored stack - 12 */
	x86_mov_membase_reg (code, X86_EBP, -12, X86_ECX, 4);

	/* restore ECX */
	x86_mov_reg_membase (code, X86_ECX, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, ecx), 4);

	/* restore ESP - 12 */
	x86_lea_membase (code, X86_ESP, X86_EBP, -12);
	/* restore EAX */
	x86_pop_reg (code, X86_EAX);
	/* restore EBP */
	x86_pop_reg (code, X86_EBP);
	/* jump to the saved IP */
	x86_ret (code);

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

		for (l = unwind_ops; l; l = l->next)
			g_free (l->data);
		g_slist_free (unwind_ops);
	}

	mono_arch_flush_icache (start, code - start);
	mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

	return start;
}
예제 #25
0
/*
 * mono_arch_get_call_filter:
 *
 * Returns a pointer to a method which calls an exception filter. We
 * also use this function to call finally handlers (we pass NULL as 
 * @exc object in this case).
 */
gpointer
mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
{
	guint8* start;
	guint8 *code;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;
	guint kMaxCodeSize = 64;

	/* call_filter (MonoContext *ctx, unsigned long eip) */
	start = code = mono_global_codeman_reserve (kMaxCodeSize);

	x86_push_reg (code, X86_EBP);
	x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
	x86_push_reg (code, X86_EBX);
	x86_push_reg (code, X86_EDI);
	x86_push_reg (code, X86_ESI);

	/* load ctx */
	x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
	/* load eip */
	x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
	/* save EBP */
	x86_push_reg (code, X86_EBP);

	/* set new EBP */
	x86_mov_reg_membase (code, X86_EBP, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, ebp), 4);
	/* restore registers used by global register allocation (EBX & ESI) */
	x86_mov_reg_membase (code, X86_EBX, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, ebx), 4);
	x86_mov_reg_membase (code, X86_ESI, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, esi), 4);
	x86_mov_reg_membase (code, X86_EDI, X86_EAX,  MONO_STRUCT_OFFSET (MonoContext, edi), 4);

	/* align stack and save ESP */
	x86_mov_reg_reg (code, X86_EDX, X86_ESP, 4);
	x86_alu_reg_imm (code, X86_AND, X86_ESP, -MONO_ARCH_FRAME_ALIGNMENT);
	g_assert (MONO_ARCH_FRAME_ALIGNMENT >= 8);
	x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 8);
	x86_push_reg (code, X86_EDX);

	/* call the handler */
	x86_call_reg (code, X86_ECX);

	/* restore ESP */
	x86_pop_reg (code, X86_ESP);

	/* restore EBP */
	x86_pop_reg (code, X86_EBP);

	/* restore saved regs */
	x86_pop_reg (code, X86_ESI);
	x86_pop_reg (code, X86_EDI);
	x86_pop_reg (code, X86_EBX);
	x86_leave (code);
	x86_ret (code);

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

		for (l = unwind_ops; l; l = l->next)
			g_free (l->data);
		g_slist_free (unwind_ops);
	}

	mono_arch_flush_icache (start, code - start);
	mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

	g_assert ((code - start) < kMaxCodeSize);
	return start;
}
예제 #26
0
/*
 * get_throw_trampoline:
 *
 *  Generate a call to mono_amd64_throw_exception/
 * mono_amd64_throw_corlib_exception.
 */
static gpointer
get_throw_trampoline (MonoTrampInfo **info, gboolean rethrow, gboolean corlib, gboolean llvm_abs, gboolean resume_unwind, const char *tramp_name, gboolean aot)
{
	guint8* start;
	guint8 *code;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;
	int i, stack_size, arg_offsets [16], ctx_offset, regs_offset, dummy_stack_space;
	const guint kMaxCodeSize = NACL_SIZE (256, 512);

#ifdef TARGET_WIN32
	dummy_stack_space = 6 * sizeof(mgreg_t);	/* Windows expects stack space allocated for all 6 dummy args. */
#else
	dummy_stack_space = 0;
#endif

	start = code = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize);

	/* The stack is unaligned on entry */
	stack_size = ALIGN_TO (sizeof (MonoContext) + 64 + dummy_stack_space, MONO_ARCH_FRAME_ALIGNMENT) + 8;

	code = start;

	if (info)
		unwind_ops = mono_arch_get_cie_program ();

	/* Alloc frame */
	amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, stack_size);
	if (info)
		mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 8);

	/*
	 * To hide linux/windows calling convention differences, we pass all arguments on
	 * the stack by passing 6 dummy values in registers.
	 */

	arg_offsets [0] = dummy_stack_space + 0;
	arg_offsets [1] = dummy_stack_space + sizeof(mgreg_t);
	arg_offsets [2] = dummy_stack_space + sizeof(mgreg_t) * 2;
	ctx_offset = dummy_stack_space + sizeof(mgreg_t) * 4;
	regs_offset = ctx_offset + MONO_STRUCT_OFFSET (MonoContext, gregs);

	/* Save registers */
	for (i = 0; i < AMD64_NREG; ++i)
		if (i != AMD64_RSP)
			amd64_mov_membase_reg (code, AMD64_RSP, regs_offset + (i * sizeof(mgreg_t)), i, sizeof(mgreg_t));
	/* Save RSP */
	amd64_lea_membase (code, AMD64_RAX, AMD64_RSP, stack_size + sizeof(mgreg_t));
	amd64_mov_membase_reg (code, AMD64_RSP, regs_offset + (AMD64_RSP * sizeof(mgreg_t)), X86_EAX, sizeof(mgreg_t));
	/* Save IP */
	if (llvm_abs)
		amd64_alu_reg_reg (code, X86_XOR, AMD64_RAX, AMD64_RAX);
	else
		amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RSP, stack_size, sizeof(mgreg_t));
	amd64_mov_membase_reg (code, AMD64_RSP, regs_offset + (AMD64_RIP * sizeof(mgreg_t)), AMD64_RAX, sizeof(mgreg_t));
	/* Set arg1 == ctx */
	amd64_lea_membase (code, AMD64_RAX, AMD64_RSP, ctx_offset);
	amd64_mov_membase_reg (code, AMD64_RSP, arg_offsets [0], AMD64_RAX, sizeof(mgreg_t));
	/* Set arg2 == exc/ex_token_index */
	if (resume_unwind)
		amd64_mov_membase_imm (code, AMD64_RSP, arg_offsets [1], 0, sizeof(mgreg_t));
	else
		amd64_mov_membase_reg (code, AMD64_RSP, arg_offsets [1], AMD64_ARG_REG1, sizeof(mgreg_t));
	/* Set arg3 == rethrow/pc offset */
	if (resume_unwind) {
		amd64_mov_membase_imm (code, AMD64_RSP, arg_offsets [2], 0, sizeof(mgreg_t));
	} else if (corlib) {
		amd64_mov_membase_reg (code, AMD64_RSP, arg_offsets [2], AMD64_ARG_REG2, sizeof(mgreg_t));
		if (llvm_abs)
			/* 
			 * The caller is LLVM code which passes the absolute address not a pc offset,
			 * so compensate by passing 0 as 'rip' and passing the negated abs address as
			 * the pc offset.
			 */
			amd64_neg_membase (code, AMD64_RSP, arg_offsets [2]);
	} else {
		amd64_mov_membase_imm (code, AMD64_RSP, arg_offsets [2], rethrow, sizeof(mgreg_t));
	}

	if (aot) {
		const char *icall_name;

		if (resume_unwind)
			icall_name = "mono_amd64_resume_unwind";
		else if (corlib)
			icall_name = "mono_amd64_throw_corlib_exception";
		else
			icall_name = "mono_amd64_throw_exception";
		ji = mono_patch_info_list_prepend (ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name);
		amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
	} else {
		amd64_mov_reg_imm (code, AMD64_R11, resume_unwind ? ((gpointer)mono_amd64_resume_unwind) : (corlib ? (gpointer)mono_amd64_throw_corlib_exception : (gpointer)mono_amd64_throw_exception));
	}
	amd64_call_reg (code, AMD64_R11);
	amd64_breakpoint (code);

	mono_arch_flush_icache (start, code - start);

	g_assert ((code - start) < kMaxCodeSize);

	nacl_global_codeman_validate(&start, kMaxCodeSize, &code);
	mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

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

	return start;
}
예제 #27
0
/*
 * mono_arch_get_call_filter:
 *
 * Returns a pointer to a method which calls an exception filter. We
 * also use this function to call finally handlers (we pass NULL as 
 * @exc object in this case).
 */
gpointer
mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
{
	guint8 *start;
	int i, gregs_offset;
	guint8 *code;
	guint32 pos;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;
	const guint kMaxCodeSize = NACL_SIZE (128, 256);

	start = code = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize);

	/* call_filter (MonoContext *ctx, unsigned long eip) */
	code = start;

	/* Alloc new frame */
	amd64_push_reg (code, AMD64_RBP);
	amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, 8);

	/* Save callee saved regs */
	pos = 0;
	for (i = 0; i < AMD64_NREG; ++i)
		if (AMD64_IS_CALLEE_SAVED_REG (i)) {
			amd64_push_reg (code, i);
			pos += 8;
		}

	/* Save EBP */
	pos += 8;
	amd64_push_reg (code, AMD64_RBP);

	/* Make stack misaligned, the call will make it aligned again */
	if (! (pos & 8))
		amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);

	gregs_offset = MONO_STRUCT_OFFSET (MonoContext, gregs);

	/* set new EBP */
	amd64_mov_reg_membase (code, AMD64_RBP, AMD64_ARG_REG1, gregs_offset + (AMD64_RBP * 8), 8);
	/* load callee saved regs */
	for (i = 0; i < AMD64_NREG; ++i) {
#if defined(__native_client_codegen__)
		if (i == AMD64_R15)
			continue;
#endif
		if (AMD64_IS_CALLEE_SAVED_REG (i) && i != AMD64_RBP)
			amd64_mov_reg_membase (code, i, AMD64_ARG_REG1, gregs_offset + (i * 8), 8);
	}
	/* load exc register */
	amd64_mov_reg_membase (code, AMD64_RAX, AMD64_ARG_REG1,  gregs_offset + (AMD64_RAX * 8), 8);

	/* call the handler */
	amd64_call_reg (code, AMD64_ARG_REG2);

	if (! (pos & 8))
		amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);

	/* restore RBP */
	amd64_pop_reg (code, AMD64_RBP);

	/* Restore callee saved regs */
	for (i = AMD64_NREG; i >= 0; --i)
		if (AMD64_IS_CALLEE_SAVED_REG (i))
			amd64_pop_reg (code, i);

	amd64_leave (code);
	amd64_ret (code);

	g_assert ((code - start) < kMaxCodeSize);

	nacl_global_codeman_validate(&start, kMaxCodeSize, &code);

	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;
}
예제 #28
0
/**
 * arch_get_throw_exception_generic:
 *
 * 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) (char *exc_name);
 *
 */
static gpointer 
mono_arch_get_throw_exception_generic (guint8 *start, int size, int corlib, gboolean rethrow)
{
	guint8 *code;
	int alloc_size, pos, i;

	code = start;

	//g_print ("mono_arch_get_throw_exception_generic: code=%p\n", code);

	pos = 0;
	/* XXX - save all the FP regs on the stack ? */

	pos += MONO_MAX_IREGS * sizeof(guint32);

	alloc_size = MIPS_MINIMAL_STACK_SIZE + pos + 64;
	// align to MIPS_STACK_ALIGNMENT bytes
	alloc_size += MIPS_STACK_ALIGNMENT - 1;
	alloc_size &= ~(MIPS_STACK_ALIGNMENT - 1);

	g_assert ((alloc_size & (MIPS_STACK_ALIGNMENT-1)) == 0);
	mips_addiu (code, mips_sp, mips_sp, -alloc_size);
	mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);

	/* Save all the regs on the stack */
	for (i = 0; i < MONO_MAX_IREGS; i++) {
		if (i != mips_sp)
			MIPS_SW (code, i, mips_sp, i*IREG_SIZE + MIPS_STACK_PARAM_OFFSET);
		else {
			mips_addiu (code, mips_at, mips_sp, alloc_size);
			MIPS_SW (code, mips_at, mips_sp, i*IREG_SIZE + MIPS_STACK_PARAM_OFFSET);
		}
	}

	if (corlib) {
		mips_move (code, mips_a1, mips_a0);
		mips_load (code, mips_a0, mono_defaults.corlib);
		mips_load (code, mips_t9, mono_exception_from_token);
		mips_jalr (code, mips_t9, mips_ra);
		mips_nop (code);
		mips_move (code, mips_a0, mips_v0);
	}
	/* call throw_exception (exc, ip, sp, rethrow) */

	/* exc is already in place in a0 */

	/* pointer to ip */
	if (corlib)
		mips_lw (code, mips_a1, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
	else
		mips_move (code, mips_a1, mips_ra);

	/* current sp & rethrow */
	mips_move (code, mips_a2, mips_sp);
	mips_addiu (code, mips_a3, mips_zero, rethrow);

	mips_load (code, mips_t9, throw_exception);
	mips_jr (code, mips_t9);
	mips_nop (code);
	/* we should never reach this breakpoint */
	mips_break (code, 0xfe);

	g_assert ((code - start) < size);
	mono_arch_flush_icache (start, code - start);

	if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION)
		mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

	return start;
}
예제 #29
0
/*
 * mono_arch_get_call_filter:
 *
 * Returns a pointer to a method which calls an exception filter. We
 * also use this function to call finally handlers (we pass NULL as 
 * @exc object in this case).
 *
 * This function is invoked as
 *	call_handler (MonoContext *ctx, handler)
 *
 * Where 'handler' is a function to be invoked as:
 *	handler (void)
 */
gpointer
mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
{
	static guint8 start [320];
	static int inited = 0;
	guint8 *code;
	int alloc_size;
	int offset;

	g_assert (!aot);
	if (info)
		*info = NULL;

	if (inited)
		return start;

	inited = 1;
	code = start;

	alloc_size = 64;
	g_assert ((alloc_size & (MIPS_STACK_ALIGNMENT-1)) == 0);

	mips_addiu (code, mips_sp, mips_sp, -alloc_size);
	mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);

	/* Save global registers on stack (s0 - s7) */
	offset = 16;
	MIPS_SW (code, mips_s0, mips_sp, offset); offset += IREG_SIZE;
	MIPS_SW (code, mips_s1, mips_sp, offset); offset += IREG_SIZE;
	MIPS_SW (code, mips_s2, mips_sp, offset); offset += IREG_SIZE;
	MIPS_SW (code, mips_s3, mips_sp, offset); offset += IREG_SIZE;
	MIPS_SW (code, mips_s4, mips_sp, offset); offset += IREG_SIZE;
	MIPS_SW (code, mips_s5, mips_sp, offset); offset += IREG_SIZE;
	MIPS_SW (code, mips_s6, mips_sp, offset); offset += IREG_SIZE;
	MIPS_SW (code, mips_s7, mips_sp, offset); offset += IREG_SIZE;
	MIPS_SW (code, mips_fp, mips_sp, offset); offset += IREG_SIZE;

	/* Restore global registers from MonoContext, including the frame pointer */
	MIPS_LW (code, mips_s0, mips_a0, G_STRUCT_OFFSET (MonoContext, sc_regs[mips_s0]));
	MIPS_LW (code, mips_s1, mips_a0, G_STRUCT_OFFSET (MonoContext, sc_regs[mips_s1]));
	MIPS_LW (code, mips_s2, mips_a0, G_STRUCT_OFFSET (MonoContext, sc_regs[mips_s2]));
	MIPS_LW (code, mips_s3, mips_a0, G_STRUCT_OFFSET (MonoContext, sc_regs[mips_s3]));
	MIPS_LW (code, mips_s4, mips_a0, G_STRUCT_OFFSET (MonoContext, sc_regs[mips_s4]));
	MIPS_LW (code, mips_s5, mips_a0, G_STRUCT_OFFSET (MonoContext, sc_regs[mips_s5]));
	MIPS_LW (code, mips_s6, mips_a0, G_STRUCT_OFFSET (MonoContext, sc_regs[mips_s6]));
	MIPS_LW (code, mips_s7, mips_a0, G_STRUCT_OFFSET (MonoContext, sc_regs[mips_s7]));
	MIPS_LW (code, mips_fp, mips_a0, G_STRUCT_OFFSET (MonoContext, sc_regs[mips_fp]));

	/* a1 is the handler to call */
	mips_move (code, mips_t9, mips_a1);

	/* jump to the saved IP */
	mips_jalr (code, mips_t9, mips_ra);
	mips_nop (code);

	/* restore all regs from the stack */
	offset = 16;
	MIPS_LW (code, mips_s0, mips_sp, offset); offset += IREG_SIZE;
	MIPS_LW (code, mips_s1, mips_sp, offset); offset += IREG_SIZE;
	MIPS_LW (code, mips_s2, mips_sp, offset); offset += IREG_SIZE;
	MIPS_LW (code, mips_s3, mips_sp, offset); offset += IREG_SIZE;
	MIPS_LW (code, mips_s4, mips_sp, offset); offset += IREG_SIZE;
	MIPS_LW (code, mips_s5, mips_sp, offset); offset += IREG_SIZE;
	MIPS_LW (code, mips_s6, mips_sp, offset); offset += IREG_SIZE;
	MIPS_LW (code, mips_s7, mips_sp, offset); offset += IREG_SIZE;
	MIPS_LW (code, mips_fp, mips_sp, offset); offset += IREG_SIZE;

	/* epilog */
	mips_lw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
	mips_addiu (code, mips_sp, mips_sp, alloc_size);
	mips_jr (code, mips_ra);
	mips_nop (code);

	g_assert ((code - start) < sizeof(start));
	mono_arch_flush_icache (start, code - start);

	if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION)
		mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);

	return start;
}
예제 #30
0
/**
 * arch_get_throw_exception_generic:
 *
 * 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, gpointer ip)
 *
 */
static gpointer
mono_arch_get_throw_exception_generic (int size, MonoTrampInfo **info, int corlib, gboolean rethrow, gboolean aot)
{
	guint8 *start, *code;
	int alloc_size, pos;
	MonoJumpInfo *ji = NULL;
	GSList *unwind_ops = NULL;

	code = start = mono_global_codeman_reserve (size);
	if (!aot)
		code = mono_ppc_create_pre_code_ftnptr (code);

	/* store ret addr */
	if (corlib)
		ppc_mr (code, ppc_r0, ppc_r4);
	else
		ppc_mflr (code, ppc_r0);
	ppc_stptr (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);

	alloc_size = REG_SAVE_STACK_FRAME_SIZE;

	g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
	ppc_stptr_update (code, ppc_sp, -alloc_size, ppc_sp);

	code = emit_save_saved_regs (code, alloc_size);

	//ppc_break (code);
	if (corlib) {
		ppc_mr (code, ppc_r4, ppc_r3);

		if (aot) {
			code = mono_arch_emit_load_aotconst (start, code, &ji, MONO_PATCH_INFO_IMAGE, mono_defaults.corlib);
			ppc_mr (code, ppc_r3, ppc_r12);
			code = mono_arch_emit_load_aotconst (start, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_exception_from_token");
#ifdef PPC_USES_FUNCTION_DESCRIPTOR
			ppc_ldptr (code, ppc_r2, sizeof (gpointer), ppc_r12);
			ppc_ldptr (code, ppc_r12, 0, ppc_r12);
#endif
			ppc_mtctr (code, ppc_r12);
			ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
		} else {
			ppc_load (code, ppc_r3, (gulong)mono_defaults.corlib);
			ppc_load_func (code, PPC_CALL_REG, mono_exception_from_token);
			ppc_mtctr (code, PPC_CALL_REG);
			ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
		}
	}

	/* call throw_exception (exc, ip, sp, int_regs, fp_regs) */
	/* caller sp */
	ppc_ldptr (code, ppc_r5, 0, ppc_sp);
	/* exc is already in place in r3 */
	if (corlib)
		ppc_ldptr (code, ppc_r4, PPC_RET_ADDR_OFFSET, ppc_r5);
	else
		ppc_mr (code, ppc_r4, ppc_r0); /* caller ip */
	/* pointer to the saved fp regs */
	pos = alloc_size - sizeof (gdouble) * MONO_SAVED_FREGS;
	ppc_addi (code, ppc_r7, ppc_sp, pos);
	/* pointer to the saved int regs */
	pos -= sizeof (gpointer) * MONO_SAVED_GREGS;
	ppc_addi (code, ppc_r6, ppc_sp, pos);
	ppc_li (code, ppc_r8, rethrow);

	if (aot) {
		// This can be called from runtime code, which can't guarantee that
		// r30 contains the got address.
		// So emit the got address loading code too
		code = mono_arch_emit_load_got_addr (start, code, NULL, &ji);
		code = mono_arch_emit_load_aotconst (start, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_ppc_throw_exception");
#ifdef PPC_USES_FUNCTION_DESCRIPTOR
		ppc_ldptr (code, ppc_r2, sizeof (gpointer), ppc_r12);
		ppc_ldptr (code, ppc_r12, 0, ppc_r12);
#endif
		ppc_mtctr (code, ppc_r12);
		ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
	} else {
		ppc_load_func (code, PPC_CALL_REG, mono_ppc_throw_exception);
		ppc_mtctr (code, PPC_CALL_REG);
		ppc_bcctrl (code, PPC_BR_ALWAYS, 0);
	}
	/* we should never reach this breakpoint */
	ppc_break (code);
	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 (corlib ? "throw_corlib_exception" : (rethrow ? "rethrow_exception" : "throw_exception"), start, code - start, ji, unwind_ops);

	return start;
}