diff options
author | David Mitchell <davem@iabyn.com> | 2012-09-24 13:50:22 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2012-11-10 13:39:31 +0000 |
commit | a7fd8ef68b459a13ba95615ec125e2e7ba656b47 (patch) | |
tree | 874247cb2e03f98ee1de71d4a7eb29d3e84a7611 /pp_hot.c | |
parent | ad9e6ae10fb581c6c053b862286f8e187063c3ab (diff) | |
download | perl-a7fd8ef68b459a13ba95615ec125e2e7ba656b47.tar.gz |
add padrange op
This single op can, in some circumstances, replace the sequence of a
pushmark followed by one or more padsv/padav/padhv ops, and possibly
a trailing 'list' op, but only where the targs of the pad ops form
a continuous range.
This is generally more efficient, but is particularly so in the case
of void-context my declarations, such as:
my ($a,@b);
Formerly this would be executed as the following set of ops:
pushmark pushes a new mark
padsv[$a] pushes $a, does a SAVEt_CLEARSV
padav[@b] pushes all the flattened elements (i.e. none) of @a,
does a SAVEt_CLEARSV
list pops the mark, and pops all stack elements except the last
nextstate pops the remaining stack element
It's now:
padrange[$a..@b] does two SAVEt_CLEARSV's
nextstate nothing needing doing to the stack
Note that in the case above, this commit changes user-visible behaviour in
pathological cases; in particular, it has always been possible to modify a
lexical var *before* the my is executed, using goto or closure tricks.
So in principle someone could tie an array, then could notice that FETCH
is no longer being called, e.g.
f();
my ($s, @a); # this no longer triggers two FETCHES
sub f {
tie @a, ...;
push @a, 1,2;
}
But I think we can live with that.
Note also that having a padrange operator will allow us shortly to have
a corresponding SAVEt_CLEARPADRANGE save type, that will replace multiple
individual SAVEt_CLEARSV's.
Diffstat (limited to 'pp_hot.c')
-rw-r--r-- | pp_hot.c | 23 |
1 files changed, 23 insertions, 0 deletions
@@ -306,6 +306,29 @@ PP(pp_concat) } } +/* ($lex1,@lex2,...) or my ($lex1,@lex2,...) */ + +PP(pp_padrange) +{ + dVAR; dSP; + PADOFFSET base = PL_op->op_targ; + int count = (int)(PL_op->op_private) & OPpPADRANGE_COUNTMASK; + int i; + /* note, this is only skipped for compile-time-known void cxt */ + if ((PL_op->op_flags & OPf_WANT) != OPf_WANT_VOID) { + EXTEND(SP, count); + PUSHMARK(SP); + for (i = 0; i <count; i++) + *++SP = PAD_SV(base+i); + } + if (PL_op->op_private & OPpLVAL_INTRO) { + for (i = 0; i <count; i++) + SAVECLEARSV(PAD_SVl(base+i)); + } + RETURN; +} + + PP(pp_padsv) { dVAR; dSP; dTARGET; |