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

Reply via email to