#include <unistd.h>
#ifndef __linux__
-#include <sys/systeminfo.h>
#include <thread.h>
#endif
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/tokentype.h>
#include <mono/utils/mono-math.h>
+#include <mono/utils/mono-hwcap-sparc.h>
#include "mini-sparc.h"
#include "trace.h"
#endif
-/* Whenever the CPU supports v9 instructions */
-static gboolean sparcv9 = FALSE;
-
/* Whenever this is a 64bit executable */
#if SPARCV9
static gboolean v64 = TRUE;
void
mono_arch_cpu_init (void)
{
- guint32 dummy;
- /* make sure sparcv9 is initialized for embedded use */
- mono_arch_cpu_optimizations(&dummy);
}
/*
guint32
mono_arch_cpu_optimizations (guint32 *exclude_mask)
{
- char buf [1024];
guint32 opts = 0;
*exclude_mask = 0;
-#ifndef __linux__
- if (!sysinfo (SI_ISALIST, buf, 1024))
- g_assert_not_reached ();
-#else
- /* From glibc. If the getpagesize is 8192, we're on sparc64, which
- * (in)directly implies that we're a v9 or better.
- * Improvements to this are greatly accepted...
- * Also, we don't differentiate between v7 and v8. I sense SIGILL
- * sniffing in my future.
- */
- if (getpagesize() == 8192)
- strcpy (buf, "sparcv9");
- else
- strcpy (buf, "sparcv8");
-#endif
-
- /*
+ /*
* On some processors, the cmov instructions are even slower than the
* normal ones...
*/
- if (strstr (buf, "sparcv9")) {
+ if (mono_hwcap_sparc_is_v9)
opts |= MONO_OPT_CMOV | MONO_OPT_FCMOV;
- sparcv9 = TRUE;
- }
else
*exclude_mask |= MONO_OPT_CMOV | MONO_OPT_FCMOV;
*
* Sparcv8 needs a flush every 8 bytes.
*/
- align = (sparcv9 ? 32 : 8);
+ align = (mono_hwcap_sparc_is_v9 ? 32 : 8);
start &= ~(align - 1);
end = (end + (align - 1)) & ~(align - 1);
gboolean
mono_sparc_is_v9 (void) {
- return sparcv9;
+ return mono_hwcap_sparc_is_v9;
}
gboolean
guint32 stack_size = 0;
CallInfo *cinfo;
MonoType *ret_type;
- MonoGenericSharingContext *gsctx = cfg ? cfg->generic_sharing_context : NULL;
cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
add_general (&gr, &stack_size, ainfo, FALSE);
continue;
}
- ptype = mono_type_get_underlying_type (sig->params [i]);
- ptype = mini_get_basic_type_from_generic (gsctx, ptype);
+ ptype = mini_get_underlying_type (sig->params [i]);
switch (ptype->type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
}
/* return value */
- ret_type = mono_type_get_underlying_type (sig->ret);
- ret_type = mini_get_basic_type_from_generic (gsctx, ret_type);
+ ret_type = mini_get_underlying_type (sig->ret);
switch (ret_type->type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
cfg->ret->inst_c0 = cinfo->ret.reg;
break;
case ArgInIRegPair: {
- MonoType *t = mono_type_get_underlying_type (sig->ret);
+ MonoType *t = mini_get_underlying_type (sig->ret);
if (((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
- MonoInst *low = get_vreg_to_inst (cfg, cfg->ret->dreg + 1);
- MonoInst *high = get_vreg_to_inst (cfg, cfg->ret->dreg + 2);
+ MonoInst *low = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->ret->dreg));
+ MonoInst *high = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->ret->dreg));
low->opcode = OP_REGVAR;
low->dreg = cinfo->ret.reg + 1;
if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
else
- size = mini_type_stack_size (cfg->generic_sharing_context, inst->inst_vtype, &align);
+ size = mini_type_stack_size (inst->inst_vtype, &align);
/*
* This is needed since structures containing doubles must be doubleword
break;
case ArgInIRegPair:
if (inst->type == STACK_I8) {
- MonoInst *low = get_vreg_to_inst (cfg, inst->dreg + 1);
- MonoInst *high = get_vreg_to_inst (cfg, inst->dreg + 2);
+ MonoInst *low = get_vreg_to_inst (cfg, MONO_LVREG_LS (inst->dreg));
+ MonoInst *high = get_vreg_to_inst (cfg, MONO_LVREG_MS (inst->dreg));
low->opcode = OP_REGVAR;
low->dreg = sparc_i0 + ainfo->reg + 1;
}
if (!sig->ret->byref && (sig->ret->type == MONO_TYPE_I8 || sig->ret->type == MONO_TYPE_U8)) {
- MonoInst *low = get_vreg_to_inst (cfg, cfg->ret->dreg + 1);
- MonoInst *high = get_vreg_to_inst (cfg, cfg->ret->dreg + 2);
+ MonoInst *low = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->ret->dreg));
+ MonoInst *high = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->ret->dreg));
low->flags |= MONO_INST_VOLATILE;
high->flags |= MONO_INST_VOLATILE;
switch (ainfo->storage) {
case ArgInIRegPair:
- add_outarg_reg (cfg, call, ArgInIReg, sparc_o0 + ainfo->reg + 1, in->dreg + 1);
- add_outarg_reg (cfg, call, ArgInIReg, sparc_o0 + ainfo->reg, in->dreg + 2);
+ add_outarg_reg (cfg, call, ArgInIReg, sparc_o0 + ainfo->reg + 1, MONO_LVREG_LS (in->dreg));
+ add_outarg_reg (cfg, call, ArgInIReg, sparc_o0 + ainfo->reg, MONO_LVREG_MS (in->dreg));
break;
case ArgOnStackPair:
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, offset, in->dreg + 2);
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, offset + 4, in->dreg + 1);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, offset, MONO_LVREG_MS (in->dreg));
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, offset + 4, MONO_LVREG_LS (in->dreg));
break;
case ArgInSplitRegStack:
- add_outarg_reg (cfg, call, ArgInIReg, sparc_o0 + ainfo->reg, in->dreg + 2);
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, offset + 4, in->dreg + 1);
+ add_outarg_reg (cfg, call, ArgInIReg, sparc_o0 + ainfo->reg, MONO_LVREG_MS (in->dreg));
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, offset + 4, MONO_LVREG_LS (in->dreg));
break;
default:
g_assert_not_reached ();
else
arg_type = sig->params [i - sig->hasthis];
- arg_type = mono_type_get_underlying_type (arg_type);
+ arg_type = mini_get_underlying_type (arg_type);
if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis])))
emit_pass_vtype (cfg, call, cinfo, ainfo, arg_type, in, sig->pinvoke);
else if (!arg_type->byref && ((arg_type->type == MONO_TYPE_I8) || (arg_type->type == MONO_TYPE_U8)))
mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
{
CallInfo *cinfo = get_call_info (cfg, mono_method_signature (method), FALSE);
- MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
+ MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
switch (cinfo->ret.storage) {
case ArgInIReg:
if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
MONO_EMIT_NEW_UNALU (cfg, OP_LMOVE, cfg->ret->dreg, val->dreg);
} else {
- MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg + 2, val->dreg + 2);
- MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg + 1, val->dreg + 1);
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (cfg->ret->dreg), MONO_LVREG_MS (val->dreg));
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (cfg->ret->dreg), MONO_LVREG_LS (val->dreg));
}
break;
case ArgInFReg:
#define EMIT_COND_SYSTEM_EXCEPTION_GENERAL(ins,cond,sexc_name,filldelay,icc) do { \
mono_add_patch_info (cfg, (guint8*)(code) - (cfg)->native_code, \
MONO_PATCH_INFO_EXC, sexc_name); \
- if (sparcv9 && ((icc) != sparc_icc_short)) { \
+ if (mono_hwcap_sparc_is_v9 && ((icc) != sparc_icc_short)) { \
sparc_branchp (code, 0, (cond), (icc), 0, 0); \
} \
else { \
static guint32*
emit_call (MonoCompile *cfg, guint32 *code, guint32 patch_type, gconstpointer data)
{
+ MonoError error;
gpointer target;
/* FIXME: This only works if the target method is already compiled */
patch_info.type = patch_type;
patch_info.data.target = data;
- target = mono_resolve_patch_target (cfg->method, cfg->domain, NULL, &patch_info, FALSE);
+ target = mono_resolve_patch_target (cfg->method, cfg->domain, NULL, &patch_info, FALSE, &error);
+ mono_error_raise_exception (&error); /* FIXME: don't raise here */
/* FIXME: Add optimizations if the target is close enough */
sparc_set (code, target, sparc_o7);
((ins->inst_offset == last_ins->inst_offset - 4)) &&
(ins->inst_imm == 0) &&
(last_ins->inst_imm == 0)) {
- if (sparcv9) {
+ if (mono_hwcap_sparc_is_v9) {
last_ins->opcode = OP_STOREI8_MEMBASE_IMM;
last_ins->inst_offset = ins->inst_offset;
MONO_DELETE_INS (bb, ins);
{
switch (ins->opcode) {
case OP_LNEG:
- MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, 0, ins->sreg1 + 1);
- MONO_EMIT_NEW_BIALU (cfg, OP_SBB, ins->dreg + 2, 0, ins->sreg1 + 2);
+ MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, MONO_LVREG_LS (ins->dreg), 0, MONO_LVREG_LS (ins->sreg1));
+ MONO_EMIT_NEW_BIALU (cfg, OP_SBB, MONO_LVREG_MS (ins->dreg), 0, MONO_LVREG_MS (ins->sreg1));
NULLIFY_INS (ins);
break;
default:
}
static guint32*
-emit_vret_token (MonoGenericSharingContext *gsctx, MonoInst *ins, guint32 *code)
+emit_vret_token (MonoInst *ins, guint32 *code)
{
MonoCallInst *call = (MonoCallInst*)ins;
guint32 size;
*/
if (call->signature->pinvoke && MONO_TYPE_ISSTRUCT(call->signature->ret)) {
if (call->signature->ret->type == MONO_TYPE_TYPEDBYREF)
- size = mini_type_stack_size (gsctx, call->signature->ret, NULL);
+ size = mini_type_stack_size (call->signature->ret, NULL);
else
size = mono_class_native_size (call->signature->ret->data.klass, NULL);
sparc_unimp (code, size & 0xfff);
mono_stats.imt_thunks_size += (code - start) * 4;
g_assert (code - start <= size);
+
+ mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
return start;
}
else
code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
- code = emit_vret_token (cfg->generic_sharing_context, ins, code);
+ code = emit_vret_token (ins, code);
code = emit_move_return_value (ins, code);
break;
case OP_FCALL_REG:
else
sparc_nop (code);
- code = emit_vret_token (cfg->generic_sharing_context, ins, code);
+ code = emit_vret_token (ins, code);
code = emit_move_return_value (ins, code);
break;
case OP_FCALL_MEMBASE:
else
sparc_nop (code);
- code = emit_vret_token (cfg->generic_sharing_context, ins, code);
+ code = emit_vret_token (ins, code);
code = emit_move_return_value (ins, code);
break;
case OP_SETFRET:
sparc_branch (code, 0, sparc_be, 0);
/* delay slot */
sparc_set (code, 0, sparc_o7);
- sparc_sub_imm (code, 0, size_reg, sparcv9 ? 8 : 4, size_reg);
+ sparc_sub_imm (code, 0, size_reg, mono_hwcap_sparc_is_v9 ? 8 : 4, size_reg);
/* start of loop */
br [1] = code;
- if (sparcv9)
+ if (mono_hwcap_sparc_is_v9)
sparc_stx (code, sparc_g0, ins->dreg, sparc_o7);
else
sparc_st (code, sparc_g0, ins->dreg, sparc_o7);
sparc_branch (code, 0, sparc_bl, 0);
sparc_patch (br [2], br [1]);
/* delay slot */
- sparc_add_imm (code, 0, sparc_o7, sparcv9 ? 8 : 4, sparc_o7);
+ sparc_add_imm (code, 0, sparc_o7, mono_hwcap_sparc_is_v9 ? 8 : 4, sparc_o7);
sparc_patch (br [0], code);
}
break;
if (offset <= 16) {
i = 0;
while (i < offset) {
- if (sparcv9) {
+ if (mono_hwcap_sparc_is_v9) {
sparc_stx_imm (code, sparc_g0, ins->dreg, i);
i += 8;
}
}
else {
sparc_set (code, offset, sparc_o7);
- sparc_sub_imm (code, 0, sparc_o7, sparcv9 ? 8 : 4, sparc_o7);
+ sparc_sub_imm (code, 0, sparc_o7, mono_hwcap_sparc_is_v9 ? 8 : 4, sparc_o7);
/* beginning of loop */
br [0] = code;
- if (sparcv9)
+ if (mono_hwcap_sparc_is_v9)
sparc_stx (code, sparc_g0, ins->dreg, sparc_o7);
else
sparc_st (code, sparc_g0, ins->dreg, sparc_o7);
br [1] = code;
sparc_branch (code, 0, sparc_bne, 0);
/* delay slot */
- sparc_sub_imm (code, 0, sparc_o7, sparcv9 ? 8 : 4, sparc_o7);
+ sparc_sub_imm (code, 0, sparc_o7, mono_hwcap_sparc_is_v9 ? 8 : 4, sparc_o7);
sparc_patch (br [1], br [0]);
}
}
case OP_IBGE_UN:
case OP_IBLE:
case OP_IBLE_UN: {
- if (sparcv9)
+ if (mono_hwcap_sparc_is_v9)
EMIT_COND_BRANCH_PREDICTED (ins, opcode_to_sparc_cond (ins->opcode), 1, 1);
else
EMIT_COND_BRANCH (ins, opcode_to_sparc_cond (ins->opcode), 1, 1);
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");
+ EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_be, "OverflowException");
#ifdef SPARCV9
sparc_fmovd (code, ins->sreg1, ins->dreg);
#else
case OP_MEMORY_BARRIER:
sparc_membar (code, sparc_membar_all);
break;
+ case OP_GC_SAFE_POINT:
+ break;
default:
#ifdef __GNUC__
}
void
-mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
+mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
{
+ MonoError error;
MonoJumpInfo *patch_info;
/* FIXME: Move part of this to arch independent code */
unsigned char *ip = patch_info->ip.i + code;
gpointer target;
- target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
+ target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, &error);
+ mono_error_raise_exception (&error); /* FIXME: don't raise here */
switch (patch_info->type) {
case MONO_PATCH_INFO_NONE:
continue;
- case MONO_PATCH_INFO_CLASS_INIT: {
- guint32 *ip2 = (guint32*)ip;
- /* Might already been changed to a nop */
-#ifdef SPARCV9
- sparc_set_template (ip2, sparc_o7);
- sparc_jmpl (ip2, sparc_o7, sparc_g0, sparc_o7);
-#else
- sparc_call_simple (ip2, 0);
-#endif
- break;
- }
case MONO_PATCH_INFO_METHOD_JUMP: {
guint32 *ip2 = (guint32*)ip;
/* Might already been patched */
int save_mode = SAVE_NONE;
MonoMethod *method = cfg->method;
- switch (mono_type_get_underlying_type (mono_method_signature (method)->ret)->type) {
+ switch (mini_get_underlying_type (mono_method_signature (method)->ret)->type) {
case MONO_TYPE_VOID:
/* special case string .ctor icall */
if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
sparc_patch ((guint32*)(cfg->native_code + patch_info->ip.i), code);
- exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
- g_assert (exc_class);
+ exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
type_idx = exc_class->type_token - MONO_TOKEN_TYPE_DEF;
throw_ip = patch_info->ip.i;
#endif
void
-mono_arch_finish_init (void)
+mono_arch_tls_init (void)
{
+ MonoJitTlsData *jit_tls;
+
if (!lmf_addr_key_inited) {
int res;
}
+ jit_tls = mono_get_jit_tls ();
+
#ifdef MONO_SPARC_THR_TLS
- thr_setspecific (lmf_addr_key, &tls->lmf);
+ thr_setspecific (lmf_addr_key, &jit_tls->lmf);
#else
- pthread_setspecific (lmf_addr_key, &tls->lmf);
+ pthread_setspecific (lmf_addr_key, &jit_tls->lmf);
#endif
}
+void
+mono_arch_finish_init (void)
+{
+}
+
void
mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
{
return 0;
}
-MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
-{
- return NULL;
-}
-
mgreg_t
mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
{
/* FIXME: implement */
g_assert_not_reached ();
}
+
+gboolean
+mono_arch_opcode_supported (int opcode)
+{
+ return FALSE;
+}