This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
For s///r, avoid copying the source early only to edit it in place.
authorNicholas Clark <nick@ccl4.org>
Fri, 17 Jun 2011 14:40:30 +0000 (16:40 +0200)
committerNicholas Clark <nick@ccl4.org>
Thu, 23 Jun 2011 08:22:13 +0000 (10:22 +0200)
Instead, take advantage of the "can't edit in place" code path of pp_subst
which writes to a new scalar, and that pp_substcont always leaves the original
intact, writing to a new scalar.

pod/perldelta.pod
pp_ctl.c
pp_hot.c

index 37c4dc9..2a94ed9 100644 (file)
@@ -69,7 +69,7 @@ may well be none in a stable release.
 
 =item *
 
-XXX
+The implementation of C<s///r> makes one fewer copy of the scalar's value.
 
 =back
 
index 9f7c52a..4324253 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -305,7 +305,7 @@ PP(pp_substcont)
                              ? (REXEC_IGNOREPOS|REXEC_NOT_FIRST)
                              : (REXEC_COPY_STR|REXEC_IGNOREPOS|REXEC_NOT_FIRST))))
        {
-           SV * const targ = cx->sb_targ;
+           SV *targ = cx->sb_targ;
 
            assert(cx->sb_strend >= s);
            if(cx->sb_strend > s) {
@@ -317,27 +317,32 @@ PP(pp_substcont)
            if (RX_MATCH_TAINTED(rx)) /* run time pattern taint, eg locale */
                cx->sb_rxtainted |= SUBST_TAINT_PAT;
 
+           if (pm->op_pmflags & PMf_NONDESTRUCT) {
+               PUSHs(dstr);
+               /* From here on down we're using the copy, and leaving the
+                  original untouched.  */
+               targ = dstr;
+           }
+           else {
 #ifdef PERL_OLD_COPY_ON_WRITE
-           if (SvIsCOW(targ)) {
-               sv_force_normal_flags(targ, SV_COW_DROP_PV);
-           } else
+               if (SvIsCOW(targ)) {
+                   sv_force_normal_flags(targ, SV_COW_DROP_PV);
+               } else
 #endif
-           {
-               SvPV_free(targ);
-           }
-           SvPV_set(targ, SvPVX(dstr));
-           SvCUR_set(targ, SvCUR(dstr));
-           SvLEN_set(targ, SvLEN(dstr));
-           if (DO_UTF8(dstr))
-               SvUTF8_on(targ);
-           SvPV_set(dstr, NULL);
-
-           if (pm->op_pmflags & PMf_NONDESTRUCT)
-               PUSHs(targ);
-           else
+               {
+                   SvPV_free(targ);
+               }
+               SvPV_set(targ, SvPVX(dstr));
+               SvCUR_set(targ, SvCUR(dstr));
+               SvLEN_set(targ, SvLEN(dstr));
+               if (DO_UTF8(dstr))
+                   SvUTF8_on(targ);
+               SvPV_set(dstr, NULL);
+
                mPUSHi(saviters - 1);
 
-           (void)SvPOK_only_UTF8(targ);
+               (void)SvPOK_only_UTF8(targ);
+           }
 
            /* update the taint state of various various variables in
             * preparation for final exit.
@@ -384,7 +389,8 @@ PP(pp_substcont)
     }
     cx->sb_s = RX_OFFS(rx)[0].end + orig;
     { /* Update the pos() information. */
-       SV * const sv = cx->sb_targ;
+       SV * const sv
+           = (pm->op_pmflags & PMf_NONDESTRUCT) ? cx->sb_dstr : cx->sb_targ;
        MAGIC *mg;
        SvUPGRADE(sv, SVt_PVMG);
        if (!(mg = mg_find(sv, PERL_MAGIC_regex_global))) {
@@ -414,7 +420,8 @@ PP(pp_substcont)
 
        if (cx->sb_iters > 1 && (cx->sb_rxtainted & 
                        (SUBST_TAINT_STR|SUBST_TAINT_PAT|SUBST_TAINT_REPL)))
-           SvTAINTED_on(cx->sb_targ);
+           SvTAINTED_on((pm->op_pmflags & PMf_NONDESTRUCT)
+                        ? cx->sb_dstr : cx->sb_targ);
        TAINT_NOT;
     }
     rxres_save(&cx->sb_rxres, rx);
index 9a869f6..d2e5240 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -2196,11 +2196,6 @@ PP(pp_subst)
        EXTEND(SP,1);
     }
 
-    /* In non-destructive replacement mode, duplicate target scalar so it
-     * remains unchanged. */
-    if (rpm->op_pmflags & PMf_NONDESTRUCT)
-       TARG = sv_2mortal(newSVsv(TARG));
-
 #ifdef PERL_OLD_COPY_ON_WRITE
     /* Awooga. Awooga. "bool" types that are actually char are dangerous,
        because they make integers such as 256 "false".  */
@@ -2209,14 +2204,14 @@ PP(pp_subst)
     if (SvIsCOW(TARG))
        sv_force_normal_flags(TARG,0);
 #endif
-    if (
+    if (!(rpm->op_pmflags & PMf_NONDESTRUCT)
 #ifdef PERL_OLD_COPY_ON_WRITE
-       !is_cow &&
+       && !is_cow
 #endif
-       (SvREADONLY(TARG)
-        || ( ((SvTYPE(TARG) == SVt_PVGV && isGV_with_GP(TARG))
-              || SvTYPE(TARG) > SVt_PVLV)
-            && !(SvTYPE(TARG) == SVt_PVGV && SvFAKE(TARG)))))
+       && (SvREADONLY(TARG)
+           || ( ((SvTYPE(TARG) == SVt_PVGV && isGV_with_GP(TARG))
+                 || SvTYPE(TARG) > SVt_PVLV)
+                && !(SvTYPE(TARG) == SVt_PVGV && SvFAKE(TARG)))))
        Perl_croak_no_modify(aTHX);
     PUTBACK;
 
@@ -2338,7 +2333,8 @@ PP(pp_subst)
 #endif
        && (I32)clen <= RX_MINLENRET(rx) && (once || !(r_flags & REXEC_COPY_STR))
        && !(RX_EXTFLAGS(rx) & RXf_LOOKBEHIND_SEEN)
-       && (!doutf8 || SvUTF8(TARG)))
+       && (!doutf8 || SvUTF8(TARG))
+       && !(rpm->op_pmflags & PMf_NONDESTRUCT))
     {
 
 #ifdef PERL_OLD_COPY_ON_WRITE
@@ -2391,7 +2387,7 @@ PP(pp_subst)
                sv_chop(TARG, d);
            }
            SPAGAIN;
-           PUSHs(rpm->op_pmflags & PMf_NONDESTRUCT ? TARG : &PL_sv_yes);
+           PUSHs(&PL_sv_yes);
        }
        else {
            do {
@@ -2420,10 +2416,7 @@ PP(pp_subst)
                Move(s, d, i+1, char);          /* include the NUL */
            }
            SPAGAIN;
-           if (rpm->op_pmflags & PMf_NONDESTRUCT)
-               PUSHs(TARG);
-           else
-               mPUSHi((I32)iters);
+           mPUSHi((I32)iters);
        }
     }
     else {
@@ -2480,34 +2473,42 @@ PP(pp_subst)
        else
            sv_catpvn(dstr, s, strend - s);
 
+       if (rpm->op_pmflags & PMf_NONDESTRUCT) {
+           /* From here on down we're using the copy, and leaving the original
+              untouched.  */
+           TARG = dstr;
+           SPAGAIN;
+           PUSHs(dstr);
+       } else {
 #ifdef PERL_OLD_COPY_ON_WRITE
-       /* The match may make the string COW. If so, brilliant, because that's
-          just saved us one malloc, copy and free - the regexp has donated
-          the old buffer, and we malloc an entirely new one, rather than the
-          regexp malloc()ing a buffer and copying our original, only for
-          us to throw it away here during the substitution.  */
-       if (SvIsCOW(TARG)) {
-           sv_force_normal_flags(TARG, SV_COW_DROP_PV);
-       } else
+           /* The match may make the string COW. If so, brilliant, because
+              that's just saved us one malloc, copy and free - the regexp has
+              donated the old buffer, and we malloc an entirely new one, rather
+              than the regexp malloc()ing a buffer and copying our original,
+              only for us to throw it away here during the substitution.  */
+           if (SvIsCOW(TARG)) {
+               sv_force_normal_flags(TARG, SV_COW_DROP_PV);
+           } else
 #endif
-       {
-           SvPV_free(TARG);
-       }
-       SvPV_set(TARG, SvPVX(dstr));
-       SvCUR_set(TARG, SvCUR(dstr));
-       SvLEN_set(TARG, SvLEN(dstr));
-       doutf8 |= DO_UTF8(dstr);
-       SvPV_set(dstr, NULL);
+           {
+               SvPV_free(TARG);
+           }
+           SvPV_set(TARG, SvPVX(dstr));
+           SvCUR_set(TARG, SvCUR(dstr));
+           SvLEN_set(TARG, SvLEN(dstr));
+           doutf8 |= DO_UTF8(dstr);
+           SvPV_set(dstr, NULL);
 
-       SPAGAIN;
-       if (rpm->op_pmflags & PMf_NONDESTRUCT)
-           PUSHs(TARG);
-       else
+           SPAGAIN;
            mPUSHi((I32)iters);
+       }
+    }
+
+    if (!(rpm->op_pmflags & PMf_NONDESTRUCT)) {
+       (void)SvPOK_only_UTF8(TARG);
+       if (doutf8)
+           SvUTF8_on(TARG);
     }
-    (void)SvPOK_only_UTF8(TARG);
-    if (doutf8)
-       SvUTF8_on(TARG);
 
     /* See "how taint works" above */
     if (PL_tainting) {