diff options
author | David Mitchell <davem@iabyn.com> | 2017-01-06 11:35:11 +0000 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2017-01-06 16:28:27 +0000 |
commit | b243b19395066bedc2a6dc3051cd0678692aa7d5 (patch) | |
tree | f4d7cda87ff8b3b0c34483a7b615983103012237 /pp_hot.c | |
parent | 9d692a7f83cf8fe36c59aaa07bca533887350e9b (diff) | |
download | perl-b243b19395066bedc2a6dc3051cd0678692aa7d5.tar.gz |
In A && B, stop special-casing boolean-ness of A
Some ops, (currently PADHV and RV2HV) can be flagged as being in boolean
context, and if so, may return a simple truth value which may be more
efficient to calculate than a full scalar value. (This was originally
motivated by code like if (%h) {...}, where the scalar context %h returned a
bucket ratio string, which involved counting how many HvARRAY buckets were
non-empty, which was slow in large hashes. It's been made less important
since %h in scalar context now just returns a key count, which is quick to
calculate.)
There is an issue with the A argument of A||B, A//B and A&&B, in that,
although A checked by the logop in boolean context, depending on its
truth value the original A may be passed through to the next op. So in
something like $x = (%h || -1), it's not sufficient for %h to return a
truth value; it must return a full scalar value which may get assigned to
$x.
So in general, we only mark the A op as being in boolean context if the
logop is in void context, or if the returned A would only be consumed in
boolean context; so !(A||B) would be ok for example.
However, && is a special case of this, since it will return the original A
only if A was false. Before this commit, && was special-cased to mark A as
being in boolean context regardless of the context of (A&&B). The downside
of this is that the A op can't just return &PL_sv_no as a false value;
it has to return something that is usable in scalar context too. For
example with %h, it returns sv_2mortal(newSViv(0))), which stringifies to
"0" while &PL_sv_no stringifies to "".
This commit removes that special case and makes && behave like || and //
again.
The upside is that some ops in boolean context will be able to more
cheaply return a false value (e.g. just &PL_sv_no verses
sv_2mortal(newSViv(0))).
The main downside is that && in unknown context (typically an
'if (%h} {...}' as the last statement in a sub) will have to check at
runtime whether the caller context is slower. It will also have to return
a scalar value for something like $y = (%h && $x), but that's a relatively
uncommon occurrence, and now that %h in scalar context doesn't have to
count used buckets, the extra cost in these rare cases is minor.
Diffstat (limited to 'pp_hot.c')
-rw-r--r-- | pp_hot.c | 4 |
1 files changed, 1 insertions, 3 deletions
@@ -1039,9 +1039,7 @@ PP(pp_rv2av) || ( PL_op->op_private & OPpMAYBE_TRUEBOOL && block_gimme() == G_VOID )) && (!SvRMAGICAL(sv) || !mg_find(sv, PERL_MAGIC_tied))) - /* use newSViv(0) rather than PL_sv_no - see OP_AND comment in - * S_check_for_bool_cxt() */ - SETs(HvUSEDKEYS(sv) ? &PL_sv_yes : sv_2mortal(newSViv(0))); + SETs(HvUSEDKEYS(sv) ? &PL_sv_yes : &PL_sv_no); else if (gimme == G_SCALAR) { dTARG; TARG = Perl_hv_scalar(aTHX_ MUTABLE_HV(sv)); |