This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Revert "op.c: Don’t keep looping when we see potential common vars"
[perl5.git] / op.c
diff --git a/op.c b/op.c
index 45935a1..7b8c176 100644 (file)
--- a/op.c
+++ b/op.c
@@ -1695,6 +1695,8 @@ Perl_scalarvoid(pTHX_ OP *o)
     case OP_SPLIT:
        kid = cLISTOPo->op_first;
        if (kid && kid->op_type == OP_PUSHRE
+               && !kid->op_targ
+               && !(o->op_flags & OPf_STACKED)
 #ifdef USE_ITHREADS
                && !((PMOP*)kid)->op_pmreplrootu.op_pmtargetoff)
 #else
@@ -3870,6 +3872,7 @@ S_fold_constants(pTHX_ OP *o)
     OP * VOL curop;
     OP *newop;
     VOL I32 type = o->op_type;
+    bool folded;
     SV * VOL sv = NULL;
     int ret = 0;
     I32 oldscope;
@@ -4016,6 +4019,7 @@ S_fold_constants(pTHX_ OP *o)
     if (ret)
        goto nope;
 
+    folded = o->op_folded;
     op_free(o);
     assert(sv);
     if (type == OP_STRINGIFY) SvPADTMP_off(sv);
@@ -4028,7 +4032,11 @@ S_fold_constants(pTHX_ OP *o)
     else
     {
        newop = newSVOP(OP_CONST, 0, MUTABLE_SV(sv));
-       if (type != OP_STRINGIFY) newop->op_folded = 1;
+       /* OP_STRINGIFY and constant folding are used to implement qq.
+          Here the constant folding is an implementation detail that we
+          want to hide.  If the stringify op is itself already marked
+          folded, however, then it is actually a folded join.  */
+       if (type != OP_STRINGIFY || folded) newop->op_folded = 1;
     }
     return newop;
 
@@ -5921,6 +5929,7 @@ S_aassign_common_vars(pTHX_ OP* o)
                curop->op_type == OP_PADHV ||
                curop->op_type == OP_PADANY)
                {
+                 padcheck:
                    if (PAD_COMPNAME_GEN(curop->op_targ)
                        == (STRLEN)PL_generation
                     || PAD_COMPNAME_GEN(curop->op_targ) == PERL_INT_MAX)
@@ -5952,6 +5961,8 @@ S_aassign_common_vars(pTHX_ OP* o)
                        return TRUE;
                    GvASSIGN_GENERATION_set(gv, PL_generation);
                }
+               else if (curop->op_targ)
+                   goto padcheck;
            }
            else if (curop->op_type == OP_PADRANGE)
                /* Ignore padrange; checking its siblings is sufficient. */
@@ -5983,6 +5994,10 @@ S_aassign_common_vars_aliases_only(pTHX_ OP *o)
           && PAD_COMPNAME_GEN(curop->op_targ) == PERL_INT_MAX)
            return TRUE;
 
+       if (curop->op_type == OP_PUSHRE && curop->op_targ
+        && PAD_COMPNAME_GEN(curop->op_targ) == PERL_INT_MAX)
+           return TRUE;
+
        if (curop->op_flags & OPf_KIDS) {
            if (S_aassign_common_vars_aliases_only(aTHX_ curop))
                return TRUE;
@@ -6057,10 +6072,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                    lop->op_type == OP_PADHV ||
                    lop->op_type == OP_PADANY) {
                    if (!(lop->op_private & OPpLVAL_INTRO))
-                   {
                        maybe_common_vars = TRUE;
-                       break;
-                   }
 
                    if (lop->op_private & OPpPAD_STATE) {
                        if (left->op_private & OPpLVAL_INTRO) {
@@ -6082,7 +6094,6 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                } else {
                    /* Other ops in the list. */
                    maybe_common_vars = TRUE;
-                   break;
                }
                lop = OP_SIBLING(lop);
            }
@@ -6115,46 +6126,72 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                o->op_private |= OPpASSIGN_COMMON;
        }
 
-       if (right && right->op_type == OP_SPLIT) {
+       if (right && right->op_type == OP_SPLIT
+        && !(right->op_flags & OPf_STACKED)) {
            OP* tmpop = ((LISTOP*)right)->op_first;
            if (tmpop && (tmpop->op_type == OP_PUSHRE)) {
                PMOP * const pm = (PMOP*)tmpop;
-               if (left->op_type == OP_RV2AV &&
-                   !(left->op_private & OPpLVAL_INTRO))
-               {
-                   tmpop = ((UNOP*)left)->op_first;
-                   if (tmpop->op_type == OP_GV
+               if (
 #ifdef USE_ITHREADS
-                       && !pm->op_pmreplrootu.op_pmtargetoff
+                   !pm->op_pmreplrootu.op_pmtargetoff
 #else
-                       && !pm->op_pmreplrootu.op_pmtargetgv
+                   !pm->op_pmreplrootu.op_pmtargetgv
 #endif
+                && !pm->op_targ
+               ) {
+                   if (!(left->op_private & OPpLVAL_INTRO) &&
+                       ( (left->op_type == OP_RV2AV &&
+                         (tmpop=((UNOP*)left)->op_first)->op_type==OP_GV)
+                       || left->op_type == OP_PADAV )
                        ) {
+                       if (tmpop != (OP *)pm) {
 #ifdef USE_ITHREADS
-                       pm->op_pmreplrootu.op_pmtargetoff
+                         pm->op_pmreplrootu.op_pmtargetoff
                            = cPADOPx(tmpop)->op_padix;
-                       cPADOPx(tmpop)->op_padix = 0;   /* steal it */
+                         cPADOPx(tmpop)->op_padix = 0; /* steal it */
 #else
-                       pm->op_pmreplrootu.op_pmtargetgv
+                         pm->op_pmreplrootu.op_pmtargetgv
                            = MUTABLE_GV(cSVOPx(tmpop)->op_sv);
-                       cSVOPx(tmpop)->op_sv = NULL;    /* steal it */
+                         cSVOPx(tmpop)->op_sv = NULL;  /* steal it */
 #endif
+                         right->op_private |=
+                           left->op_private & OPpOUR_INTRO;
+                       }
+                       else {
+                           pm->op_targ = left->op_targ;
+                           left->op_targ = 0; /* filch it */
+                       }
+                     detach_split:
                        tmpop = cUNOPo->op_first;       /* to list (nulled) */
                        tmpop = ((UNOP*)tmpop)->op_first; /* to pushmark */
                         /* detach rest of siblings from o subtree,
                          * and free subtree */
                         op_sibling_splice(cUNOPo->op_first, tmpop, -1, NULL);
-                       right->op_private |=
-                           left->op_private & OPpOUR_INTRO;
                        op_free(o);                     /* blow off assign */
                        right->op_flags &= ~OPf_WANT;
                                /* "I don't know and I don't care." */
                        return right;
                    }
-               }
-               else {
-                   if (PL_modcount < RETURN_UNLIMITED_NUMBER &&
-                     ((LISTOP*)right)->op_last->op_type == OP_CONST)
+                   else if (left->op_type == OP_RV2AV
+                         || left->op_type == OP_PADAV)
+                   {
+                       /* Detach the array.  */
+#ifdef DEBUGGING
+                       OP * const ary =
+#endif
+                       op_sibling_splice(cBINOPo->op_last,
+                                         cUNOPx(cBINOPo->op_last)
+                                               ->op_first, 1, NULL);
+                       assert(ary == left);
+                       /* Attach it to the split.  */
+                       op_sibling_splice(right, cLISTOPx(right)->op_last,
+                                         0, left);
+                       right->op_flags |= OPf_STACKED;
+                       /* Detach split and expunge aassign as above.  */
+                       goto detach_split;
+                   }
+                   else if (PL_modcount < RETURN_UNLIMITED_NUMBER &&
+                           ((LISTOP*)right)->op_last->op_type == OP_CONST)
                    {
                        SV ** const svp =
                            &((SVOP*)((LISTOP*)right)->op_last)->op_sv;
@@ -6973,6 +7010,7 @@ Perl_newFOROP(pTHX_ I32 flags, OP *sv, OP *expr, OP *block, OP *cont)
             sv->op_targ = 0;
             op_free(sv);
            sv = NULL;
+           PAD_COMPNAME_GEN_set(padoff, PERL_INT_MAX);
        }
        else if (sv->op_type == OP_NULL && sv->op_targ == OP_SREFGEN)
            NOOP;
@@ -10568,9 +10606,23 @@ Perl_ck_split(pTHX_ OP *o)
 }
 
 OP *
+Perl_ck_stringify(pTHX_ OP *o)
+{
+    OP * const kid = OP_SIBLING(cUNOPo->op_first);
+    PERL_ARGS_ASSERT_CK_STRINGIFY;
+    if (kid->op_type == OP_JOIN) {
+       assert(!OP_HAS_SIBLING(kid));
+       op_sibling_splice(o, cUNOPo->op_first, -1, NULL);
+       op_free(o);
+       return kid;
+    }
+    return ck_fun(o);
+}
+       
+OP *
 Perl_ck_join(pTHX_ OP *o)
 {
-    const OP * const kid = OP_SIBLING(cLISTOPo->op_first);
+    OP * const kid = OP_SIBLING(cLISTOPo->op_first);
 
     PERL_ARGS_ASSERT_CK_JOIN;
 
@@ -10586,6 +10638,23 @@ Perl_ck_join(pTHX_ OP *o)
                        SVfARG(msg), SVfARG(msg));
        }
     }
+    if (kid->op_type == OP_CONST  /* an innocent, unsuspicious separator */
+     || (kid->op_type == OP_PADSV && !(kid->op_private & OPpLVAL_INTRO))
+     || (kid->op_type==OP_RV2SV && kUNOP->op_first->op_type == OP_GV
+       && !(kid->op_private & (OPpLVAL_INTRO|OPpOUR_INTRO))))
+    {
+       const OP * const bairn = OP_SIBLING(kid); /* the list */
+       if (bairn && !OP_HAS_SIBLING(bairn) /* single-item list */
+        && PL_opargs[bairn->op_type] & OA_RETSCALAR)
+       {
+           OP * const ret = convert(OP_STRINGIFY, 0,
+                                    op_sibling_splice(o, kid, 1, NULL));
+           op_free(o);
+           ret->op_folded = 1;
+           return ret;
+       }
+    }
+
     return ck_fun(o);
 }