.field public int32 a
.field public int32 b
.field public int32 c
+ .field public int32 d
+ .field public int32 e
}
- .method static valuetype Tests/TailCallStructBig tail1_big (valuetype Tests/TailCallStructBig arg) {
+ .method static valuetype Tests/TailCallStructBig tail_vret_by_addr_inner (valuetype Tests/TailCallStructBig arg) {
ldarga 0
ldarga 0
ldfld int32 Tests/TailCallStructBig::a
ret
}
- .method static valuetype Tests/TailCallStructBig tail2_big (valuetype Tests/TailCallStructBig arg) {
+ .method static valuetype Tests/TailCallStructBig tail_vret_by_addr (valuetype Tests/TailCallStructBig arg) {
ldarg.0
tail.
- call valuetype Tests/TailCallStructBig Tests::tail1_big (valuetype Tests/TailCallStructBig)
+ call valuetype Tests/TailCallStructBig Tests::tail_vret_by_addr_inner (valuetype Tests/TailCallStructBig)
ret
}
- .method static public int32 test_0_tail_calls () il managed {
+ .method static public int32 test_3_tail_call_vret_by_addr () il managed {
.maxstack 16
.locals init (
- valuetype Tests/TailCallStruct arg,
valuetype Tests/TailCallStructBig arg2
)
+
+ ldloca 0
+ ldc.i4.2
+ stfld int32 Tests/TailCallStructBig::a
+ ldloc.0
+ call valuetype Tests/TailCallStructBig Tests::tail_vret_by_addr (valuetype Tests/TailCallStructBig)
+ stloc.0
+
+ ldloca 0
+ ldfld int32 Tests/TailCallStructBig::a
+ ret
+ }
+
+ .method static public int32 test_9_tail_call_vret_by_val () il managed {
+ .maxstack 16
+ .locals init (
+ valuetype Tests/TailCallStruct arg
+ )
ldloca 0
ldc.i4.2
stfld int32 Tests/TailCallStruct::a
call valuetype Tests/TailCallStruct Tests::tail2 (valuetype Tests/TailCallStruct)
stloc.0
- ldloca 1
- ldc.i4.2
- stfld int32 Tests/TailCallStructBig::a
- ldloc.1
- call valuetype Tests/TailCallStructBig Tests::tail2_big (valuetype Tests/TailCallStructBig)
- stloc.1
-
ldloca 0
ldfld int32 Tests/TailCallStruct::a
ldloca 0
ldfld int32 Tests/TailCallStruct::b
add
- ldloca 1
- ldfld int32 Tests/TailCallStructBig::a
- add
- ldc.i4 12
- sub
ret
}
inline static MonoCallInst *
mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
- MonoInst **args, int calli, int virtual)
+ MonoInst **args, int calli, int virtual, int tail)
{
MonoCallInst *call;
#ifdef MONO_ARCH_SOFT_FLOAT
int i;
#endif
- MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
+ if (tail)
+ MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
+ else
+ MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
call->args = args;
call->signature = sig;
type_to_eval_stack_type ((cfg), sig->ret, &call->inst);
- if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ if (tail) {
+ if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ call->vret_var = cfg->vret_addr;
+ //g_assert_not_reached ();
+ }
+ } else if (MONO_TYPE_ISSTRUCT (sig->ret)) {
MonoInst *temp = mono_compile_create_var (cfg, sig->ret, OP_LOCAL);
MonoInst *loada;
inline static MonoInst*
mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr)
{
- MonoCallInst *call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE);
+ MonoCallInst *call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE);
call->inst.sreg1 = addr->dreg;
sig = ctor_sig;
}
- call = mono_emit_call_args (cfg, sig, args, FALSE, virtual);
+ call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, FALSE);
if (this && sig->hasthis &&
(method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
g_assert (sig);
- call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE);
+ call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE);
call->fptr = func;
MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
CHECK_CFG_EXCEPTION;
-#ifdef TARGET_AMD64
+#ifdef MONO_ARCH_USE_OP_TAIL_CALL
{
MonoMethodSignature *fsig = mono_method_signature (cmethod);
int i, n;
gboolean pass_mrgctx = FALSE;
MonoInst *vtable_arg = NULL;
gboolean check_this = FALSE;
+ gboolean supported_tail_call = FALSE;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
break;
}
+#ifdef MONO_ARCH_USE_OP_TAIL_CALL
+ supported_tail_call = cmethod && MONO_ARCH_USE_OP_TAIL_CALL (mono_method_signature (method), mono_method_signature (cmethod));
+#else
+ supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod))) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
+#endif
+
/* Tail prefix */
/* FIXME: runtime generic context pointer for jumps? */
/* FIXME: handle this for generic sharing eventually */
- if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) &&
- (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod))) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret)) {
+ if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) && supported_tail_call) {
MonoCallInst *call;
/* Prevent inlining of methods with tail calls (the call stack would be altered) */
INLINE_FAILURE;
+#ifdef MONO_ARCH_USE_OP_TAIL_CALL
+ /* Handle tail calls similarly to calls */
+ call = mono_emit_call_args (cfg, mono_method_signature (cmethod), sp, FALSE, FALSE, TRUE);
+#else
MONO_INST_NEW_CALL (cfg, call, OP_JMP);
call->tail_call = TRUE;
call->method = cmethod;
call->signature = mono_method_signature (cmethod);
-#ifdef TARGET_AMD64
- /* Handle tail calls similarly to calls */
- call->inst.opcode = OP_TAILCALL;
- call->args = sp;
- mono_arch_emit_call (cfg, call);
-#else
/*
* We implement tail calls by storing the actual arguments into the
* argument variables, then emitting a CEE_JMP.