summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2011-06-17 16:40:30 +0200
committerNicholas Clark <nick@ccl4.org>2011-06-23 10:22:13 +0200
commit8ca8a454f60a417f5040d6e3e47673333702f58d (patch)
treeeff5d0d46490c02817e88b95e66f0beaf0a9b2a1
parent7c4202907c499a6fd1a41da6fdf1d414ecadeb37 (diff)
downloadperl-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.pod2
-rw-r--r--pp_ctl.c47
-rw-r--r--pp_hot.c81
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
diff --git a/pp_ctl.c b/pp_ctl.c
index 9f7c52a1bf..4324253692 100644
--- 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);
diff --git a/pp_hot.c b/pp_hot.c
index 9a869f6015..d2e52408b9 100644
--- 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) {