The difference is that 5.42 made constants produced by constant folding eligible for buffer sharing ("COW").[1]
Use SvGROW if you want the buffer to have a minimum size.
In the 5.42 run, $buffer initially shares a buffer with the constant created by 'z' x 60. This is evident by the IsCOW flag indicating the buffer is shared with another scalar.
This means that set_pv must create a new buffer. Notice how the address of the buffer changed from 0x2352275d050 to 0x2352279a8a0.
There's no reason for set_pv to create a new buffer whose length is based on the old string buffer's length. The new buffer's length will be based on length of the string being assigned.
SV = PV(0x2352069fd80) at 0x235206db678
REFCNT = 1
FLAGS = (POK,IsCOW,pPOK) <- IsCOW = Shared buffer
PV = 0x2352275d050 "zzz...zzz"\0
CUR = 60
LEN = 64
COW_REFCNT = 1
SV = PV(0x2352069fd80) at 0x235206db678
REFCNT = 1
FLAGS = (POK,pPOK) <- No longer sharing a buffer
PV = 0x2352279a8a0 "Hello there"\0 <- New buffer at new address
CUR = 11
LEN = 16
In the 5.40 run, $buffer doesn't share a buffer with another scalar, as noted by the lack of the IsCOW flag.
This means that set_pv can reuse the existing buffer if it's large enough. And it is. Notice how the address of the buffer remains 0x2077084ae90.
SV = PV(0x2076e35a3b0) at 0x2076e41b338
REFCNT = 1
FLAGS = (POK,pPOK) <- Not sharing a buffer
PV = 0x2077084ae90 "zzz...zzz"\0
CUR = 60
LEN = 62
SV = PV(0x2076e35a3b0) at 0x2076e41b338
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x2077084ae90 "Hello there"\0 <- Same address. Same buffer
CUR = 11
LEN = 62
So why is the buffer shared with 'z' x 60 in one version and not the other?
5.42 fixed a bug that prevented the buffer of constants created by constant folding from being shared. An in-depth explanation of the bug follows.
When a string buffer is shared, the IsCOW flag of both scalars is set, and a share count is placed in the unused portion of the buffer.[2] This means that for COW to be used, there must be free space at the end of the string buffer, and the string buffer must be modifiable.
When Perl encounters a literal, it produces a read-only scalar in memory.[3] Being read-only makes it ineligible for COW. But that would be dumb. So Perl marks the scalar as already being shared with zero scalars.
$ perl -MDevel::Peek -e'Dump( "zzzzzz" )'
SV = PV(0x57f44e969f20) at 0x57f44e9980a8
REFCNT = 1
FLAGS = (POK,IsCOW,READONLY,PROTECT,pPOK)
PV = 0x57f44e9e8140 "zzzzzz"\0
CUR = 6
LEN = 16
COW_REFCNT = 0
One wouldn't normally encounter a scalar shared with zero other scalars. But since Perl doesn't need to check if a scalar's buffer can be shared if it's already shared, this permits the read-only scalar's buffer to be shared.
For literals, this was true of both 5.42 and earlier versions.
$ 5.42t/bin/perl -MDevel::Peek -e'Dump( "zzzzzz" )'
SV = PV(0x582cd0b72f20) at 0x582cd0ba1098
REFCNT = 1
FLAGS = (POK,IsCOW,READONLY,PROTECT,pPOK)
PV = 0x582cd0ba4a40 "zzzzzz"\0
CUR = 6
LEN = 16
COW_REFCNT = 0
$ 5.40t/bin/perl -MDevel::Peek -e'Dump( "zzzzzz" )'
SV = PV(0x6381a4328f20) at 0x6381a4357028
REFCNT = 1
FLAGS = (POK,IsCOW,READONLY,PROTECT,pPOK)
PV = 0x6381a43a7d10 "zzzzzz"\0
CUR = 6
LEN = 16
COW_REFCNT = 0
But before 5.42, constants produced by constant folding weren't being set up this way, so they weren't eligible for COW.
$ 5.42t/bin/perl -MDevel::Peek -e'Dump( "zzz" . "zzz" )'
SV = PV(0x6110ea0263a0) at 0x6110ea0540a0
REFCNT = 1
FLAGS = (PADTMP,POK,IsCOW,READONLY,PROTECT,pPOK)
PV = 0x6110ea080fc0 "zzzzzz"\0
CUR = 6
LEN = 16
COW_REFCNT = 0
$ 5.40t/bin/perl -MDevel::Peek -e'Dump( "zzz" . "zzz" )'
SV = PV(0x5be570a973a0) at 0x5be570ac50c0
REFCNT = 1
FLAGS = (PADTMP,POK,READONLY,PROTECT,pPOK)
PV = 0x5be570af23e0 "zzzzzz"\0
CUR = 6
LEN = 16
$ 5.42t/bin/perl -MDevel::Peek -e'Dump( "z" x 6 )'
SV = PV(0x607fa35c4200) at 0x607fa35f2138
REFCNT = 1
FLAGS = (PADTMP,POK,IsCOW,READONLY,PROTECT,pPOK)
PV = 0x607fa3603d10 "zzzzzz"\0
CUR = 6
LEN = 16
COW_REFCNT = 0
$ 5.40t/bin/perl -MDevel::Peek -e'Dump( "z" x 6 )'
SV = PV(0x5d8bda39d200) at 0x5d8bda3cafb8
REFCNT = 1
FLAGS = (PADTMP,POK,READONLY,PROTECT,pPOK)
PV = 0x5d8bda3d5340 "zzzzzz"\0
CUR = 6
LEN = 16
-
From perl5420delta,
Constant-folded strings are now shareable via the Copy-on-Write mechanism. [GH #22163]
The following code would previously have allocated eleven string buffers, each containing one million "A"s:
my @scalars; push @scalars, ("A" x 1_000_000) for 0..9;
Now a single buffer is allocated and shared between a CONST OP and the ten scalar elements of @scalars.
Note that any code using this sort of constant to simulate memory leaks (perhaps in test files) must now permute the string in order to trigger a string copy and the allocation of separate buffers. For example, ("A" x 1_000_000).time might be a suitable small change.
-
It must be somewhere all users of the buffer can find, and this is a very efficient solution in terms of speed and memory. But it means it can't be used for every scalar.
-
So you don't do stupid things like
for ( 1 .. 2 ) {
my $r = \"abc";
say $$r;
$$r = "def";
}
|