diff options
author | David Mitchell <davem@iabyn.com> | 2017-07-10 15:48:02 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2017-07-27 11:30:22 +0100 |
commit | 748f2c65599942147442f443949449a965f6d608 (patch) | |
tree | e0ccd923e221f95c7ddb80fc5c6c4c42c85c5a8f /pp_hot.c | |
parent | 4fa080dbc664ee90dd374a9a49ac0a4932421bd7 (diff) | |
download | perl-748f2c65599942147442f443949449a965f6d608.tar.gz |
optimise away OP_KEYS op in scalar/void context
In something like
if (keys %h) { ... }
the 'keys %h' is implemented as the op sequences
gv[*h] s
rv2hv lKRM/1
keys[t2] sK/1
or
padhv[%h:1,6] lRM
keys[t2] sK/1
It turns out that (%h) in scalar and void context now behaves very
similarly to (keys %h) (except that it reset the iterator), so in these
cases, convert the two ops
rv2hv/padhv, keys
into the single op
rv2hv/padhv
with a private flag indicating that the op is handling the 'keys' action
by itself.
As well as one less op to execute, this brings the boolean-context
optimisation already present in padhv/rv2sv to keys. So
if (keys %h) { ... }
is no longer slower than
if (%h) { ... }
Diffstat (limited to 'pp_hot.c')
-rw-r--r-- | pp_hot.c | 33 |
1 files changed, 28 insertions, 5 deletions
@@ -1035,20 +1035,43 @@ PP(pp_rv2av) SETi(maxarg); } } else { + bool tied; /* The guts of pp_rv2hv */ if (gimme == G_ARRAY) { /* array wanted */ *PL_stack_sp = sv; return Perl_do_kv(aTHX); } - else if ((PL_op->op_private & OPpTRUEBOOL + + if (PL_op->op_private & OPpRV2HV_ISKEYS) + /* 'keys %h' masquerading as '%h': reset iterator */ + (void)hv_iterinit(MUTABLE_HV(sv)); + + tied = SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied); + + if ( ( PL_op->op_private & OPpTRUEBOOL || ( PL_op->op_private & OPpMAYBE_TRUEBOOL - && block_gimme() == G_VOID )) - && (!SvRMAGICAL(sv) || !mg_find(sv, PERL_MAGIC_tied))) + && block_gimme() == G_VOID) + ) + && !tied) SETs(HvUSEDKEYS(MUTABLE_HV(sv)) ? &PL_sv_yes : &PL_sv_zero); else if (gimme == G_SCALAR) { dTARG; - TARG = Perl_hv_scalar(aTHX_ MUTABLE_HV(sv)); - SETTARG; + if (PL_op->op_private & OPpRV2HV_ISKEYS) { + IV i; + if (tied) { + i = 0; + while (hv_iternext(MUTABLE_HV(sv))) + i++; + } + else + i = HvUSEDKEYS(MUTABLE_HV(sv)); + (void)POPs; + mPUSHi(i); + } + else { + TARG = Perl_hv_scalar(aTHX_ MUTABLE_HV(sv)); + SETTARG; + } } } RETURN; |