/** * 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; }
/* * mono_arch_get_unbox_trampoline: * @m: method pointer * @addr: pointer to native code for @m * * when value type methods are called through the vtable we need to unbox the * this argument. This method returns a pointer to a trampoline which does * unboxing before calling the method */ gpointer mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) { guint8 *code, *start; int reg; start = code = mono_global_codeman_reserve (36); /* This executes in the context of the caller, hence o0 */ sparc_add_imm (code, 0, sparc_o0, sizeof (MonoObject), sparc_o0); #ifdef SPARCV9 reg = sparc_g4; #else reg = sparc_g1; #endif sparc_set (code, addr, reg); sparc_jmpl (code, reg, sparc_g0, sparc_g0); sparc_nop (code); g_assert ((code - start) <= 36); mono_arch_flush_icache (start, code - start); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), NULL); return start; }
gpointer mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) { guint32 *code, *buf, *tramp; tramp = mono_get_trampoline_code (tramp_type); code = buf = mono_domain_code_reserve (domain, TRAMPOLINE_SIZE * 4); /* We have to use g5 here because there is no other free register */ sparc_set (code, tramp, sparc_g5); sparc_jmpl (code, sparc_g5, sparc_g0, sparc_g5); sparc_nop (code); #ifdef SPARCV9 g_assert_not_reached (); #else *code = (guint32)arg1; code ++; #endif g_assert ((code - buf) <= TRAMPOLINE_SIZE); if (code_len) *code_len = (code - buf) * 4; mono_arch_flush_icache ((guint8*)buf, (code - buf) * 4); return buf; }
/** * 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; }
static gpointer get_throw_exception (gboolean rethrow) { guint32 *start, *code; code = start = mono_global_codeman_reserve (16 * sizeof (guint32)); sparc_save_imm (code, sparc_sp, -512, sparc_sp); sparc_flushw (code); sparc_mov_reg_reg (code, sparc_i0, sparc_o0); sparc_mov_reg_reg (code, sparc_fp, sparc_o1); sparc_mov_reg_reg (code, sparc_i7, sparc_o2); sparc_set (code, rethrow, sparc_o3); sparc_set (code, throw_exception, sparc_o7); sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite); sparc_nop (code); g_assert ((code - start) <= 16); mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start); return start; }
void * mono_arch_create_method_pointer (MonoMethod *method) { MonoMethodSignature *sig; MonoJitInfo *ji; guint stack_size, code_size, stackval_arg_pos, local_pos; guint i, local_start, reg_param = 0, stack_param, cpos, vt_cur; guint32 align = 0; guint32 *p, *code_buffer; gint *vtbuf; gint32 simpletype; code_size = 1024; /* these should be calculated... */ stack_size = 1024; stack_param = 0; sig = method->signature; p = code_buffer = g_malloc (code_size); DEBUG(fprintf(stderr, "Delegate [start emiting] %s\n", method->name)); DEBUG(fprintf(stderr, "%s\n", sig_to_name(sig, FALSE))); p = emit_prolog (p, sig, stack_size); /* fill MonoInvocation */ sparc_st_imm_ptr (p, sparc_g0, sparc_sp, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex))); sparc_st_imm_ptr (p, sparc_g0, sparc_sp, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler))); sparc_st_imm_ptr (p, sparc_g0, sparc_sp, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent))); sparc_set_ptr (p, (void *)method, sparc_l0); sparc_st_imm_ptr (p, sparc_l0, sparc_sp, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method))); stackval_arg_pos = MINV_POS + sizeof (MonoInvocation); local_start = local_pos = stackval_arg_pos + (sig->param_count + 1) * sizeof (stackval); if (sig->hasthis) { sparc_st_imm_ptr (p, sparc_i0, sparc_sp, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj))); reg_param = 1; } if (sig->param_count) { gint save_count = MIN (OUT_REGS, sig->param_count + sig->hasthis); for (i = reg_param; i < save_count; i++) { sparc_st_imm_ptr (p, sparc_i0 + i, sparc_sp, local_pos); local_pos += SLOT_SIZE; } } /* prepare space for valuetypes */ vt_cur = local_pos; vtbuf = alloca (sizeof(int)*sig->param_count); cpos = 0; for (i = 0; i < sig->param_count; i++) { MonoType *type = sig->params [i]; vtbuf [i] = -1; if (!sig->params[i]->byref && type->type == MONO_TYPE_VALUETYPE) { MonoClass *klass = type->data.klass; gint size; if (klass->enumtype) continue; size = mono_class_native_size (klass, &align); cpos += align - 1; cpos &= ~(align - 1); vtbuf [i] = cpos; cpos += size; } } cpos += SLOT_SIZE - 1; cpos &= ~(SLOT_SIZE - 1); local_pos += cpos; /* set MonoInvocation::stack_args */ sparc_add_imm (p, 0, sparc_sp, stackval_arg_pos, sparc_l0); sparc_st_imm_ptr (p, sparc_l0, sparc_sp, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args))); /* add stackval arguments */ for (i=0; i < sig->param_count; i++) { int stack_offset; int type; if (reg_param < OUT_REGS) { stack_offset = local_start + i * SLOT_SIZE; reg_param++; } else { stack_offset = stack_size + 8 + stack_param; stack_param++; } if (!sig->params[i]->byref) { type = sig->params[i]->type; enum_arg: switch (type) { case MONO_TYPE_I8: case MONO_TYPE_U8: case MONO_TYPE_I: case MONO_TYPE_U: case MONO_TYPE_STRING: case MONO_TYPE_OBJECT: case MONO_TYPE_CLASS: case MONO_TYPE_SZARRAY: case MONO_TYPE_PTR: case MONO_TYPE_R8: break; case MONO_TYPE_I4: case MONO_TYPE_U4: stack_offset += SLOT_SIZE - 4; break; case MONO_TYPE_CHAR: case MONO_TYPE_I2: case MONO_TYPE_U2: stack_offset += SLOT_SIZE - 2; break; case MONO_TYPE_I1: case MONO_TYPE_U1: case MONO_TYPE_BOOLEAN: stack_offset += SLOT_SIZE - 1; break; case MONO_TYPE_VALUETYPE: if (sig->params[i]->data.klass->enumtype) { type = sig->params[i]->data.klass->enum_basetype->type; goto enum_arg; } g_assert(vtbuf[i] >= 0); break; default: g_error ("can not cope with delegate arg type %d", type); } } sparc_add_imm (p, 0, sparc_sp, stack_offset, sparc_o2); if (vtbuf[i] >= 0) { sparc_add_imm (p, 0, sparc_sp, vt_cur, sparc_o1); sparc_st_imm_ptr (p, sparc_o1, sparc_sp, stackval_arg_pos); sparc_add_imm (p, 0, sparc_sp, stackval_arg_pos, sparc_o1); sparc_ld_imm_ptr (p, sparc_o2, 0, sparc_o2); vt_cur += vtbuf[i]; } else { sparc_add_imm (p, 0, sparc_sp, stackval_arg_pos, sparc_o1); } sparc_set_ptr (p, (void *)sig->params[i], sparc_o0); sparc_set (p, (guint32)sig->pinvoke, sparc_o3); /* YOU make the CALL! */ sparc_set_ptr (p, (void *)stackval_from_data, sparc_l0); sparc_jmpl_imm (p, sparc_l0, 0, sparc_callsite); sparc_nop (p); stackval_arg_pos += sizeof(stackval); } /* return value storage */ /* Align to dword */ stackval_arg_pos = (stackval_arg_pos + (8 - 1)) & (~(8 -1)); if (sig->param_count) { sparc_add_imm (p, 0, sparc_sp, stackval_arg_pos, sparc_l0); } if (!sig->ret->byref && sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->data.klass->enumtype) { #if !SPARCV9 /* pass on callers buffer */ sparc_ld_imm_ptr (p, sparc_fp, 64, sparc_l1); sparc_st_imm_ptr (p, sparc_l1, sparc_l0, 0); #else sparc_add_imm (p, 0, sparc_l0, sizeof(stackval), sparc_l1); sparc_st_imm_ptr (p, sparc_l1, sparc_l0, 0); #endif } sparc_st_imm_ptr (p, sparc_l0, sparc_sp, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval))); /* call ves_exec_method */ sparc_add_imm (p, 0, sparc_sp, MINV_POS, sparc_o0); sparc_set_ptr (p, (void *)ves_exec_method, sparc_l0); sparc_jmpl_imm (p, sparc_l0, 0, sparc_callsite); sparc_nop (p); /* move retval from stackval to proper place (r3/r4/...) */ if (sig->ret->byref) { sparc_ld_imm_ptr (p, sparc_sp, stackval_arg_pos, sparc_i0 ); } else { enum_retvalue: switch (sig->ret->type) { case MONO_TYPE_VOID: break; case MONO_TYPE_BOOLEAN: case MONO_TYPE_I1: case MONO_TYPE_U1: case MONO_TYPE_I2: case MONO_TYPE_U2: case MONO_TYPE_I4: case MONO_TYPE_U4: sparc_ld_imm (p, sparc_sp, stackval_arg_pos, sparc_i0); break; case MONO_TYPE_I: case MONO_TYPE_U: case MONO_TYPE_OBJECT: case MONO_TYPE_STRING: case MONO_TYPE_CLASS: sparc_ld_imm_ptr (p, sparc_sp, stackval_arg_pos, sparc_i0); break; case MONO_TYPE_I8: case MONO_TYPE_U8: #if SPARCV9 sparc_ldx_imm (p, sparc_sp, stackval_arg_pos, sparc_i0); #else sparc_ld_imm (p, sparc_sp, stackval_arg_pos, sparc_i0); sparc_ld_imm (p, sparc_sp, stackval_arg_pos + 4, sparc_i1); #endif break; case MONO_TYPE_R4: sparc_lddf_imm (p, sparc_sp, stackval_arg_pos, sparc_f0); sparc_fdtos(p, sparc_f0, sparc_f0); break; case MONO_TYPE_R8: sparc_lddf_imm (p, sparc_sp, stackval_arg_pos, sparc_f0); break; case MONO_TYPE_VALUETYPE: { gint size; gint reg = sparc_i0; if (sig->ret->data.klass->enumtype) { simpletype = sig->ret->data.klass->enum_basetype->type; goto enum_retvalue; } #if SPARCV9 size = mono_class_native_size (sig->ret->data.klass, NULL); sparc_ldx_imm (p, sparc_sp, stackval_arg_pos, sparc_l0); if (size <= 16) { gint off = 0; if (size >= 8) { sparc_ldx_imm (p, sparc_l0, 0, reg); size -= 8; off += 8; reg++; } if (size > 0) sparc_ldx_imm (p, sparc_l0, off, reg); } else NOT_IMPL("value type as ret val from delegate"); #endif break; } default: g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type); break; } } p = emit_epilog (p, sig, stack_size); for (i = 0; i < ((p - code_buffer)/2); i++) flushi((code_buffer + (i*8))); ji = g_new0 (MonoJitInfo, 1); ji->method = method; ji->code_size = p - code_buffer; ji->code_start = code_buffer; mono_jit_info_table_add (mono_get_root_domain (), ji); DEBUG(sparc_disassemble_code (code_buffer, p, method->name)); DEBUG(fprintf(stderr, "Delegate [end emiting] %s\n", method->name)); return ji->code_start; }
static inline guint32* emit_save_parameters (guint32 *p, MonoMethodSignature *sig, guint stack_size, gboolean use_memcpy) { guint i, fr, gr, stack_par_pos, struct_pos, cur_struct_pos; guint32 simpletype; fr = gr = 0; stack_par_pos = MINIMAL_STACK_SIZE * SLOT_SIZE + BIAS; if (sig->hasthis) { if (use_memcpy) { /* we don't need to save a thing. */ } else sparc_mov_reg_reg (p, sparc_i2, sparc_o0); gr ++; } if (use_memcpy) { cur_struct_pos = struct_pos = stack_par_pos; for (i = 0; i < sig->param_count; i++) { if (sig->params[i]->byref) continue; if (sig->params[i]->type == MONO_TYPE_VALUETYPE && !sig->params[i]->data.klass->enumtype) { gint size; guint32 align; size = mono_class_native_size (sig->params[i]->data.klass, &align); #if SPARCV9 if (size != 4) { #else if (1) { #endif /* Add alignment */ stack_par_pos = (stack_par_pos + (align - 1)) & (~(align - 1)); /* need to call memcpy here */ sparc_add_imm (p, 0, sparc_sp, stack_par_pos, sparc_o0); sparc_ld_imm_ptr (p, sparc_i3, i*16, sparc_o1); sparc_set (p, (guint32)size, sparc_o2); sparc_set_ptr (p, (void *)memmove, sparc_l0); sparc_jmpl_imm (p, sparc_l0, 0, sparc_callsite); sparc_nop (p); stack_par_pos += (size + (SLOT_SIZE - 1)) & (~(SLOT_SIZE - 1)); } } } } if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) { MonoClass *klass = sig->ret->data.klass; if (!klass->enumtype) { gint size = mono_class_native_size (klass, NULL); DEBUG(fprintf(stderr, "retval value type size: %d\n", size)); #if SPARCV9 if (size > 32) { #else { #endif /* pass on buffer in interp.c to called function */ sparc_ld_imm_ptr (p, sparc_i1, 0, sparc_l0); sparc_st_imm_ptr (p, sparc_l0, sparc_sp, 64); } } } DEBUG(fprintf(stderr, "%s\n", sig_to_name(sig, FALSE))); for (i = 0; i < sig->param_count; i++) { if (sig->params[i]->byref) { SAVE_PTR_IN_GENERIC_REGISTER; continue; } simpletype = sig->params[i]->type; enum_calc_size: 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: if (gr < OUT_REGS) { sparc_ld_imm (p, ARG_BASE, i*ARG_SIZE, sparc_o0 + gr); gr++; } else { sparc_ld_imm (p, ARG_BASE, i*ARG_SIZE, sparc_l0); sparc_st_imm_word (p, sparc_l0, sparc_sp, stack_par_pos); stack_par_pos += SLOT_SIZE; } break; case MONO_TYPE_R4: #if SPARCV9 sparc_lddf_imm (p, ARG_BASE, i*ARG_SIZE, sparc_f30); /* fix using this fixed reg */ sparc_fdtos(p, sparc_f30, sparc_f0 + 2 * gr + 1); gr++; break; #else /* Convert from double to single */ sparc_lddf_imm (p, ARG_BASE, i*ARG_SIZE, sparc_f0); sparc_fdtos (p, sparc_f0, sparc_f0); /* * FIXME: Is there an easier way to do an * freg->ireg move ? */ sparc_stf_imm (p, sparc_f0, sparc_sp, stack_par_pos); if (gr < OUT_REGS) { sparc_ld_imm (p, sparc_sp, stack_par_pos, sparc_o0 + gr); gr++; } else { sparc_ldf_imm (p, sparc_sp, stack_par_pos, sparc_f0); sparc_stf_imm (p, sparc_f0, sparc_sp, stack_par_pos); stack_par_pos += SLOT_SIZE; } break; #endif 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: SAVE_PTR_IN_GENERIC_REGISTER; break; case MONO_TYPE_VALUETYPE: { gint size; guint32 align; MonoClass *klass = sig->params[i]->data.klass; if (klass->enumtype) { simpletype = klass->enum_basetype->type; goto enum_calc_size; } size = mono_class_native_size (klass, &align); #if SPARCV9 if (size <= 16) { if (gr < OUT_REGS) { p = v9_struct_arg(p, i, klass, size, &gr); } else { sparc_ld_imm_ptr (p, ARG_BASE, i*ARG_SIZE, sparc_l0); sparc_ld_imm (p, sparc_l0, 0, sparc_l0); sparc_st_imm_word (p, sparc_l0, sparc_sp, stack_par_pos); stack_par_pos += SLOT_SIZE; } break; } #else /* * FIXME: The 32bit ABI docs do not mention that small * structures are passed in registers. */ /* if (size == 4) { if (gr < OUT_REGS) { sparc_ld_imm_ptr (p, ARG_BASE, i*ARG_SIZE, sparc_l0); sparc_ld_imm (p, sparc_l0, 0, sparc_o0 + gr); gr++; } else { sparc_ld_imm_ptr (p, ARG_BASE, i*ARG_SIZE, sparc_l0); sparc_ld_imm (p, sparc_l0, 0, sparc_l0); sparc_st_imm_word (p, sparc_l0, sparc_sp, stack_par_pos); stack_par_pos += SLOT_SIZE; } break; } */ #endif cur_struct_pos = (cur_struct_pos + (align - 1)) & (~(align - 1)); if (gr < OUT_REGS) { sparc_add_imm (p, 0, sparc_sp, cur_struct_pos, sparc_o0 + gr); gr ++; } else { sparc_ld_imm_ptr (p, sparc_sp, cur_struct_pos, sparc_l1); sparc_st_imm_ptr (p, sparc_l1, sparc_sp, stack_par_pos); } cur_struct_pos += (size + (SLOT_SIZE - 1)) & (~(SLOT_SIZE - 1)); break; } #if SPARCV9 case MONO_TYPE_I8: if (gr < OUT_REGS) { sparc_ldx_imm (p, ARG_BASE, i*ARG_SIZE, sparc_o0 + gr); gr++; } else { sparc_ldx_imm (p, ARG_BASE, i*ARG_SIZE, sparc_l0); sparc_stx_imm (p, sparc_l0, sparc_sp, stack_par_pos); stack_par_pos += SLOT_SIZE; } break; case MONO_TYPE_R8: sparc_lddf_imm (p, ARG_BASE, i*ARG_SIZE, sparc_f0 + 2 * i); break; #else case MONO_TYPE_I8: case MONO_TYPE_R8: if (gr < (OUT_REGS - 1)) { sparc_ld_imm (p, ARG_BASE, i*ARG_SIZE, sparc_o0 + gr); gr ++; sparc_ld_imm (p, ARG_BASE, (i*ARG_SIZE) + 4, sparc_o0 + gr); gr ++; } else if (gr == (OUT_REGS - 1)) { /* Split register/stack */ sparc_ld_imm (p, ARG_BASE, i*ARG_SIZE, sparc_o0 + gr); gr ++; sparc_ld_imm (p, ARG_BASE, (i*ARG_SIZE) + 4, sparc_l0); sparc_st_imm (p, sparc_l0, sparc_sp, stack_par_pos); stack_par_pos += SLOT_SIZE; } else { sparc_ld_imm (p, ARG_BASE, i*ARG_SIZE, sparc_l0); sparc_st_imm (p, sparc_l0, sparc_sp, stack_par_pos); stack_par_pos += SLOT_SIZE; sparc_ld_imm (p, ARG_BASE, (i*ARG_SIZE) + 4, sparc_l0); sparc_st_imm (p, sparc_l0, sparc_sp, stack_par_pos); stack_par_pos += SLOT_SIZE; } break; #endif default: g_error ("Can't trampoline 0x%x", sig->params[i]->type); } } g_assert ((stack_par_pos - BIAS) <= stack_size); return p; } static inline guint32 * alloc_code_memory (guint code_size) { guint32 *p; p = g_malloc(code_size); return p; } static inline guint32 * emit_call_and_store_retval (guint32 *p, MonoMethodSignature *sig, guint stack_size, gboolean string_ctor) { guint32 simpletype; /* call "callme" */ sparc_jmpl_imm (p, sparc_i0, 0, sparc_callsite); sparc_nop (p); #if !SPARCV9 if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->data.klass->enumtype) { int size = mono_class_native_size (sig->ret->data.klass, NULL); sparc_unimp (p, size & 4095); } #endif /* get return value */ if (sig->ret->byref || string_ctor) { sparc_st_ptr (p, sparc_o0, sparc_i1, 0); } else { simpletype = sig->ret->type; enum_retval: switch (simpletype) { case MONO_TYPE_BOOLEAN: case MONO_TYPE_I1: case MONO_TYPE_U1: sparc_stb (p, sparc_o0, sparc_i1, 0); break; case MONO_TYPE_CHAR: case MONO_TYPE_I2: case MONO_TYPE_U2: sparc_sth (p, sparc_o0, sparc_i1, 0); break; case MONO_TYPE_I4: case MONO_TYPE_U4: sparc_st (p, sparc_o0, sparc_i1, 0); break; case MONO_TYPE_I: case MONO_TYPE_U: case MONO_TYPE_CLASS: case MONO_TYPE_OBJECT: case MONO_TYPE_SZARRAY: case MONO_TYPE_ARRAY: case MONO_TYPE_STRING: case MONO_TYPE_PTR: sparc_st_ptr (p, sparc_o0, sparc_i1, 0); break; case MONO_TYPE_R4: sparc_stf (p, sparc_f0, sparc_i1, 0); break; case MONO_TYPE_R8: sparc_stdf (p, sparc_f0, sparc_i1, 0); break; case MONO_TYPE_I8: #if SPARCV9 sparc_stx (p, sparc_o0, sparc_i1, 0); #else sparc_std (p, sparc_o0, sparc_i1, 0); #endif break; case MONO_TYPE_VALUETYPE: { gint size; if (sig->ret->data.klass->enumtype) { simpletype = sig->ret->data.klass->enum_basetype->type; goto enum_retval; } #if SPARCV9 size = mono_class_native_size (sig->ret->data.klass, NULL); if (size <= 32) { int n_regs = size / 8; int j; sparc_ldx_imm (p, sparc_i1, 0, sparc_i1); /* wrong if there are floating values in the struct... */ for (j = 0; j < n_regs; j++) { sparc_stx_imm (p, sparc_o0 + j, sparc_i1, j * 8); } size -= n_regs * 8; if (size > 0) { int last_reg = sparc_o0 + n_regs; /* get value right aligned in register */ sparc_srlx_imm(p, last_reg, 64 - 8 * size, last_reg); if ((size & 1) != 0) { sparc_stb_imm (p, last_reg, sparc_i1, n_regs * 8 + size - 1); size--; if (size > 0) sparc_srlx_imm(p, last_reg, 8, last_reg); } if ((size & 2) != 0) { sparc_sth_imm (p, last_reg, sparc_i1, n_regs * 8 + size - 2); size -= 2; if (size > 0) sparc_srlx_imm(p, last_reg, 16, last_reg); } if ((size & 4) != 0) sparc_st_imm (p, last_reg, sparc_i1, n_regs * 8); } } #endif } case MONO_TYPE_VOID: break; default: g_error ("Can't handle as return value 0x%x", sig->ret->type); } } return p; }
/* * 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; }
guchar* mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot) { guint8 *buf, *code, *tramp_addr; guint32 lmf_offset, regs_offset, method_reg, i; gboolean has_caller; g_assert (!aot); *info = NULL; if (tramp_type == MONO_TRAMPOLINE_JUMP) has_caller = FALSE; else has_caller = TRUE; code = buf = mono_global_codeman_reserve (1024); sparc_save_imm (code, sparc_sp, -1608, sparc_sp); #ifdef SPARCV9 method_reg = sparc_g4; #else method_reg = sparc_g1; #endif regs_offset = MONO_SPARC_STACK_BIAS + 1000; /* Save r1 needed by the IMT code */ sparc_sti_imm (code, sparc_g1, sparc_sp, regs_offset + (sparc_g1 * sizeof (gpointer))); /* * sparc_g5 contains the return address, the trampoline argument is stored in the * instruction stream after the call. */ sparc_ld_imm (code, sparc_g5, 8, method_reg); #ifdef SPARCV9 /* Save fp regs since they are not preserved by calls */ for (i = 0; i < 16; i ++) sparc_stdf_imm (code, sparc_f0 + (i * 2), sparc_sp, MONO_SPARC_STACK_BIAS + 320 + (i * 8)); #endif /* We receive the method address in %r1, so save it here */ sparc_sti_imm (code, method_reg, sparc_sp, MONO_SPARC_STACK_BIAS + 200); /* Save lmf since compilation can raise exceptions */ lmf_offset = MONO_SPARC_STACK_BIAS - sizeof (MonoLMF); /* Save the data for the parent (managed) frame */ /* Save ip */ sparc_sti_imm (code, sparc_i7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ip)); /* Save sp */ sparc_sti_imm (code, sparc_fp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, sp)); /* Save fp */ /* Load previous fp from the saved register window */ sparc_flushw (code); sparc_ldi_imm (code, sparc_fp, MONO_SPARC_STACK_BIAS + (sparc_i6 - 16) * sizeof (gpointer), sparc_o7); sparc_sti_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp)); /* Save method */ sparc_sti_imm (code, method_reg, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method)); sparc_set (code, mono_get_lmf_addr, sparc_o7); sparc_jmpl (code, sparc_o7, sparc_g0, sparc_o7); sparc_nop (code); code = mono_sparc_emit_save_lmf (code, lmf_offset); if (has_caller) { /* Load all registers of the caller into a table inside this frame */ /* first the out registers */ for (i = 0; i < 8; ++i) sparc_sti_imm (code, sparc_i0 + i, sparc_sp, regs_offset + ((sparc_o0 + i) * sizeof (gpointer))); /* then the in+local registers */ for (i = 0; i < 16; i ++) { sparc_ldi_imm (code, sparc_fp, MONO_SPARC_STACK_BIAS + (i * sizeof (gpointer)), sparc_o7); sparc_sti_imm (code, sparc_o7, sparc_sp, regs_offset + ((sparc_l0 + i) * sizeof (gpointer))); } } tramp_addr = mono_get_trampoline_func (tramp_type); sparc_ldi_imm (code, sparc_sp, MONO_SPARC_STACK_BIAS + 200, sparc_o2); /* pass address of register table as third argument */ sparc_add_imm (code, FALSE, sparc_sp, regs_offset, sparc_o0); sparc_set (code, tramp_addr, sparc_o7); /* set %o1 to caller address */ if (has_caller) sparc_mov_reg_reg (code, sparc_i7, sparc_o1); else sparc_set (code, 0, sparc_o1); sparc_set (code, 0, sparc_o3); sparc_jmpl (code, sparc_o7, sparc_g0, sparc_o7); sparc_nop (code); /* Save result */ sparc_sti_imm (code, sparc_o0, sparc_sp, MONO_SPARC_STACK_BIAS + 304); /* Check for thread interruption */ sparc_set (code, (guint8*)mono_thread_force_interruption_checkpoint, sparc_o7); sparc_jmpl (code, sparc_o7, sparc_g0, sparc_o7); sparc_nop (code); /* Restore lmf */ code = mono_sparc_emit_restore_lmf (code, lmf_offset); /* Reload result */ sparc_ldi_imm (code, sparc_sp, MONO_SPARC_STACK_BIAS + 304, sparc_o0); #ifdef SPARCV9 /* Reload fp regs */ for (i = 0; i < 16; i ++) sparc_lddf_imm (code, sparc_sp, MONO_SPARC_STACK_BIAS + 320 + (i * 8), sparc_f0 + (i * 2)); #endif sparc_jmpl (code, sparc_o0, sparc_g0, sparc_g0); /* restore previous frame in delay slot */ sparc_restore_simple (code); /* { gpointer addr; sparc_save_imm (code, sparc_sp, -608, sparc_sp); addr = code; sparc_call_simple (code, 16); sparc_nop (code); sparc_rett_simple (code); sparc_nop (code); sparc_save_imm (code, sparc_sp, -608, sparc_sp); sparc_ta (code, 1); tramp_addr = &sparc_magic_trampoline; sparc_call_simple (code, tramp_addr - code); sparc_nop (code); sparc_rett_simple (code); sparc_nop (code); } */ g_assert ((code - buf) <= 512); mono_arch_flush_icache (buf, code - buf); return buf; }
void mono_arch_nullify_class_init_trampoline (guint8 *code, mgreg_t *regs) { /* Patch calling code */ sparc_nop (code); }