diff options
author | David Mitchell <davem@iabyn.com> | 2017-07-23 16:31:38 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2017-07-27 11:30:25 +0100 |
commit | 6f2dc9a6b978e866e22c46235932d018da8262ba (patch) | |
tree | aaea4ac92d8aa676e597ecbf13aff28c3a58f65d /pp_hot.c | |
parent | 8dc9003ff3914e78971f561eaece965e9ceeb49e (diff) | |
download | perl-6f2dc9a6b978e866e22c46235932d018da8262ba.tar.gz |
make scalar(keys(%lexical)) less slow.
A recent commit in this branch made OP_PADHV / OP_RV2HV in void/scalar
context, followed by OP_KEYS, optimise away the OP_KEYS op and set the
OPpPADHV_ISKEYS or OPpRV2HV_ISKEYS flag on the OP_PADHV / OP_RV2HV op.
However, in scalar but non-boolean context with OP_PADHV, this actually
makes it slower, because the OP_KEYS op has a target, while the OP_PADHV
op doesn't, thus it has to create a new mortal each time to return the
integer value.
This commit fixes that by, in the case of scalar padhv, retaining the
OP_KEYS node (although still not keeping it in the execution path), then
at runtime using that op's otherwise unused target.
This only works on PERL_OP_PARENT builds (now the default) as the OP_KEYS
is the parent of the OP_PADHV, so would be hard to find at runtime
otherwise.
This commit also fixes pp_padhv/pp_rv2hv in void context - formerly it
was needlessly pushing a scalar-valued count like scalar context.
Diffstat (limited to 'pp_hot.c')
-rw-r--r-- | pp_hot.c | 18 |
1 files changed, 18 insertions, 0 deletions
@@ -991,6 +991,9 @@ S_padhv_rv2hv_common(pTHX_ HV *hv, U8 gimme, bool is_keys, bool has_targ) /* 'keys %h' masquerading as '%h': reset iterator */ (void)hv_iterinit(hv); + if (gimme == G_VOID) + return NORMAL; + is_bool = ( PL_op->op_private & OPpTRUEBOOL || ( PL_op->op_private & OPpMAYBE_TRUEBOOL && block_gimme() == G_VOID)); @@ -1022,6 +1025,21 @@ S_padhv_rv2hv_common(pTHX_ HV *hv, U8 gimme, bool is_keys, bool has_targ) PUSHi(i); } else +#ifdef PERL_OP_PARENT + if (is_keys) { + /* parent op should be an unused OP_KEYS whose targ we can + * use */ + dTARG; + OP *k; + + assert(!OpHAS_SIBLING(PL_op)); + k = PL_op->op_sibparent; + assert(k->op_type == OP_KEYS); + TARG = PAD_SV(k->op_targ); + PUSHi(i); + } + else +#endif mPUSHi(i); } } |