Author: leo
Date: Tue Aug 2 04:22:59 2005
New Revision: 8765
Modified:
branches/leo-ctx5/classes/sub.pmc
branches/leo-ctx5/include/parrot/inter_call.h
branches/leo-ctx5/src/inter_call.c
branches/leo-ctx5/t/op/calling.t
Log:
Fix argument passing w/ tailcalls
* in a tailcall the register storage is reused
* therefore conflicts between args and params can exist
* disable taicalls for this case
* see also the comments for src/inter_call.c:parrot_check_tail_call()
Modified: branches/leo-ctx5/classes/sub.pmc
==============================================================================
--- branches/leo-ctx5/classes/sub.pmc (original)
+++ branches/leo-ctx5/classes/sub.pmc Tue Aug 2 04:22:59 2005
@@ -290,7 +290,12 @@ Invokes the subroutine.
}
assert (!PMC_IS_NULL(ccont));
- if (PObj_get_FLAGS(ccont) & SUB_FLAG_TAILCALL) {
+ /*
+ * if we do a taicall, we have to check that registers
+ * don't overlap
+ */
+ if ((PObj_get_FLAGS(ccont) & SUB_FLAG_TAILCALL)
+ && parrot_check_tail_call(INTERP, sub->seg, pc)) {
/* clear tail call flag - it has to be set again
* by the tailcall opcode
*/
Modified: branches/leo-ctx5/include/parrot/inter_call.h
==============================================================================
--- branches/leo-ctx5/include/parrot/inter_call.h (original)
+++ branches/leo-ctx5/include/parrot/inter_call.h Tue Aug 2 04:22:59 2005
@@ -69,6 +69,8 @@ int Parrot_fetch_arg_nci(Interp *, struc
int Parrot_convert_arg(Interp *, struct call_state *st);
int Parrot_store_arg(Interp *, struct call_state *st);
+int parrot_check_tail_call(Interp*, struct PackFile_ByteCode *, opcode_t *);
+
opcode_t * parrot_pass_args(Interp *, struct PackFile_ByteCode *seg,
struct parrot_regs_t *caller_regs, int what);
opcode_t * parrot_pass_args_fromc(Interp *, const char *sig, INTVAL src_n,
Modified: branches/leo-ctx5/src/inter_call.c
==============================================================================
--- branches/leo-ctx5/src/inter_call.c (original)
+++ branches/leo-ctx5/src/inter_call.c Tue Aug 2 04:22:59 2005
@@ -578,6 +578,68 @@ the latter handles return values and yie
#endif
+/*
+
+=item C<int parrot_check_tail_call(Interp*, struct PackFile_ByteCode *,
opcode_t *)>
+
+Check register usage of arguments and params for a conflict that would
+prevent proper argument passing. E.g.
+
+ args P30 P14 P15
+ params P14 P30 P15
+
+As in a tailcall we are working in the same register store, passing
+the first argument (P30 -> P14) would overwrite the next source (P14)
+and the second param would get a wrong value.
+
+TODO instead of disabling tailcalls in such a case, we could create an
+intermediate storage for conflicting registers and use this information
+in the subsequent argument passing.
+
+=cut
+
+*/
+
+int
+parrot_check_tail_call(Interp* interpreter,
+ struct PackFile_ByteCode *dst_seg, opcode_t *pc)
+{
+ struct call_state st;
+ int todo, i;
+
+ if (*pc != PARROT_OP_get_params_pc)
+ return 1;
+ todo = Parrot_init_arg_op(interpreter, dst_seg,
+ interpreter->ctx.bp, pc, &st.dest);
+ if (!todo)
+ return 1;
+ todo = Parrot_init_arg_op(interpreter, interpreter->code,
+ interpreter->ctx.bp,
+ interpreter->current_args, &st.src);
+ if (!todo)
+ return 1;
+ for (;;) {
+ if (!next_arg(interpreter, &st.src))
+ return 1;
+ if (!next_arg(interpreter, &st.dest))
+ return 1;
+ pc = st.src.u.op.pc;
+ i = st.src.i;
+ for (;;) {
+ if (!next_arg(interpreter, &st.src))
+ break;
+ if ( (st.src.sig & PARROT_ARG_TYPE_MASK) ==
+ (st.dest.sig & PARROT_ARG_TYPE_MASK) &&
+ *st.src.u.op.pc == *st.dest.u.op.pc) {
+ return 0;
+ }
+ }
+ st.src.u.op.pc = pc;
+ st.src.i = i;
+ }
+ return 1;
+}
+
opcode_t *
parrot_pass_args(Interp *interpreter, struct PackFile_ByteCode *dst_seg,
struct parrot_regs_t *caller_regs, int what)
Modified: branches/leo-ctx5/t/op/calling.t
==============================================================================
--- branches/leo-ctx5/t/op/calling.t (original)
+++ branches/leo-ctx5/t/op/calling.t Tue Aug 2 04:22:59 2005
@@ -16,7 +16,7 @@ Tests Parrot calling conventions.
=cut
-use Parrot::Test tests => 33;
+use Parrot::Test tests => 34;
use Test::More;
output_is(<<'CODE', <<'OUTPUT', "set_args - parsing");
@@ -916,3 +916,41 @@ ex:
CODE
ok 1
OUTPUT
+
+pir_output_is(<<'CODE', <<'OUTPUT', "tailcall 5 - arg/param conflict");
+.sub main @MAIN
+ .local pmc a, b
+ a = new Integer
+ a = 1
+ b = new Integer
+ b = 2
+ .local pmc c, d
+ (c, d) = foo(a, b)
+ eq_addr a, c, ok1
+ print "not "
+ok1:
+ print "ok 1\n"
+ eq_addr b, d, ok2
+ print "not "
+ok2:
+ print "ok 2\n"
+.end
+
+.sub foo
+ .param pmc a
+ .param pmc b
+ $P0 = new Integer
+ $P0 = 3
+ .return bar($P0, a, b)
+.end
+
+.sub bar
+ .param pmc x
+ .param pmc a
+ .param pmc b
+ .return (a, b)
+.end
+CODE
+ok 1
+ok 2
+OUTPUT