typedef struct {
gint16 offset;
gint8 reg;
- ArgStorage storage;
+ ArgStorage storage : 8;
+ gboolean is_gsharedvt_return_value : 1;
/* Only if storage == ArgValuetypeInReg */
ArgStorage pair_storage [2];
/* The size of each pair */
int pair_size [2];
int nregs;
+ /* Only if storage == ArgOnStack */
+ int arg_size;
} ArgInfo;
typedef struct {
if (*gr >= PARAM_REGS) {
ainfo->storage = ArgOnStack;
+ ainfo->arg_size = sizeof (mgreg_t);
/* Since the same stack slot size is used for all arg */
/* types, it needs to be big enough to hold them all */
(*stack_size) += sizeof(mgreg_t);
if (*gr >= FLOAT_PARAM_REGS) {
ainfo->storage = ArgOnStack;
+ ainfo->arg_size = sizeof (mgreg_t);
/* Since the same stack slot size is used for both float */
/* types, it needs to be big enough to hold them both */
(*stack_size) += sizeof(mgreg_t);
ainfo->offset = *stack_size;
*stack_size += ALIGN_TO (size, 8);
ainfo->storage = is_return ? ArgValuetypeAddrInIReg : ArgOnStack;
+ if (!is_return)
+ ainfo->arg_size = ALIGN_TO (size, 8);
g_free (fields);
return;
else {
ainfo->pair_storage [0] = ArgOnStack;
ainfo->offset = *stack_size;
+ ainfo->arg_size = sizeof (mgreg_t);
*stack_size += 8;
}
}
ainfo->offset = *stack_size;
*stack_size += sizeof (mgreg_t);
ainfo->storage = is_return ? ArgValuetypeAddrInIReg : ArgOnStack;
+ if (!is_return)
+ ainfo->arg_size = sizeof (mgreg_t);
}
}
}
ainfo->offset = *stack_size;
*stack_size += ALIGN_TO (size, 8);
ainfo->storage = is_return ? ArgValuetypeAddrInIReg : ArgOnStack;
+ if (!is_return)
+ ainfo->arg_size = ALIGN_TO (size, 8);
g_free (fields);
return;
ainfo->offset = *stack_size;
*stack_size += ALIGN_TO (info->native_size, 8);
ainfo->storage = is_return ? ArgValuetypeAddrInIReg : ArgOnStack;
+ if (!is_return)
+ ainfo->arg_size = ALIGN_TO (info->native_size, 8);
g_free (fields);
return;
}
if ((args [0] == ARG_CLASS_MEMORY) || (args [1] == ARG_CLASS_MEMORY)) {
+ int arg_size;
/* Revert possible register assignments */
*gr = orig_gr;
*fr = orig_fr;
ainfo->offset = *stack_size;
if (sig->pinvoke)
- *stack_size += ALIGN_TO (info->native_size, 8);
+ arg_size = ALIGN_TO (info->native_size, 8);
else
- *stack_size += nquads * sizeof(mgreg_t);
+ arg_size = nquads * sizeof(mgreg_t);
+ *stack_size += arg_size;
ainfo->storage = is_return ? ArgValuetypeAddrInIReg : ArgOnStack;
+ if (!is_return)
+ ainfo->arg_size = arg_size;
}
}
#endif /* !TARGET_WIN32 */
}
if (mini_is_gsharedvt_type (ret_type)) {
cinfo->ret.storage = ArgValuetypeAddrInIReg;
+ cinfo->ret.is_gsharedvt_return_value = 1;
break;
}
/* fall through */
case MONO_TYPE_MVAR:
g_assert (mini_is_gsharedvt_type (ret_type));
cinfo->ret.storage = ArgValuetypeAddrInIReg;
+ cinfo->ret.is_gsharedvt_return_value = 1;
break;
case MONO_TYPE_VOID:
break;
add_general (&gr, &stack_size, ainfo);
break;
}
- if (mini_is_gsharedvt_type (ptype)) {
+ if (mini_is_gsharedvt_variable_type (ptype)) {
/* gsharedvt arguments are passed by ref */
add_general (&gr, &stack_size, ainfo);
if (ainfo->storage == ArgInIReg)
mono_aot_register_jit_icall ("mono_amd64_throw_corlib_exception", mono_amd64_throw_corlib_exception);
mono_aot_register_jit_icall ("mono_amd64_resume_unwind", mono_amd64_resume_unwind);
mono_aot_register_jit_icall ("mono_amd64_get_original_ip", mono_amd64_get_original_ip);
+#if defined(ENABLE_GSHAREDVT)
+ mono_aot_register_jit_icall ("mono_amd64_start_gsharedvt_call", mono_amd64_start_gsharedvt_call);
+#endif
if (!mono_aot_only)
bp_trampoline = mini_get_breakpoint_trampoline ();
case ArgInDoubleSSEReg:
cfg->ret->opcode = OP_REGVAR;
cfg->ret->inst_c0 = cinfo->ret.reg;
+ cfg->ret->dreg = cinfo->ret.reg;
break;
case ArgValuetypeAddrInIReg:
/* The register is volatile */
default:
g_assert_not_reached ();
}
- cfg->ret->dreg = cfg->ret->inst_c0;
}
/* Allocate locals */
NOT_IMPLEMENTED;
}
- if (!inreg && (ainfo->storage != ArgOnStack) && (ainfo->storage != ArgValuetypeAddrInIReg)) {
+ if (!inreg && (ainfo->storage != ArgOnStack) && (ainfo->storage != ArgValuetypeAddrInIReg) && (ainfo->storage != ArgGSharedVtOnStack)) {
ins->opcode = OP_REGOFFSET;
ins->inst_basereg = cfg->frame_reg;
/* These arguments are saved to the stack in the prolog */
case ArgInDoubleSSEReg:
linfo->ret.storage = LLVMArgNormal;
break;
- case ArgValuetypeInReg:
- if (sig->pinvoke) {
- cfg->exception_message = g_strdup ("pinvoke + vtypes");
+ case ArgValuetypeInReg: {
+ ainfo = &cinfo->ret;
+
+ if (sig->pinvoke &&
+ (ainfo->pair_storage [0] == ArgInFloatSSEReg || ainfo->pair_storage [0] == ArgInDoubleSSEReg ||
+ ainfo->pair_storage [1] == ArgInFloatSSEReg || ainfo->pair_storage [1] == ArgInDoubleSSEReg)) {
+ cfg->exception_message = g_strdup ("pinvoke + vtype ret");
cfg->disable_llvm = TRUE;
return linfo;
}
linfo->ret.storage = LLVMArgVtypeInReg;
for (j = 0; j < 2; ++j)
- linfo->ret.pair_storage [j] = arg_storage_to_llvm_arg_storage (cfg, cinfo->ret.pair_storage [j]);
+ linfo->ret.pair_storage [j] = arg_storage_to_llvm_arg_storage (cfg, ainfo->pair_storage [j]);
break;
+ }
case ArgValuetypeAddrInIReg:
/* Vtype returned using a hidden argument */
linfo->ret.storage = LLVMArgVtypeRetAddr;
linfo->args [i].storage = LLVMArgNormal;
break;
case ArgValuetypeInReg:
- if (sig->pinvoke) {
+ if (sig->pinvoke &&
+ (ainfo->pair_storage [0] == ArgInFloatSSEReg || ainfo->pair_storage [0] == ArgInDoubleSSEReg ||
+ ainfo->pair_storage [1] == ArgInFloatSSEReg || ainfo->pair_storage [1] == ArgInDoubleSSEReg)) {
cfg->exception_message = g_strdup ("pinvoke + vtypes");
cfg->disable_llvm = TRUE;
return linfo;
t = sig->params [i - sig->hasthis];
t = mini_get_underlying_type (t);
+ //XXX what about ArgGSharedVtOnStack here?
if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t) && !call->tail_call) {
if (!t->byref) {
if (t->type == MONO_TYPE_R4)
if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t) && !call->tail_call)
/* Already emitted above */
break;
+ //FIXME what about ArgGSharedVtOnStack ?
if (ainfo->storage == ArgOnStack && call->tail_call) {
MonoInst *call_inst = (MonoInst*)call;
cfg->args [i]->flags |= MONO_INST_VOLATILE;
mono_call_inst_add_outarg_reg (cfg, call, src->dreg, ainfo->reg, FALSE);
break;
case ArgGSharedVtOnStack:
- g_assert_not_reached ();
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, ainfo->offset, src->dreg);
break;
default:
if (size == 8) {
DynCallArgs *p = (DynCallArgs*)buf;
int arg_index, greg, i, pindex;
MonoMethodSignature *sig = dinfo->sig;
+ int buffer_offset = 0;
g_assert (buf_len >= sizeof (DynCallArgs));
if (MONO_TYPE_IS_REFERENCE (t)) {
p->regs [greg ++] = PTR_TO_GREG(*(arg));
break;
+ } else if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
+ MonoClass *klass = mono_class_from_mono_type (t);
+ guint8 *nullable_buf;
+ int size;
+
+ size = mono_class_value_size (klass, NULL);
+ nullable_buf = p->buffer + buffer_offset;
+ buffer_offset += size;
+ g_assert (buffer_offset <= 256);
+
+ /* The argument pointed to by arg is either a boxed vtype or null */
+ mono_nullable_init (nullable_buf, (MonoObject*)arg, klass);
+
+ arg = (gpointer*)nullable_buf;
+ /* Fall though */
+
} else {
/* Fall through */
}
if (ainfo->pair_storage [0] == ArgInIReg)
amd64_mov_membase_reg (code, ins->inst_left->inst_basereg, ins->inst_left->inst_offset, ainfo->pair_regs [0], sizeof (gpointer));
break;
+ case ArgGSharedVtInReg:
+ amd64_mov_membase_reg (code, ins->inst_basereg, ins->inst_offset, ainfo->reg, 8);
+ break;
default:
break;
}
}
}
-#if defined(ENABLE_GSHAREDVT)
+#if defined(ENABLE_GSHAREDVT) && defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
#include "../../../mono-extensions/mono/mini/mini-amd64-gsharedvt.c"
-#endif /* !MONOTOUCH */
+#endif /* !ENABLE_GSHAREDVT */