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 }