[perl #114576] Optimise if(%hash) in non-void context
authorFather Chrysostomos <sprout@cpan.org>
Sat, 25 Aug 2012 06:52:36 +0000 (23:52 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sat, 25 Aug 2012 06:53:02 +0000 (23:53 -0700)
The boolkeys optimisation (867fa1e2da1) was only applying to an and
(or if) in void context.  If an if occurs as the last thing in a sub-
routine, the void context is not know at compile time so the optimisa-
tion does not apply.

In the case of || (to which the boolkeys optimisation also applies),
we can’t optimise it in non-void context, because someone might be
writing $bucket_info = %hash || '0/0';

In the case of &&, we can optimise it, even in non-void context,
because a true value will always be discarded in %hash && foo.
The false value it returns for an empty hash is always the int-
eger 0.  That would change if we simply applied boolkeys to
my $ret = %hash && foo; because boolkeys return &PL_sv_no (the dualvar
you get from !1).  But since boolkeys’ return value is never directly
visible to perl code, we can safely change that.

op.c
pp.c

diff --git a/op.c b/op.c
index 1a0e5ab..7782c07 100644 (file)
--- a/op.c
+++ b/op.c
@@ -10226,7 +10226,7 @@ S_opt_scalarhv(pTHX_ OP *rep_op) {
     rep_op->op_flags|=(OPf_REF | OPf_MOD);
     unop->op_sibling = rep_op->op_sibling;
     rep_op->op_sibling = NULL;
-    /* unop->op_targ = pad_alloc(OP_BOOLKEYS, SVs_PADTMP); */
+    unop->op_targ = pad_alloc(OP_BOOLKEYS, SVs_PADTMP);
     if (rep_op->op_type == OP_PADHV) { 
         rep_op->op_flags &= ~OPf_WANT_SCALAR;
         rep_op->op_flags |= OPf_WANT_LIST;
@@ -10570,12 +10570,14 @@ Perl_rpeep(pTHX_ register OP *o)
                         }
                     }            
                 }
-                if ((lop->op_flags & OPf_WANT) == OPf_WANT_VOID) {
-                    if (fop->op_type == OP_PADHV || fop->op_type == OP_RV2HV) 
+                if (  (  (lop->op_flags & OPf_WANT) == OPf_WANT_VOID
+                      || o->op_type == OP_AND  )
+                   && (  fop->op_type == OP_PADHV
+                      || fop->op_type == OP_RV2HV))
                         cLOGOP->op_first = opt_scalarhv(fop);
-                    if (sop && (sop->op_type == OP_PADHV || sop->op_type == OP_RV2HV)) 
+                if (  (lop->op_flags & OPf_WANT) == OPf_WANT_VOID
+                   && sop && (sop->op_type == OP_PADHV || sop->op_type == OP_RV2HV))
                         cLOGOP->op_first->op_sibling = opt_scalarhv(sop);
-                }                                        
             }                  
             
            
diff --git a/pp.c b/pp.c
index 7565a9d..eba4e22 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -5722,6 +5722,7 @@ PP(pp_boolkeys)
 {
     dVAR;
     dSP;
+    dTARGET;
     HV * const hv = (HV*)TOPs;
     
     if (SvTYPE(hv) != SVt_PVHV) RETSETNO;
@@ -5734,7 +5735,8 @@ PP(pp_boolkeys)
         }          
     }
 
-    SETs(boolSV(HvUSEDKEYS(hv) != 0));
+    if (HvUSEDKEYS(hv) != 0) RETSETYES;
+    else SETi(0); /* for $ret = %hash && foo() */
     RETURN;
 }