This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #118747] Allow in-place s///g when !!PL_sawampersand
authorFather Chrysostomos <sprout@cpan.org>
Thu, 22 Aug 2013 04:59:20 +0000 (21:59 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Thu, 22 Aug 2013 15:28:10 +0000 (08:28 -0700)
This is the more correct version of 1555b325 which was reverted
by 6200d5a0e.

In pp_subst, there is an initial pattern match against the target
string, followed by logic to determine which of several code paths
will handle the rest of the substitution, depending on which shortcuts
can be taken.

There is one path specifically for doing a global sort (/g) and modi-
fying the target in place.  This code was skipped if the target was a
copy-on-write scalar or if the pre-match copy was enabled.  The pre-
match copy is always enabled now, so this code is unreachable.

In-place substitution stringifies the rhs at the outset, just after
the first regexp match, but before any substitution.  Then it uses
that string buffer, expecting it not to change.

That clearly cannot work with s/a/$&/g; it will also cause erratic
behaviour in the case of regexp code blocks (which will see the
string being modified, which doesn not happen with unoptimised subst).
That’s why the in-place optimisation has to be skipped when the
REXEC_COPY_STR flag is set.

But we can tweak that logic:

• As long as the rhs is not a magical var, its contents are not going
  to change from one iteration to the next.
• If there are no code blocks, nothing will see the string during the
  substitution.

So this commit adds logic to check those things, enabling this opti-
misation where possible.

Skipping this optimisation for the pre-match copy was originally added
in commit 5d5aaa5e7.

pp_hot.c

index c30acc5..75e5d65 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -2159,7 +2159,10 @@ PP(pp_subst)
        && !is_cow
 #endif
         && (I32)clen <= RX_MINLENRET(rx)
-        && (once || !(r_flags & REXEC_COPY_STR))
+        && (  once
+           || !(r_flags & REXEC_COPY_STR)
+           || (!SvGMAGICAL(dstr) && !(RX_EXTFLAGS(rx) & RXf_EVAL_SEEN))
+           )
         && !(RX_EXTFLAGS(rx) & RXf_NO_INPLACE_SUBST)
        && (!doutf8 || SvUTF8(TARG))
        && !(rpm->op_pmflags & PMf_NONDESTRUCT))