Author: leo
Date: Tue Mar 14 04:19:16 2006
New Revision: 11896

Modified:
   trunk/src/inter_call.c
   trunk/src/pmc/compiler.pmc
   trunk/src/pmc/nci.pmc
   trunk/t/op/calling.t

Log:
Fix tailcalls to NCI, #38724

* unit Compiler.invoke and NCI.invoke
* free call frame in NCI.invoke, if tailcalled
* get rid of more dead code regarding tailcalla and arg passing


Modified: trunk/src/inter_call.c
==============================================================================
--- trunk/src/inter_call.c      (original)
+++ trunk/src/inter_call.c      Tue Mar 14 04:19:16 2006
@@ -1116,22 +1116,6 @@
         if (!PARROT_ERRORS_test(interpreter, PARROT_ERRORS_PARAM_COUNT_FLAG))
             err_check = 0;
     }
-    if (src_pc && (src_pc[-3] == PARROT_OP_tailcallmethod_p_sc ||
-            src_pc[-3] == PARROT_OP_tailcallmethod_p_s)) {
-        /*
-         * If we have this sequence:
-         *
-         * tailcallmethod_p_s?
-         * set_returns_pc '()'
-         * return_cc
-         *
-         * we are returning 1 retval to caller on behalf
-         * of the NCI (a PIR method had already returned
-         * all and doesn't run anything after the
-         * tailcall - ignore arg_count
-         */
-        err_check = 0;
-    }
     process_args(interpreter, &st, action, err_check);
 
     /* skip the get_params opcode - all done here */

Modified: trunk/src/pmc/compiler.pmc
==============================================================================
--- trunk/src/pmc/compiler.pmc  (original)
+++ trunk/src/pmc/compiler.pmc  Tue Mar 14 04:19:16 2006
@@ -36,12 +36,7 @@
 */
 
     void* invoke (void * code_ptr) {
-        typedef INTVAL (*nci_sub_t)(Interp * , PMC * );
-        nci_sub_t func = (nci_sub_t)D2FPTR(PMC_data(SELF));
-        
-        INTERP->current_cont = NULL;
-        func(INTERP, SELF);
-        return code_ptr;
+        return SUPER(code_ptr);
     }
 }
 

Modified: trunk/src/pmc/nci.pmc
==============================================================================
--- trunk/src/pmc/nci.pmc       (original)
+++ trunk/src/pmc/nci.pmc       Tue Mar 14 04:19:16 2006
@@ -124,23 +124,25 @@
     void* invoke (void * next) {
         typedef INTVAL (*nci_sub_t)(Interp * , PMC * );
         nci_sub_t func = (nci_sub_t)D2FPTR(PMC_data(SELF));
+        PMC *cont;
 
-        INTERP->current_cont = NULL;
         if (!func)
             real_exception(INTERP, NULL, INVALID_OPERATION,
                 "attempt to call NULL function");
+        func(INTERP, SELF);
+        cont = INTERP->current_cont;
         /*
-         * If the invocant is a class or there is no invocant
-         * shift down arguments.
-         * But not if it's a plain NCI function created
-         * from dlfunc.
-         *
-         * NCI flags:
-         *   private0 ... builtin multi method
-         *   private1 ... created via dlfunc
-         *
+         * If the NCI function was tailcalled, the return result
+         * is already passed back to the caller of this frame
+         * - see  Parrot_init_ret_nci(). We therefore invoke the
+         * return continuation here, which gets rid of this frame
+         * and returns the real return address
          */
-        func(INTERP, SELF);
+        if (cont && cont != NEED_CONTINUATION && 
+                (PObj_get_FLAGS(cont) & SUB_FLAG_TAILCALL)) {
+            cont = CONTEXT(interpreter->ctx)->current_cont;
+            next = VTABLE_invoke(INTERP, cont, next);
+        }
         return next;
     }
 

Modified: trunk/t/op/calling.t
==============================================================================
--- trunk/t/op/calling.t        (original)
+++ trunk/t/op/calling.t        Tue Mar 14 04:19:16 2006
@@ -1315,6 +1315,23 @@
 ok 2
 OUTPUT
 
+pir_output_is(<<'CODE', <<'OUTPUT', "tailcall to NCI - 2");
+.sub main :main
+    $P0 = eval("print \"Foo!\\n\"")
+    $P0()
+    end
+.end
+
+.sub eval
+    .param string code
+    code = ".sub main :main :anon\n" . code
+    code = code . "\n.end\n"
+    $P0 = compreg "PIR"
+    .return $P0(code)
+.end
+CODE
+Foo!
+OUTPUT
 
 # bug - repeated calls to eval'd sub crashes (pmichaud, 2005.10.27)
 pir_output_is(<<'CODE', <<'OUTPUT', "repeated calls to eval'd sub");
@@ -2282,5 +2299,5 @@
 OUTPUT
 
 ## remember to change the number of tests :-)
-BEGIN { plan tests => 88 }
+BEGIN { plan tests => 89 }
 

Reply via email to