The final part of the "signatures" feature still to be implemented, is getting rid of the @_ setup as part of OP_ENTERSUB when entering a signature'd sub, for the speed benefit it gives. I've been thinking about how to implement this. It seems to me we need four pieces. The first two of these should be quite simple: 1. Add a flag (maybe CvSIGNATURE(cv)) on CVs that is present when the sub has a signature. The parser can easily turn this one on at the time it creates the CV. 2. Get pp_entersub to check that flag, and skip setting up the callee's @_ array if set. -- this is the core of the speedup. 3. {handwavy something} to ensure that OP_ARGCHECK and OP_ARGELEM can look somewhere else to find the arguments, now they can no longer use GvAV(PL_defgv). 4. {handwavy something else} to make accesses of @_ throw an error at runtime. Part 2 is the main reason *why* to do this. Part 1 is the logic to make it apply at the right time. Those are the easy bits. Far less clear is how to do parts 3 and 4. In particular, for part 3 I have the following thoughts on possible ways to implement it: 3a. Don't set up @_ but instead move the stack values over to some other temporary place for the OP_ARG* ops to read from. Since that has to be local'ised in case of recursion into another signatured sub during argument unpack in practice this is going to perform about the same amount of work as the current GvAV(PL_defgv) implementation anyway, and thus be about the same speed. We gain nothing. 3b. Don't have pp_entersub reset the stack pointers before jumping into the optree. A CV with CvSIGNATURE() set would be promising that it will inspect the TOPMARK and use that to pull its arguments off the stack into whatever setup it wants, via those OP_ARG* operations. Thus where OP_ARGCHECK currently does argc = (UV)(AvFILLp(defav) + 1); It could instead compare TOPMARK with SP, in something like ((I may have an off-by-one here but you get the idea)) argc = SP - TOPMARK + 1; This does seem notably more fragile than the current setup, because now we can't have any OP_NEXTSTATEs in the middle of signature unpacking, or else they'll reset the stack pointers. The whole setup relies on the state of the stack being rather fragile during the first phase of the callee's optree - at least until the OP_ARG* ops are finished. 3c. A variant of 3b, which involves adding a new interpreter pointer like SP, which points at the start of the stack arguments. Lets steal x86's naming and call it the "frame pointer". When entering a CV with CvSIGNATURE(), pp_entersub would set FP = TOPMARK and jump into the optree. Thereafter, the OP_ARG* ops can use the frame pointer to work: In OP_ARGCHECK: argc = SP - FP + 1; In OP_ARGELEM: SV *arg = FP[argi]; This would be somewhat less fragile than 3b because it doesn't rely on the TOPMARK being preserved. It lets us set aside a storage area for passed arguments that should be much more robust than in 3b, without needing to copy them aside as we do now, or with 3a. It is still one more pointer value that has to be saved/restored around every function invocation (and likely stored on the context stack), but it's nowhere near as much work to do that as the current work around @_. And finally I don't really have much thought on how to go about part 4, other than the vague thinking that adding a new AV flag just to put one on @_ in a signature'd sub, and then have every AV access check it, is probably going to be a bit slow as it makes every AV access slow. I'd welcome any thoughts anyone else has around this subject... -- Paul "LeoNerd" Evans leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/Thread Next