diff options
author | Nicholas Clark <nick@ccl4.org> | 2011-06-17 16:40:30 +0200 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2011-06-23 10:22:13 +0200 |
commit | 8ca8a454f60a417f5040d6e3e47673333702f58d (patch) | |
tree | eff5d0d46490c02817e88b95e66f0beaf0a9b2a1 | |
parent | 7c4202907c499a6fd1a41da6fdf1d414ecadeb37 (diff) | |
download | perl-8ca8a454f60a417f5040d6e3e47673333702f58d.tar.gz |
For s///r, avoid copying the source early only to edit it in place.
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.
-rw-r--r-- | pod/perldelta.pod | 2 | ||||
-rw-r--r-- | pp_ctl.c | 47 | ||||
-rw-r--r-- | pp_hot.c | 81 |
3 files changed, 69 insertions, 61 deletions
diff --git a/pod/perldelta.pod b/pod/perldelta.pod index 37c4dc92b2..2a94ed9dd3 100644 --- a/pod/perldelta.pod +++ b/pod/perldelta.pod @@ -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 @@ -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); @@ -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) { |