#include <mono/utils/mono-mmap.h>
#include <mono/utils/mono-hwcap-arm.h>
#include <mono/utils/mono-memory-model.h>
+#include <mono/utils/mono-threads-coop.h>
#include "mini-arm.h"
#include "mini-arm-tls.h"
void
mono_arch_flush_icache (guint8 *code, gint size)
{
-#if defined(MONO_CROSS_COMPILE) || defined(__native_client__)
- // For Native Client we don't have to flush i-cache here,
- // as it's being done by dyncode interface.
+#if defined(MONO_CROSS_COMPILE)
#elif __APPLE__
sys_icache_invalidate (code, size);
#else
cinfo->ret.nregs = nfields;
cinfo->ret.esize = esize;
} else {
- if (is_pinvoke && mono_class_native_size (mono_class_from_mono_type (t), &align) <= sizeof (gpointer))
- cinfo->ret.storage = RegTypeStructByVal;
- else
+ if (is_pinvoke) {
+ int native_size = mono_class_native_size (mono_class_from_mono_type (t), &align);
+ int max_size;
+
+#ifdef TARGET_WATCHOS
+ max_size = 16;
+#else
+ max_size = 4;
+#endif
+ if (native_size <= max_size) {
+ cinfo->ret.storage = RegTypeStructByVal;
+ cinfo->ret.struct_size = native_size;
+ cinfo->ret.nregs = ALIGN_TO (native_size, 4) / 4;
+ } else {
+ cinfo->ret.storage = RegTypeStructByAddr;
+ }
+ } else {
cinfo->ret.storage = RegTypeStructByAddr;
+ }
}
break;
case MONO_TYPE_VAR:
size = mini_type_stack_size_full (t, &align, FALSE);
}
DEBUG(g_print ("load %d bytes struct\n", size));
+
+#ifdef TARGET_WATCHOS
+ /* Watchos pass large structures by ref */
+ /* We only do this for pinvoke to make gsharedvt/dyncall simpler */
+ if (sig->pinvoke && size > 16) {
+ add_general (&gr, &stack_size, ainfo, TRUE);
+ switch (ainfo->storage) {
+ case RegTypeGeneral:
+ ainfo->storage = RegTypeStructByAddr;
+ break;
+ case RegTypeBase:
+ ainfo->storage = RegTypeStructByAddrOnStack;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+ }
+#endif
+
align_size = size;
nwords = 0;
align_size += (sizeof (gpointer) - 1);
switch (cinfo->ret.storage) {
case RegTypeStructByVal:
- cfg->ret->opcode = OP_REGOFFSET;
- cfg->ret->inst_basereg = cfg->frame_reg;
- offset += sizeof (gpointer) - 1;
- offset &= ~(sizeof (gpointer) - 1);
- cfg->ret->inst_offset = - offset;
- offset += sizeof(gpointer);
- break;
case RegTypeHFA:
/* Allocate a local to hold the result, the epilog will copy it to the correct place */
offset = ALIGN_TO (offset, 8);
cfg->ret->opcode = OP_REGOFFSET;
cfg->ret->inst_basereg = cfg->frame_reg;
cfg->ret->inst_offset = offset;
- // FIXME:
- offset += 32;
+ if (cinfo->ret.storage == RegTypeStructByVal)
+ offset += cinfo->ret.nregs * sizeof (gpointer);
+ else
+ offset += 32;
break;
case RegTypeStructByAddr:
ins = cfg->vret_addr;
linfo->ret.storage = LLVMArgVtypeRetAddr;
linfo->vret_arg_index = cinfo->vret_arg_index;
break;
+#if TARGET_WATCHOS
+ case RegTypeStructByVal:
+ /* LLVM models this by returning an int array */
+ linfo->ret.storage = LLVMArgAsIArgs;
+ linfo->ret.nslots = cinfo->ret.nregs;
+ break;
+#endif
default:
cfg->exception_message = g_strdup_printf ("unknown ret conv (%d)", cinfo->ret.storage);
cfg->disable_llvm = TRUE;
}
for (i = 0; i < n; ++i) {
+ LLVMArgInfo *lainfo = &linfo->args [i];
ainfo = cinfo->args + i;
- linfo->args [i].storage = LLVMArgNone;
+ lainfo->storage = LLVMArgNone;
switch (ainfo->storage) {
case RegTypeGeneral:
case RegTypeBase:
case RegTypeBaseGen:
case RegTypeFP:
- linfo->args [i].storage = LLVMArgNormal;
+ lainfo->storage = LLVMArgNormal;
break;
case RegTypeStructByVal:
- linfo->args [i].storage = LLVMArgAsIArgs;
- linfo->args [i].nslots = ainfo->struct_size / sizeof (gpointer);
+ lainfo->storage = LLVMArgAsIArgs;
+ lainfo->nslots = ainfo->struct_size / sizeof (gpointer);
+ break;
+ case RegTypeStructByAddr:
+ case RegTypeStructByAddrOnStack:
+ lainfo->storage = LLVMArgVtypeByRef;
break;
default:
cfg->exception_message = g_strdup_printf ("ainfo->storage (%d)", ainfo->storage);
switch (cinfo->ret.storage) {
case RegTypeStructByVal:
- /* The JIT will transform this into a normal call */
- call->vret_in_reg = TRUE;
- break;
case RegTypeHFA:
+ if (cinfo->ret.storage == RegTypeStructByVal && cinfo->ret.nregs == 1) {
+ /* The JIT will transform this into a normal call */
+ call->vret_in_reg = TRUE;
+ break;
+ }
+ if (call->inst.opcode == OP_TAILCALL)
+ break;
/*
* The vtype is returned in registers, save the return area address in a local, and save the vtype into
* the location pointed to by it after call in emit_move_return_value ().
mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
}
break;
- case RegTypeStructByAddr:
- NOT_IMPLEMENTED;
-#if 0
- /* FIXME: where si the data allocated? */
- arg->backend.reg3 = ainfo->reg;
- call->used_iregs |= 1 << ainfo->reg;
- g_assert_not_reached ();
-#endif
- break;
case RegTypeStructByVal:
case RegTypeGSharedVtInReg:
case RegTypeGSharedVtOnStack:
case RegTypeHFA:
+ case RegTypeStructByAddr:
+ case RegTypeStructByAddrOnStack:
MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
ins->opcode = OP_OUTARG_VT;
ins->sreg1 = in->dreg;
switch (ainfo->storage) {
case RegTypeGSharedVtInReg:
+ case RegTypeStructByAddr:
/* Pass by addr */
mono_call_inst_add_outarg_reg (cfg, call, src->dreg, ainfo->reg, FALSE);
break;
case RegTypeGSharedVtOnStack:
+ case RegTypeStructByAddrOnStack:
/* Pass by addr on stack */
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, src->dreg);
break;
cinfo = call->call_info;
switch (cinfo->ret.storage) {
+ case RegTypeStructByVal:
case RegTypeHFA: {
MonoInst *loc = cfg->arch.vret_addr_loc;
int i;
+ if (cinfo->ret.storage == RegTypeStructByVal && cinfo->ret.nregs == 1) {
+ /* The JIT treats this as a normal call */
+ break;
+ }
+
/* Load the destination address */
g_assert (loc && loc->opcode == OP_REGOFFSET);
code = mono_arm_emit_load_imm (code, ARMREG_LR, loc->inst_offset);
ARM_LDR_REG_REG (code, ARMREG_LR, loc->inst_basereg, ARMREG_LR);
}
- for (i = 0; i < cinfo->ret.nregs; ++i) {
- if (cinfo->ret.esize == 4)
- ARM_FSTS (code, cinfo->ret.reg + i, ARMREG_LR, i * 4);
- else
- ARM_FSTD (code, cinfo->ret.reg + (i * 2), ARMREG_LR, i * 8);
+
+ if (cinfo->ret.storage == RegTypeStructByVal) {
+ int rsize = cinfo->ret.struct_size;
+
+ for (i = 0; i < cinfo->ret.nregs; ++i) {
+ g_assert (rsize >= 0);
+ switch (rsize) {
+ case 0:
+ break;
+ case 1:
+ ARM_STRB_IMM (code, i, ARMREG_LR, i * 4);
+ break;
+ case 2:
+ ARM_STRH_IMM (code, i, ARMREG_LR, i * 4);
+ break;
+ default:
+ ARM_STR_IMM (code, i, ARMREG_LR, i * 4);
+ break;
+ }
+ rsize -= 4;
+ }
+ } else {
+ for (i = 0; i < cinfo->ret.nregs; ++i) {
+ if (cinfo->ret.esize == 4)
+ ARM_FSTS (code, cinfo->ret.reg + i, ARMREG_LR, i * 4);
+ else
+ ARM_FSTD (code, cinfo->ret.reg + (i * 2), ARMREG_LR, i * 8);
+ }
}
return code;
}
break;
}
- ARM_DMB (code, ARM_DMB_SY);
+ if (ins->backend.memory_barrier_kind != MONO_MEMORY_BARRIER_NONE)
+ ARM_DMB (code, ARM_DMB_SY);
break;
}
case OP_ATOMIC_STORE_I1:
case OP_ATOMIC_STORE_U4:
case OP_ATOMIC_STORE_R4:
case OP_ATOMIC_STORE_R8: {
- ARM_DMB (code, ARM_DMB_SY);
+ if (ins->backend.memory_barrier_kind != MONO_MEMORY_BARRIER_NONE)
+ ARM_DMB (code, ARM_DMB_SY);
code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
break;
case OP_GC_SAFE_POINT: {
- const char *polling_func = NULL;
guint8 *buf [1];
g_assert (mono_threads_is_coop_enabled ());
- polling_func = "mono_threads_state_poll";
ARM_LDR_IMM (code, ARMREG_IP, ins->sreg1, 0);
ARM_CMP_REG_IMM (code, ARMREG_IP, 0, 0);
buf [0] = code;
ARM_B_COND (code, ARMCOND_EQ, 0);
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, polling_func);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_threads_state_poll");
code = emit_call_seq (cfg, code);
arm_patch (buf [0], code);
break;
reg_offset += 4;
}
}
- if (iphone_abi) {
- mono_emit_unwind_op_offset (cfg, code, ARMREG_LR, -4);
- mini_gc_set_slot_type_from_cfa (cfg, -4, SLOT_NOREF);
- } else {
- mono_emit_unwind_op_offset (cfg, code, ARMREG_LR, -4);
- mini_gc_set_slot_type_from_cfa (cfg, -4, SLOT_NOREF);
- }
+ mono_emit_unwind_op_offset (cfg, code, ARMREG_LR, -4);
+ mini_gc_set_slot_type_from_cfa (cfg, -4, SLOT_NOREF);
} else {
ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
ARM_PUSH (code, 0x5ff0);
case RegTypeGeneral:
case RegTypeIRegPair:
case RegTypeGSharedVtInReg:
+ case RegTypeStructByAddr:
switch (ainfo->size) {
case 1:
if (arm_is_imm12 (inst->inst_offset))
break;
case RegTypeBase:
case RegTypeGSharedVtOnStack:
+ case RegTypeStructByAddrOnStack:
if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
} else {
}
break;
}
- case RegTypeStructByAddr:
- g_assert_not_reached ();
- /* FIXME: handle overrun! with struct sizes not multiple of 4 */
- code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
default:
g_assert_not_reached ();
break;
case RegTypeStructByVal: {
MonoInst *ins = cfg->ret;
- if (arm_is_imm12 (ins->inst_offset)) {
- ARM_LDR_IMM (code, ARMREG_R0, ins->inst_basereg, ins->inst_offset);
+ if (cinfo->ret.nregs == 1) {
+ if (arm_is_imm12 (ins->inst_offset)) {
+ ARM_LDR_IMM (code, ARMREG_R0, ins->inst_basereg, ins->inst_offset);
+ } else {
+ code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
+ ARM_LDR_REG_REG (code, ARMREG_R0, ins->inst_basereg, ARMREG_LR);
+ }
} else {
- code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
- ARM_LDR_REG_REG (code, ARMREG_R0, ins->inst_basereg, ARMREG_LR);
+ for (i = 0; i < cinfo->ret.nregs; ++i) {
+ int offset = ins->inst_offset + (i * 4);
+ if (arm_is_imm12 (offset)) {
+ ARM_LDR_IMM (code, i, ins->inst_basereg, offset);
+ } else {
+ code = mono_arm_emit_load_imm (code, ARMREG_LR, offset);
+ ARM_LDR_REG_REG (code, i, ins->inst_basereg, ARMREG_LR);
+ }
+ }
}
break;
}