summaryrefslogtreecommitdiff
path: root/sv.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2016-05-02 14:46:49 +0100
committerRicardo Signes <rjbs@cpan.org>2016-05-03 11:23:03 -0400
commit9a21f3bac1068ca5b18174aada84118ea04fe3eb (patch)
tree43f401ca40932ec73affc05d24b1a237c912a457 /sv.c
parenta21b01b71e8d60c4063525294714681dc88a5bcd (diff)
downloadperl-9a21f3bac1068ca5b18174aada84118ea04fe3eb.tar.gz
RT #127855] Slowdown in m//g on COW strings
Better fix for this issue. The previous couple of commits revert an earlier fix for this, which basically modified SvGROW or a particular one of its callers to add 1 to the requested length to ensure that there was space for any future COW reference count (which is stored in spare byte off the end of the string if SvCUR + null byte < SvLEN). It turns out that sv_grow() already does a +1 over-allocation (added by me with v5.19.0-442-gcbcb2a1), *except* that I made it skip the +1 if the request size seemed to be a large power of two: with the idea being that if someone had requested an exact big power of two then they were probably doing something with buffers, and wouldn't want an 0x10000001 byte buffer when they requested 0x10000000 bytes. This was me basically being conservative. However, I was probably too conservative: the simple test I added just checked that bottom 8 bits were zero and if so, assumed that it was a big buffer request. So as a side effect of this over-simple test, something like 0x13d57f00 wouldn't be incremented to 0x13d57f01. This is what was discovered in the original report in the the RT ticket: strings allocated with lengths whose lower 8 bits were zero wouldn't have space for a COW refcount, so would become much slower on things like while $g =~ m/0/g. This commit improves the test so it only skips the +1 on lengths that are an exact power of 2 and are greater than 0xfff.
Diffstat (limited to 'sv.c')
-rw-r--r--sv.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/sv.c b/sv.c
index 0200679087..decc47c3dd 100644
--- a/sv.c
+++ b/sv.c
@@ -1573,7 +1573,9 @@ Perl_sv_grow(pTHX_ SV *const sv, STRLEN newlen)
* Only increment if the allocation isn't MEM_SIZE_MAX,
* otherwise it will wrap to 0.
*/
- if (newlen & 0xff && newlen != MEM_SIZE_MAX)
+ if ( (newlen < 0x1000 || (newlen & (newlen - 1)))
+ && newlen != MEM_SIZE_MAX
+ )
newlen++;
#endif