Example #1
0
/**
 * mono_arch_get_throw_corlib_exception:
 *
 * Returns a function pointer which can be used to raise 
 * corlib exceptions. The returned function has the following 
 * signature: void (*func) (guint32 ex_token, guint32 offset); 
 * Here, offset is the offset which needs to be substracted from the caller IP 
 * to get the IP of the throw. Passing the offset has the advantage that it 
 * needs no relocations in the caller.
 */
gpointer
mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
{
	static guint32 *start;
	static int inited = 0;
	guint32 *code;
	int reg;

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

	if (inited)
		return start;

	inited = 1;
	code = start = mono_global_codeman_reserve (64 * sizeof (guint32));

#ifdef SPARCV9
	reg = sparc_g4;
#else
	reg = sparc_g1;
#endif

	sparc_mov_reg_reg (code, sparc_o7, sparc_o2);
	sparc_save_imm (code, sparc_sp, -160, sparc_sp);

	sparc_set (code, MONO_TOKEN_TYPE_DEF, sparc_o7);
	sparc_add (code, FALSE, sparc_i0, sparc_o7, sparc_o1);
	sparc_set (code, mono_defaults.exception_class->image, sparc_o0);
	sparc_set (code, mono_exception_from_token, sparc_o7);
	sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
	sparc_nop (code);

	/* Return to the caller, so exception handling does not see this frame */
	sparc_restore (code, sparc_o0, sparc_g0, sparc_o0);

	/* Compute throw ip */
	sparc_sll_imm (code, sparc_o1, 2, sparc_o1);
	sparc_sub (code, 0, sparc_o2, sparc_o1, sparc_o7);

	sparc_set (code, mono_arch_get_throw_exception (NULL, FALSE), reg);
	/* Use a jmp instead of a call so o7 is preserved */
	sparc_jmpl_imm (code, reg, 0, sparc_g0);
	sparc_nop (code);

	g_assert ((code - start) < 32);

	mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start);

	return start;
}
Example #2
0
/**
 * mono_arch_get_throw_exception_by_name:
 *
 * Returns a function pointer which can be used to raise 
 * corlib exceptions. The returned function has the following 
 * signature: void (*func) (char *exc_name, gpointer ip); 
 */
gpointer 
mono_arch_get_throw_exception_by_name (void)
{
	static guint32 *start;
	static int inited = 0;
	guint32 *code;
	int reg;

	if (inited)
		return start;

	inited = 1;
	code = start = mono_global_codeman_reserve (64 * sizeof (guint32));

#ifdef SPARCV9
	reg = sparc_g4;
#else
	reg = sparc_g1;
#endif

	sparc_save_imm (code, sparc_sp, -160, sparc_sp);

	sparc_mov_reg_reg (code, sparc_i0, sparc_o2);
	sparc_set (code, mono_defaults.corlib, sparc_o0);
	sparc_set (code, "System", sparc_o1);
	sparc_set (code, mono_exception_from_name, sparc_o7);
	sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
	sparc_nop (code);

	/* Return to the caller, so exception handling does not see this frame */
	sparc_restore (code, sparc_o0, sparc_g0, sparc_o0);

	/* Put original return address into %o7 */
	sparc_mov_reg_reg (code, sparc_o1, sparc_o7);
	sparc_set (code, mono_arch_get_throw_exception (), reg);
	/* Use a jmp instead of a call so o7 is preserved */
	sparc_jmpl_imm (code, reg, 0, sparc_g0);
	sparc_nop (code);

	g_assert ((code - start) < 32);

	mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start);

	return start;
}
Example #3
0
File: tramp.c Project: ANahr/mono
static void
calculate_sizes (MonoMethodSignature *sig, guint *stack_size, guint *code_size,
		 gboolean string_ctor, gboolean *use_memcpy)
{
	guint i, fr, gr;
	guint32 simpletype;
	
	fr = gr = 0;
	*stack_size = MINIMAL_STACK_SIZE * SLOT_SIZE;
	*code_size = (PROLOG_INS + CALL_INS + EPILOG_INS) * 4;
	
	/* function arguments */
	if (sig->hasthis)
		add_general (&gr, stack_size, code_size, TRUE);
	
	for (i = 0; i < sig->param_count; i++) {
		if (sig->params[i]->byref) {
			add_general (&gr, stack_size, code_size, TRUE);
			continue;
		}
		simpletype = sig->params[i]->type;
	enum_calc_size:
		switch (simpletype) {
		case MONO_TYPE_R4:
#if SPARCV9
			(*code_size) += 4; /* for the fdtos */
#else
			(*code_size) += 12;
			(*stack_size) += 4;
#endif
		case MONO_TYPE_BOOLEAN:
		case MONO_TYPE_CHAR:
		case MONO_TYPE_I1:
		case MONO_TYPE_U1:
		case MONO_TYPE_I2:
		case MONO_TYPE_U2:
		case MONO_TYPE_I4:
		case MONO_TYPE_U4:
		case MONO_TYPE_I:
		case MONO_TYPE_U:
		case MONO_TYPE_PTR:
		case MONO_TYPE_CLASS:
		case MONO_TYPE_OBJECT:
		case MONO_TYPE_STRING:
		case MONO_TYPE_SZARRAY:
			add_general (&gr, stack_size, code_size, TRUE);
			break;
		case MONO_TYPE_VALUETYPE: {
			gint size;
			guint32 align;
			if (sig->params[i]->data.klass->enumtype) {
				simpletype = sig->params[i]->data.klass->enum_basetype->type;
				goto enum_calc_size;
			}
			size = mono_class_native_size (sig->params[i]->data.klass, &align);
#if SPARCV9
			if (size != 4) {
#else
			if (1) {
#endif
				DEBUG(fprintf(stderr, "copy %d byte struct on stack\n", size));
				*use_memcpy = TRUE;
				*code_size += 8*4;

				*stack_size = (*stack_size + (align - 1)) & (~(align -1));
				*stack_size += (size + 3) & (~3);
				if (gr > OUT_REGS) {
					*code_size += 4;
					*stack_size += 4;
				}
			} else {
				add_general (&gr, stack_size, code_size, TRUE);	
#if SPARCV9
				*code_size += 8;
#else
				*code_size += 4;
#endif
			}
			break;
		}
		case MONO_TYPE_I8:
		case MONO_TYPE_R8:
			add_general (&gr, stack_size, code_size, FALSE);
			break;
		default:
			g_error ("Can't trampoline 0x%x", sig->params[i]->type);
		}
	}
	
	/* function return value */
	if (sig->ret->byref || string_ctor) {
		*code_size += 8;
	} else {
		simpletype = sig->ret->type;
	enum_retvalue:
		switch (simpletype) {
		case MONO_TYPE_BOOLEAN:
		case MONO_TYPE_I1:
		case MONO_TYPE_U1:
		case MONO_TYPE_I2:
		case MONO_TYPE_U2:
		case MONO_TYPE_CHAR:
		case MONO_TYPE_I4:
		case MONO_TYPE_U4:
		case MONO_TYPE_I:
		case MONO_TYPE_U:
		case MONO_TYPE_CLASS:
		case MONO_TYPE_OBJECT:
		case MONO_TYPE_PTR:
		case MONO_TYPE_STRING:
		case MONO_TYPE_R4:
		case MONO_TYPE_R8:
		case MONO_TYPE_SZARRAY:
		case MONO_TYPE_ARRAY:
			*code_size += 8;
			break;
		case MONO_TYPE_I8:
			*code_size += 12;
			break;
		case MONO_TYPE_VALUETYPE: {
			gint size;
			if (sig->ret->data.klass->enumtype) {
				simpletype = sig->ret->data.klass->enum_basetype->type;
				goto enum_retvalue;
			}
			size = mono_class_native_size (sig->ret->data.klass, NULL);
#if SPARCV9
			if (size <= 32)
				*code_size += 8 + (size + 7) / 2;
			else
				*code_size += 8;
#else
			*code_size += 8;
#endif
			break;
		}
		case MONO_TYPE_VOID:
			break;
		default:
			g_error ("Can't handle as return value 0x%x", sig->ret->type);
		}
	}
	
	if (*use_memcpy) {
		*stack_size += 8;
		*code_size += 24;
		if (sig->hasthis) {
			*stack_size += SLOT_SIZE;
			*code_size += 4;
		}
	}
	
	*stack_size = (*stack_size + (FRAME_ALIGN - 1)) & (~(FRAME_ALIGN -1));
}	
	
static inline guint32 *
emit_epilog (guint32 *p, MonoMethodSignature *sig, guint stack_size)
{
	int ret_offset = 8;

	/*
	 * Standard epilog.
	 * 8 may be 12 when returning structures (to skip unimp opcode).
	 */
#if !SPARCV9
	if (sig != NULL && !sig->ret->byref && sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->data.klass->enumtype)
		ret_offset = 12;
#endif
	sparc_jmpl_imm (p, sparc_i7, ret_offset, sparc_zero);
	sparc_restore (p, sparc_zero, sparc_zero, sparc_zero);
	
	return p;
}
Example #4
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).
 *
 * call_filter (MonoContext *ctx, gpointer ip)
 */
gpointer
mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
{
	static guint32 *start;
	static int inited = 0;
	guint32 *code;
	int i;

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

	if (inited)
		return start;

	code = start = mono_global_codeman_reserve (64 * sizeof (guint32));

	/*
	 * There are two frames here:
	 * - the first frame is used by call_filter
	 * - the second frame is used to run the filter code
	 */

	/* Create first frame */
	sparc_save_imm (code, sparc_sp, -256, sparc_sp);

	sparc_mov_reg_reg (code, sparc_i1, sparc_o0);
	sparc_ldi_imm (code, sparc_i0, G_STRUCT_OFFSET (MonoContext, sp), sparc_o1);

	/* Create second frame */
	sparc_save_imm (code, sparc_sp, -256, sparc_sp);

	sparc_mov_reg_reg (code, sparc_i0, sparc_o0);
	sparc_mov_reg_reg (code, sparc_i1, sparc_o1);

	/*
	 * We need to change %fp to point to the stack frame of the method
	 * containing the filter. But changing %fp also changes the %sp of
	 * the parent frame (the first frame), so if the OS saves the first frame,
	 * it saves it to the stack frame of the method, which is not good.
	 * So flush all register windows to memory before changing %fp.
	 */
	sparc_flushw (code);

	sparc_mov_reg_reg (code, sparc_fp, sparc_o7);

	/* 
	 * Modify the second frame so it is identical to the one used in the
	 * method containing the filter.
	 */
	for (i = 0; i < 16; ++i)
		sparc_ldi_imm (code, sparc_o1, MONO_SPARC_STACK_BIAS + i * sizeof (gpointer), sparc_l0 + i);

	/* Save %fp to a location reserved in mono_arch_allocate_vars */
	sparc_sti_imm (code, sparc_o7, sparc_fp, MONO_SPARC_STACK_BIAS - sizeof (gpointer));

	/* Call the filter code, after this returns, %o0 will hold the result */
	sparc_call_imm (code, sparc_o0, 0);
	sparc_nop (code);

	/* Restore original %fp */
	sparc_ldi_imm (code, sparc_fp, MONO_SPARC_STACK_BIAS - sizeof (gpointer), sparc_fp);

	sparc_mov_reg_reg (code, sparc_o0, sparc_i0);

	/* Return to first frame */
	sparc_restore (code, sparc_g0, sparc_g0, sparc_g0);

	/* FIXME: Save locals to the stack */

	/* Return to caller */
	sparc_ret (code);
	/* Return result in delay slot */
	sparc_restore (code, sparc_o0, sparc_g0, sparc_o0);

	g_assert ((code - start) < 64);

	mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start);

	inited = 1;

	return start;
}