The patch is fine with two exceptions: 1) still breaks existing P6C tests WRT exceptions & rules 2) performance of CPS sucks
ad 1) I'd like to preserve the old style invoke/ret scheme too. incokecc and friends could call a new ContSub[1] class, which is the same as sub.pmc but doesn't put the return address on the control stack during invoke.
ad 2) CPS subroutines are 3 times slower for calling the sub. There are 2 problems here:
2a) The main is: the continuation object is generated for each[2] subroutine call. Replacing the invokecc with an explicit sequence of constructing the return Continuation object once outside the loop brings again the same speed as invoke/ret.
2b) There is still too much context copying going on AFAIK. The register top and base pointers are copied too in {save,restore}context worth of 8 words, while just copying the 3 stacks (pad, control, user) should more then be enough. The coroutine code only swaps these - BTW and doesn't set them COW.
So we have currently:
sub.pmc (+ contsub.pmc), continuation.pmc, and coroutine.pmc do very similar things. The only major difference is, where they branch on invoke. The differences are: - sub.pmc doesn't have an own context, it pushes the current lex_pad on the interpreters pad_stack on invoke - continuation.pmc saves/restores the whole context structure and marks the 3 stacks COW - coroutine.pmc swaps the 3 stacks and doesn't mark them COW
This leads to some questions: - shouldn't these all preserve the same stack(s)? - which stack(s): pad_stack only or control/user/intstack too? - can we pull out the construction of the return continuation of the loop like done below? - what parts of current context structure should then be preserved (registers are already out, why then deal with register backing store)?
Comments welcome leo
[1] we could AFAIK reuse CSub, which is obsoleted by NCI. (also most routines in method_utils.c seems to be obsolete)
[2] new P10, .PerlUndef set P10, 1000000 new P11, .PerlUndef set P11, 0 new P0, .Sub set_addr I12, func set P0, I12 set I0, 0 # no prototype set I2, 0 # no PMC params set I3, 0 # void context new P1, .Continuation ## set_addr I12, ret ## set P1, I12 ## lp: pushbottomp invoke ## invokecc ret: popbottomp inc P11 lt P11, P10, lp end
func: invoke P1