提交 d35860a2 编写于 作者: Z Zoltan Varga

2004-03-11 Zoltan Varga <vargaz@freemail.hu>

	* mini-sparc.h mini-sparc.c tramp-sparc.c exceptions-sparc.c: Ongoing
	sparc work.

svn path=/trunk/mono/; revision=23928
上级 bcebc6cc
2004-03-11 Zoltan Varga <vargaz@freemail.hu>
* mini-sparc.h mini-sparc.c tramp-sparc.c exceptions-sparc.c: Ongoing
sparc work.
* basic-float.cs basic-calls.cs: New regression tests.
2004-03-10 Zoltan Varga <vargaz@freemail.hu>
......
......@@ -391,7 +391,37 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
}
void
mono_jit_walk_stack (MonoStackWalk func, gpointer user_data) {
mono_jit_walk_stack (MonoStackWalk func, gpointer user_data)
{
MonoDomain *domain = mono_domain_get ();
MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
MonoLMF *lmf = jit_tls->lmf;
MonoJitInfo *ji, rji;
gint native_offset, il_offset;
gboolean managed;
MonoContext ctx, new_ctx;
mono_sparc_flushw ();
MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (1));
while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
ji = mono_arch_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
g_assert (ji);
if (ji == (gpointer)-1)
return;
il_offset = mono_debug_il_offset_from_address (ji->method, native_offset, domain);
if (func (ji->method, native_offset, il_offset, managed, user_data))
return;
ctx = new_ctx;
}
}
MonoBoolean
......
......@@ -197,7 +197,7 @@ mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
}
#ifdef __GNUC__
#define flushi(addr) __asm__ __volatile__ ("flush %0"::"r"(addr):"memory")
#define flushi(addr) __asm__ __volatile__ ("iflush %0"::"r"(addr):"memory")
#else /* assume Sun's compiler */
static void flushi(void *addr)
{
......@@ -208,17 +208,51 @@ static void flushi(void *addr)
void
mono_arch_flush_icache (guint8 *code, gint size)
{
guint64 *p = (guint64*)code;
guint64 *end = (guint64*)(code + ((size + 8) /8));
/*
* FIXME: This might not work on older machines, but flushing code in dword
* chunks in _slow_.
* FIXME: Flushing code in dword chunks in _slow_.
*/
flushi (code);
/*
for (i = 0; i < (size/8); i++)
flushi(code + (i*8));
*/
while (p < end)
#ifdef __GNUC__
__asm__ __volatile__ ("iflush %0"::"r"(p++));
#else
flushi (p ++);
#endif
}
/*
* mono_sparc_flushw:
*
* Flush all register windows to memory. Every register window is saved to
* a 16 word area on the stack pointed to by its %sp register.
*/
void
mono_sparc_flushw (void)
{
static guint32 start [64];
static int inited = 0;
guint32 *code;
static void (*flushw) (void);
if (!inited) {
code = start;
sparc_save_imm (code, sparc_sp, -160, sparc_sp);
sparc_flushw (code);
sparc_ret (code);
sparc_restore_simple (code);
g_assert ((code - start) < 64);
flushw = (gpointer)start;
inited = 1;
}
flushw ();
}
typedef enum {
......@@ -329,7 +363,6 @@ get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
enum_calc_size:
switch (simpletype) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_CHAR:
case MONO_TYPE_I1:
case MONO_TYPE_U1:
add_general (&gr, &stack_size, ainfo, FALSE);
......@@ -338,6 +371,7 @@ get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
break;
case MONO_TYPE_I2:
case MONO_TYPE_U2:
case MONO_TYPE_CHAR:
add_general (&gr, &stack_size, ainfo, FALSE);
/* the value is in the ls word */
ainfo->offset += 2;
......@@ -444,7 +478,9 @@ mono_arch_allocate_vars (MonoCompile *m)
MonoInst *inst;
int i, offset, size, align, curinst;
CallInfo *cinfo;
if (strstr (m->method->name, "pass_byref_double"))
printf ("FOO");
header = ((MonoMethodNormal *)m->method)->header;
sig = m->method->signature;
......@@ -540,8 +576,8 @@ mono_arch_allocate_vars (MonoCompile *m)
else
arg_type = sig->params [i - sig->hasthis];
if ((arg_type->type == MONO_TYPE_R4)
|| (arg_type->type == MONO_TYPE_R8))
if (!arg_type->byref && ((arg_type->type == MONO_TYPE_R4)
|| (arg_type->type == MONO_TYPE_R8)))
/*
* Since float arguments are passed in integer registers, we need to
* save them to the stack in the prolog.
......@@ -576,7 +612,7 @@ mono_arch_allocate_vars (MonoCompile *m)
inst->inst_basereg = sparc_fp;
inst->inst_offset = ainfo->offset + 68;
if (arg_type->type == MONO_TYPE_R8) {
if (!arg_type->byref && (arg_type->type == MONO_TYPE_R8)) {
/*
* It is very hard to load doubles from non-doubleword aligned
* memory locations. So if the offset is misaligned, we copy the
......@@ -1922,6 +1958,23 @@ sparc_patch (guint8 *code, const guint8 *target)
// g_print ("patched with 0x%08x\n", ins);
}
static guint32*
emit_save_sp_to_lmf (MonoCompile *cfg, guint32 *code)
{
/*
* Since register windows are saved to the current value of %sp, we need to
* set the sp field in the lmf before the call, not in the prolog.
*/
if (cfg->method->save_lmf) {
gint32 lmf_offset = - cfg->arch.lmf_offset;
/* Save sp */
sparc_st_imm (code, sparc_sp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, sp));
}
return code;
}
static guint32*
emit_vret_token (MonoInst *ins, guint32 *code)
{
......@@ -2015,6 +2068,43 @@ mono_sparc_is_virtual_call (guint32 *code)
return FALSE;
}
/*
* mono_sparc_get_vcall_slot_addr:
*
* Determine the vtable slot used by a virtual call.
*/
gpointer*
mono_sparc_get_vcall_slot_addr (guint32 *code, guint32 *fp)
{
guint32 ins = code [0];
guint32 prev_ins = code [-1];
mono_sparc_flushw ();
if ((sparc_inst_op (ins) == 0x2) && (sparc_inst_op3 (ins) == 0x38)) {
if ((sparc_inst_op (prev_ins) == 0x3) && (sparc_inst_op3 (prev_ins) == 0)) {
/* ld [r1 + CONST ], r2; call r2 */
guint32 base = sparc_inst_rs1 (prev_ins);
guint32 disp = sparc_inst_imm13 (prev_ins);
guint32 base_val;
g_assert (sparc_inst_rd (prev_ins) == sparc_inst_rs1 (ins));
g_assert ((base >= sparc_o0) && (base <= sparc_i7));
base_val = fp [base - 16];
return (gpointer)((guint8*)base_val + disp);
}
else
g_assert_not_reached ();
}
else
g_assert_not_reached ();
return FALSE;
}
/*
* Some conventions used in the following code.
* 2) The only scratch registers we have are o7 and g1. We try to
......@@ -2323,7 +2413,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
sparc_mov_reg_reg (code, ins->sreg1, ins->dreg);
break;
case CEE_JMP:
g_assert_not_reached ();
if (cfg->method->save_lmf)
NOT_IMPLEMENTED;
mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
sparc_set (code, 0xffffff, sparc_o7);
sparc_jmpl (code, sparc_o7, sparc_g0, sparc_g0);
/* Restore parent frame in delay slot */
sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
/* FIXME: Need to handle arguments */
NOT_IMPLEMENTED;
break;
case OP_CHECK_THIS:
/* ensure ins->sreg1 is not NULL */
......@@ -2336,10 +2435,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
case CEE_CALL:
call = (MonoCallInst*)ins;
g_assert (!call->virtual);
code = emit_save_sp_to_lmf (cfg, code);
if (ins->flags & MONO_INST_HAS_METHOD)
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_METHOD, call->method);
else
mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_ABS, call->fptr);
sparc_call_simple (code, 0);
sparc_nop (code);
......@@ -2352,6 +2452,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
case OP_VOIDCALL_REG:
case OP_CALL_REG:
call = (MonoCallInst*)ins;
code = emit_save_sp_to_lmf (cfg, code);
sparc_jmpl (code, ins->sreg1, sparc_g0, sparc_callsite);
/*
* We emit a special kind of nop in the delay slot to tell the
......@@ -2373,7 +2474,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
case OP_CALL_MEMBASE:
call = (MonoCallInst*)ins;
g_assert (sparc_is_imm13 (ins->inst_offset));
code = emit_save_sp_to_lmf (cfg, code);
sparc_ld_imm (code, ins->inst_basereg, ins->inst_offset, sparc_o7);
sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
if (call->virtual)
......@@ -2645,13 +2746,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
}
case OP_FCONV_TO_I8:
case OP_FCONV_TO_U8:
NOT_IMPLEMENTED;
/* Emulated */
g_assert_not_reached ();
break;
case CEE_CONV_R_UN:
NOT_IMPLEMENTED;
/* Emulated */
g_assert_not_reached ();
break;
case OP_LCONV_TO_R_UN: {
NOT_IMPLEMENTED;
/* Emulated */
g_assert_not_reached ();
break;
}
case OP_LCONV_TO_OVF_I: {
......@@ -2783,7 +2887,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu);
break;
case CEE_CKFINITE: {
NOT_IMPLEMENTED;
guint32 offset = mono_spillvar_offset_float (cfg, 0);
if (!sparc_is_imm13 (offset))
NOT_IMPLEMENTED;
sparc_stdf_imm (code, ins->sreg1, sparc_sp, offset);
sparc_lduh_imm (code, sparc_sp, offset, sparc_o7);
sparc_srl_imm (code, sparc_o7, 4, sparc_o7);
sparc_and_imm (code, FALSE, sparc_o7, 2047, sparc_o7);
sparc_cmp_imm (code, sparc_o7, 2047);
EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_be, "ArithmeticException");
sparc_fmovs (code, ins->sreg1, ins->dreg);
sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
break;
}
default:
......@@ -2828,97 +2942,27 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono
unsigned char *ip = patch_info->ip.i + code;
const unsigned char *target = NULL;
switch (patch_info->type) {
case MONO_PATCH_INFO_BB:
target = patch_info->data.bb->native_offset + code;
break;
case MONO_PATCH_INFO_ABS:
target = patch_info->data.target;
break;
case MONO_PATCH_INFO_LABEL:
target = patch_info->data.inst->inst_c0 + code;
break;
case MONO_PATCH_INFO_IP:
target = ip;
break;
case MONO_PATCH_INFO_METHOD_REL:
target = code + patch_info->data.offset;
if (ip == 0xfdec419c)
printf ("X: %p %p.\n", ip, target);
break;
case MONO_PATCH_INFO_INTERNAL_METHOD: {
MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
if (!mi) {
g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
g_assert_not_reached ();
}
target = mono_icall_get_wrapper (mi);
break;
}
case MONO_PATCH_INFO_METHOD_JUMP: {
GSList *list;
target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
/* get the trampoline to the method from the domain */
target = mono_arch_create_jump_trampoline (patch_info->data.method);
if (!domain->jump_target_hash)
domain->jump_target_hash = g_hash_table_new (NULL, NULL);
list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
list = g_slist_prepend (list, ip);
g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
break;
}
case MONO_PATCH_INFO_METHOD:
if (patch_info->data.method == method) {
target = code;
} else
/* get the trampoline to the method from the domain */
target = mono_arch_create_jit_trampoline (patch_info->data.method);
break;
case MONO_PATCH_INFO_SWITCH: {
guint32 *p = (guint32*)ip;
gpointer *jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->table_size);
int i;
target = jump_table;
for (i = 0; i < patch_info->table_size; i++) {
jump_table [i] = code + (int)patch_info->data.table [i];
}
break;
}
switch (patch_info->type) {
case MONO_PATCH_INFO_METHODCONST:
case MONO_PATCH_INFO_CLASS:
case MONO_PATCH_INFO_IMAGE:
case MONO_PATCH_INFO_FIELD:
NOT_IMPLEMENTED;
*((gconstpointer *)(ip + 1)) = patch_info->data.target;
continue;
case MONO_PATCH_INFO_IID:
NOT_IMPLEMENTED;
mono_class_init (patch_info->data.klass);
*((guint32 *)(ip + 1)) = patch_info->data.klass->interface_id;
continue;
case MONO_PATCH_INFO_VTABLE:
NOT_IMPLEMENTED;
*((gconstpointer *)(ip + 1)) = mono_class_vtable (domain, patch_info->data.klass);
continue;
case MONO_PATCH_INFO_CLASS_INIT: {
/* Might already been changed to a nop */
target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
/* FIXME: Might already been changed to a nop */
break;
}
case MONO_PATCH_INFO_SFLDA: {
MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (vtable->klass, method))
/* Done by the generated code */
;
else {
if (run_cctors)
mono_runtime_class_init (vtable);
}
NOT_IMPLEMENTED;
*((gconstpointer *)(ip + 1)) =
(char*)vtable->data + patch_info->data.field->offset;
continue;
}
case MONO_PATCH_INFO_R4: {
......@@ -2933,43 +2977,17 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono
target = d;
break;
}
case MONO_PATCH_INFO_EXC_NAME:
target = patch_info->data.name;
break;
case MONO_PATCH_INFO_LDSTR:
NOT_IMPLEMENTED;
*((gconstpointer *)(ip + 1)) =
mono_ldstr (domain, patch_info->data.token->image,
mono_metadata_token_index (patch_info->data.token->token));
continue;
case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
gpointer handle;
MonoClass *handle_class;
handle = mono_ldtoken (patch_info->data.token->image,
patch_info->data.token->token, &handle_class);
mono_class_init (handle_class);
mono_class_init (mono_class_from_mono_type (handle));
NOT_IMPLEMENTED;
*((gconstpointer *)(ip + 1)) =
mono_type_get_object (domain, handle);
continue;
}
case MONO_PATCH_INFO_LDTOKEN: {
gpointer handle;
MonoClass *handle_class;
handle = mono_ldtoken (patch_info->data.token->image,
patch_info->data.token->token, &handle_class);
mono_class_init (handle_class);
NOT_IMPLEMENTED;
*((gconstpointer *)(ip + 1)) = handle;
continue;
}
default:
g_assert_not_reached ();
}
sparc_patch (ip, target);
}
......@@ -3228,7 +3246,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
sparc_st_imm (code, sparc_i5, inst->inst_basereg, stack_offset);
}
if (arg_type->type == MONO_TYPE_R8) {
if (!arg_type->byref && (arg_type->type == MONO_TYPE_R8)) {
/* Save the argument to a dword aligned stack location */
/*
* stack_offset contains the offset of the argument on the stack.
......@@ -3359,7 +3377,14 @@ mono_arch_emit_epilog (MonoCompile *cfg)
sparc_st (code, sparc_l0, sparc_l1, sparc_g0);
}
sparc_ret (code);
/*
* The sparc ABI requires that calls to functions which return a structure
* return to %i7+12
*/
if (cfg->method->signature->pinvoke && MONO_TYPE_ISSTRUCT(cfg->method->signature->ret))
sparc_jmpl_imm (code, sparc_i7, 12, sparc_g0);
else
sparc_ret (code);
sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
/* add code to raise exceptions */
......
......@@ -38,4 +38,8 @@ typedef struct MonoCompileArch {
gboolean mono_sparc_is_virtual_call (guint32 *code);
gpointer* mono_sparc_get_vcall_slot_addr (guint32 *code, guint32 *fp);
void mono_sparc_flushw (void);
#endif /* __MONO_MINI_SPARC_H__ */
......@@ -72,6 +72,7 @@ get_unbox_trampoline (MonoMethod *m, gpointer addr)
* sparc_magic_trampoline:
* @m: the method to translate
* @code: the address of the call instruction
* @fp: address of the stack frame for the caller
*
* This method is called by the trampoline functions for methods. It calls the
* JIT compiler to compile the method, then patches the calling instruction so
......@@ -79,9 +80,10 @@ get_unbox_trampoline (MonoMethod *m, gpointer addr)
* address of the vtable slot and updates it.
*/
static gpointer
sparc_magic_trampoline (MonoMethod *m, guint32 *code)
sparc_magic_trampoline (MonoMethod *m, guint32 *code, guint32 *fp)
{
gpointer addr;
gpointer *vtable_slot;
addr = mono_compile_method (m);
g_assert (addr);
......@@ -95,6 +97,15 @@ sparc_magic_trampoline (MonoMethod *m, guint32 *code)
if (mono_sparc_is_virtual_call (code)) {
if (m->klass->valuetype)
addr = get_unbox_trampoline (m, addr);
/* Compute address of vtable slot */
vtable_slot = mono_sparc_get_vcall_slot_addr (code, fp);
*vtable_slot = addr;
}
else {
/* Patch calling code */
if (sparc_inst_op (*code) == 0x1)
sparc_call_simple (code, (guint8*)addr - (guint8*)code);
}
return addr;
......@@ -143,6 +154,8 @@ create_trampoline_code (MonoTrampolineType tramp_type)
tramp_addr = &sparc_class_init_trampoline;
else
tramp_addr = &sparc_magic_trampoline;
/* pass parent frame address as third argument */
sparc_mov_reg_reg (code, sparc_fp, sparc_o2);
sparc_call_simple (code, tramp_addr - code);
/* set %o1 to caller address in delay slot */
sparc_mov_reg_reg (code, sparc_i7, sparc_o1);
......@@ -208,7 +221,7 @@ create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type)
MonoJitInfo*
mono_arch_create_jump_trampoline (MonoMethod *method)
{
MonoJitInfo *ji = create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC);
MonoJitInfo *ji = create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP);
ji->method = method;
return ji;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册