In perl.git, the branch sprout/op_const_sv2 has been created
<http://perl5.git.perl.org/perl.git/commitdiff/61223142748fe46794db45d9402c9cad1c427952?hp=0000000000000000000000000000000000000000>
at 61223142748fe46794db45d9402c9cad1c427952 (commit)
- Log -----------------------------------------------------------------
commit 61223142748fe46794db45d9402c9cad1c427952
Author: Father Chrysostomos <[email protected]>
Date: Mon Nov 3 22:28:08 2014 -0800
Account for state vars when const-izing sub(){$x}
If the only lvalue use of a lexical âmyâ variable is its declaration,
then it is fine to turn a sub that closes over it into a constant.
But with state variables we have to be a little more careful.
This is fine:
state $x = something();
sub () { $x }
because the variable is only assigned to once. But this modifies the
same variable every time the enclosing sub is called:
state $x++;
sub () { $x }
So that closure must remain a closure, and not become a constant.
(However, for a simple lexical scalar in the sub like that, we still
make it a constant, but deprecate the usage.)
M op.c
M t/op/const-optree.t
commit 44a1345fa99600f71ef7a72f7836e64d41dbee20
Author: Father Chrysostomos <[email protected]>
Date: Mon Nov 3 22:18:11 2014 -0800
Account for string eval when const-izing sub(){$x}
If we have a string eval in the same scope as the variable, it is
potentially in value context.
M inline.h
M op.c
M pad.c
M t/op/const-optree.t
commit 31223794005797376ce498da5b4478056d032080
Author: Father Chrysostomos <[email protected]>
Date: Mon Nov 3 17:56:11 2014 -0800
Make op.c:op_const_sv static
It is no longer called from any other file.
M embed.fnc
M embed.h
M op.c
M proto.h
commit 304ee1718efcdd7178e845d1725e3bf3855a9e59
Author: Father Chrysostomos <[email protected]>
Date: Mon Nov 3 17:53:01 2014 -0800
Inline op_const_sv into cv_clone
op_const_sv is actually two functions in one. This particular calling
convention (CvCONST) was used only by cv_clone.
Half the code was not even necessary for cv_cloneâs use (the other
half only for its use), so this reduces the total number of lines.
M embed.fnc
M embed.h
M op.c
M pad.c
M proto.h
commit 47bd1587e55d2fa4da48ccf626be00bd45654957
Author: Father Chrysostomos <[email protected]>
Date: Sun Nov 2 22:24:32 2014 -0800
Make sub () { 0; 3 } inlinable once more
It probably stopped being inlinable in commit beab0874143b.
Following op_next pointers to see whether a subâs execution chain con-
sists of a constant followed by sub exit does not make sense if the
op_next pointers have not been set up yet.
So call LINKLIST earlier, so that we can merge the two calls to
op_const_sv in newATTRSUB (no need to search for constants twice).
That will allow sub () { 0; 3 } to be inlined once more, as it was in
perl 5.005 (I checked) and probably in 5.6, too (I didnât check).
This also allows us to remove initial the OP_LINESEQ check, which
was added to help this function into the block when we have no
op_next pointers.
op_const_sv is now called only before the peephole optimiser and
finalize_op, which removes the need for the special explicit return
check (it hasnât been optimised out of the execution chain yet) and
the need to account for constants that have been relocated to the pad
by finalize_op.
M embed.fnc
M embed.h
M op.c
M pad.c
M proto.h
M t/op/const-optree.t
commit c12fc37cdff071dd1abf5a7b8143ddec6bd5705d
Author: Father Chrysostomos <[email protected]>
Date: Sun Nov 2 21:54:22 2014 -0800
Allow sub():method{CONSTANT} to be inlined
This brings non-closure subs into conformity with closures.
M op.c
M t/op/const-optree.t
commit b02ab38cf7f0a30df4cc0a527eb241a84bd3b21e
Author: Father Chrysostomos <[email protected]>
Date: Sun Nov 2 21:34:23 2014 -0800
First arg to op_const_sv is never null
M embed.fnc
M op.c
M proto.h
commit ecc47641f8b216fad0dd4c02ffbe165007d5a05f
Author: Father Chrysostomos <[email protected]>
Date: Sun Nov 2 16:50:40 2014 -0800
Remove SvREADONLY_on from op.c:op_const_sv
If we turn on the padtmp flag, then this this SV will never be seen in
lvalue context, so whether it is read-only is irrelevant. Donât even
bother making it so.
M op.c
commit 65f9fc0bb5bd522592d1813c28c0dbf6968e19d8
Author: Father Chrysostomos <[email protected]>
Date: Sun Nov 2 16:46:57 2014 -0800
op.c:Start the search for const vars at CvSTART
When we search an op tree to see whether it could become a constant
closure, we search the op execution chain, but we donât necessarily
start at the beginning. We start at the outermost op of the first
statementâs contents. That means that for sub {$a+$b} we begin the
search at the + (add), even though the full execution chain is next-
state, gvsv, gvsv, add, leavesub.
It was this oddity that led to bug #63540. Originally (before
beab0874143b), the search through the op chain started at CvSTART
(the start of the execution chain), but was accidentally changed
in beab0874143b. (That was also when sub(){return 2} stopped
being inlined.)
Changing this back to the way it used to be allows use to remove the
check to see whether a null op has kids, which was added to handle op
trees like
b leavesub
- lineseq
1 nextstate
- null ->9
3 and
2 padsv
8 leave
4 enter
5 nextstate
7 die
6 pushmark
9 nextstate
a const
which is the result of sub { if($x){ die }; 0 }.
If we begin the search at the null op, and if nulls are skipped, we
end up missing the entire âifâ block and seeing just null, nextstate,
const, leavesub, which looks constant.
M op.c
commit c836a7af7d4eae65911b289c3345c7ae881c7f82
Author: Father Chrysostomos <[email protected]>
Date: Sun Nov 2 16:31:27 2014 -0800
Handle multiple closures in sub(){$x} const-izing
Till now, we were checking the reference count of the variable that we
have just closed over, to see whether the newly-cloned sub can become
a constant. A reference count of 2 would indicate that only the outer
pad and the pad of the newly-cloned sub held references.
Recent commits also checked whether the variable is used in lvalue
context in the outer sub in places other than its declaration.
This is insufficient to detect cases like:
my $x = 43;
my $const_closure = sub () { $x };
my $other_closure = sub {$x++};
Although it does work if the $other_closure comes first (because it
holds a refcount by the time the $const_closure is created).
Extending the check for lvalue uses to inner subs as well (the changes
this commit makes to op_lvalue_flags) fixes that issue. It does not
allows cases like
my $x = 43;
my $other_closure = sub { $x };
my $const_closure = sub () { $x };
to create a constant, because the reference count check still prevents
it. I tried removing the reference count check, but it fails for
cases like \(my $x = 1), which allows $x to be referenced elsewhere,
even though the only lvalue use of it is its declaration.
As with the commits leading up to this, we allow a simple sub(){$x} to
create constants erroneously where it would have done so before, but
with a deprecation warning.
The deprecation warning had to be moved, because it could trigger even
in those cases where the refcount check fails and we donât create a
constant, which is just wrong.
This commit does not account for string eval within the scope of
the variable.
M op.c
M t/op/const-optree.t
commit 5be1e345f17d7b3c96c75e47c7fdc3ac80a9231b
Author: Father Chrysostomos <[email protected]>
Date: Sun Nov 2 06:20:09 2014 -0800
const-optree.t: Correct comment
M t/op/const-optree.t
commit 1d82a40a7906b4042e81980a6d70be3bc5a86ff5
Author: Father Chrysostomos <[email protected]>
Date: Sun Nov 2 06:02:18 2014 -0800
Donât inline sub(){ 0; return $x }
If return occurs at the end of a sub, it is optimised out of the
execution, chain, so we have to look at the op tree structure to
detect it.
M op.c
M t/op/const-optree.t
commit 4da090a33e09da12d1d4874a26345b1db7a58aab
Author: Father Chrysostomos <[email protected]>
Date: Sat Nov 1 22:17:39 2014 -0700
Donât inline sub(){ 0; return $x; ... }
We document that explicit return prevents subs from being inlined.
But if that explicit return comes after a statement optimised away,
then it does not prevent inlining.
Originally, explicit return did not prevent inlining, and the way
constant subs were detected was to search through the op chain in
execution order, looking for padsv followed by return or leavesub.
Later, things were accidentally changed, such that the search began,
not at the beginning of the execution chain, but at the outer-
most op of the first statementâs contents. That means that, with
sub () { $a + $b }, we begin the search at the + (add), even though
the execution order is nextstate, gvsv, gvsv, add, leavesub. So for
sub () { return $x } we begin the search at return, and miss the padsv
that precedes it.
Even though it was accidental that âreturnâ inlining was broken, it
ended up becoming a documented feature, and has been so for over a
decade. So I am just making things consistent with that.
This commit only affects those cases where the return is not at the
end of the sub. At the end of the sub, the return is optimised out of
the execution chain, so it requires a little more work, which the next
commit will do.
M op.c
M t/op/const-optree.t
commit 91a80d495ab6dd69a3269e924777bc0eecc6999b
Author: Father Chrysostomos <[email protected]>
Date: Sat Nov 1 22:01:54 2014 -0700
const-optree.t: More tests
Test explicit return with variable (single statement) and simple scalar
not modified elsewhere.
M t/op/const-optree.t
commit 19eab468672165c19cca70cd8ed8e8ea0cacd1df
Author: Father Chrysostomos <[email protected]>
Date: Sat Nov 1 21:52:08 2014 -0700
Donât inline sub(){my $x; state sub z {$x} $outer}
The code that determines whether a closure prototype is potentially eligi-
ble for inlining when cloned iterates through the op chain in the order it
is executed. It looks for padsv (or const) followed by sub exit. Cer-
tain ops with no side effects, like nextstate and null, are skipped over.
There is a flaw in the logic handling padsv ops. If the padsv op closes
over a variable from outside, we record that we have seen an SV, so
another padsv or const prevents inlining. If the first padsv op does
not close over a variable from outside, but belongs to this sub itself,
then we just ignore it and skip over it as we would a null op. So that
means sub () { my $x; $outer_var } is marked as potentially eligible
for inlining.
Now, when cloning happens (i.e., when the âsubâ expression is
evaluated),
we search through the op chain (once more) of subs marked as potentially
inlinable and find the first padsv op, which we assume is the one that
closes over the outer sub. So we get the value of the wrong variable.
Now, there is a reference count check that usually saves the day. The
reference count must be exactly 2, one reference held by the newly-cloned
closure and the other by the outer sub. Usually âmy $xâ will have a
ref-
erence count of 1 when the sub is cloned, so it does not become inlina-
ble, but behaves as expected.
With state subs, however, which are cloned when the enclosing sub is
cloned, we can make that inner lexical have a reference count of 2.
So the sub becomes inlinable, using the undefined value taken from the
wrong variable:
$ ./perl -Ilib -MO=Concise -Mfeature=:all -e 'BEGIN { my $x = 43; *foo =
sub :prototype(){my $y; state sub z { $y } $x}} print foo()'
The lexical_subs feature is experimental at -e line 1.
6 <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 53 -e:1) v:%,{,469764096 ->3
5 <@> print vK ->6
3 <0> pushmark s ->4
4 <$> const[NULL ] s*/FOLD ->5
-e syntax OK
Notice the const[NULL ], which indicates undef.
At least thatâs what we get if we are lucky enough not to crash in the
padname-handling code added recently to op.c:op_const_sv. Sometimes
this results:
$ ./perl -Ilib -MO=Concise -Mfeature=:all -e 'BEGIN { my $x = 43; *foo =
sub :prototype(){my $y; state sub z { $y } $x}} print foo()'
The lexical_subs feature is experimental at -e line 1.
Segmentation fault: 11
M op.c
M t/op/const-optree.t
commit c2ea96c42576accffee5f00fe5158054039cde35
Author: Father Chrysostomos <[email protected]>
Date: Sat Nov 1 19:08:46 2014 -0700
Donât inline sub(){0; $x} if $x changes elsewhere
Some op trees will turn a sub into a constant even if they
are more than just a simple constant or lexical variable. In
particular, a statement optimised away followed by a lexi-
cal variable is eligible for inlining. As discussed in
<[email protected]>, make these
more complex op trees follow closure rules properly. If the outer
lexical is used in lvalue context in places other than its declara-
tion, then we should forego inlining.
M op.c
M t/op/const-optree.t
commit c9e9822c821e444dbbe0d4230dc67c9ac04af7c0
Author: Father Chrysostomos <[email protected]>
Date: Sat Nov 1 18:45:37 2014 -0700
Restructure const-optree.t
This new layout (it is completely rewritten) allows endless variations
to be tested more easily.
M t/op/const-optree.t
commit 5303989d273f8ad501a244be9b35a527dfd08ef3
Author: Father Chrysostomos <[email protected]>
Date: Sat Nov 1 16:41:23 2014 -0700
Use âbehaviorâ consistently in perldiag
âBehaviorâ is used many times; âbehaviourâ only three.
M pod/perldiag.pod
commit a49f230a324ce6648214c2a54ca37cd88507bd04
Author: Father Chrysostomos <[email protected]>
Date: Sat Nov 1 07:07:36 2014 -0700
Deprecate inlining sub(){$x} if $x is changed elsewhere
With the new PadnameLVALUE flag, we can detect cases where an outer
lexical is used multiple times in lvalue context. If the subroutine
contains just a lexical variable and nothing else, deprecate this
behaviour, so we can change it not to break the closure pattern at
some future date.
Future commits will fix those cases where the subroutine contains more
than just a lexical variable, without a deprecation cycle.
Adding this code to op_const_sv doesnât really make sense. More to
the point, having S_cv_clone_pad call op_const_sv doesnât make sense,
but changing that (moving this code directly to S_cv_clone_pad) will
require other refactorings to avoid breaking some cases of constant
(real constant) inlining, such as sub(){$x++ if 0; 3}, which cur-
rently gets inlined.
M embed.fnc
M embed.h
M op.c
M pad.c
M pod/perldiag.pod
M proto.h
M t/op/const-optree.t
commit d8c0988a4e25a1366fe651db728ba5b46feedcd4
Author: Father Chrysostomos <[email protected]>
Date: Sat Nov 1 14:33:35 2014 -0700
Put sub(){ ... } constant tests in a new file
M MANIFEST
M t/op/closure.t
A t/op/const-optree.t
M t/op/sub.t
commit 6fddce3fbaa14993c0596a3bf7650a67ebed499d
Author: Father Chrysostomos <[email protected]>
Date: Fri Oct 31 22:08:52 2014 -0700
pad.c: Move constant closure code
S_cv_clone normally calls S_cv_clone_pad, which takes care of cloning
the pad, surprisingly enough. Then S_cv_clone checks whether it can
turn a closure into a constant. That code needs to be moved into
S_cv_clone_pad, because, not only is it pad-related, but to work cor-
rectly it needs to access the outer sub (which S_cv_clone_pad already
fetches for its own use), which future commits will make it do.
M pad.c
commit 276801b8943a919792c3979483dce9d449adccdf
Author: Father Chrysostomos <[email protected]>
Date: Fri Oct 31 22:04:21 2014 -0700
pad.c: Have S_cv_clone_pad return the CV
Currently it is a void function, because it modifies the CV in place.
Shortly it will sometimes return a different CV from the one it was
passed.
M pad.c
commit eb98632b20ebb0e3d571851a5effcd5595809825
Author: Father Chrysostomos <[email protected]>
Date: Fri Oct 31 21:59:39 2014 -0700
pad.c:S_cv_clone: Add assertion
This code cannot handle the case where cloning uses an existing
stub, because it creates a new CV via newCONSTSUB. Cloning into
an existing stub only happens for lexical subs, and the previous
commit prevented them from reaching this code. Before that we
would have had assertion failures in pp_padcv.
M pad.c
commit 9fb220b10befd1fb842bd8ad871e5c9685ad3dad
Author: Father Chrysostomos <[email protected]>
Date: Fri Oct 31 21:57:28 2014 -0700
Donât attempt to inline my sub (){$outer_var}
$ perl5.18.2 -Ilib -Mfeature=lexical_subs -e ' my $x; my sub a(){$x};
print a'
The lexical_subs feature is experimental at -e line 1.
Segmentation fault: 11
Same in blead.
When calls to the sub are compiled (the âaâ in âprint aâ) the value
of the lexical variable cannot possibly known, because the sub hasnât
been cloned yet, and all we have is the closure prototype.
A potentially constant closure prototype is marked CvCONST and
cv_const_sv_or_av (called by the code in toke.c that handles bare-
words) thinks that CvCONST means we have a constant XSUB. Only lexi-
cal subs allow a closure prototype to reach that function.
We shouldnât mark the closure prototype as CvCONST to begin with.
Because when we do, the âconstantâ is retrieved from CvXUBANY, which
is a union shared by CvSTART. Then toke.c does SvREFCNT_inc on
CvSTART, and screws up the op tree.
M op.c
M t/op/lexsub.t
commit fd33016bc81e2979a20070d4506cf2033fb020cb
Author: Father Chrysostomos <[email protected]>
Date: Fri Oct 31 15:54:39 2014 -0700
op.c: Record lvalue use of lexicals
other than where the variable is declared.
This will be used to determine whether my $x; sub(){$x} can make a
constant. Currently, this becomes a constant even if $x is subse-
quently modified, breaking the closure behaviour (bug #79908).
M op.c
commit 784eadbed9f40a90e42651ba2d64131b08d2861e
Author: Father Chrysostomos <[email protected]>
Date: Fri Oct 31 14:54:20 2014 -0700
Add two new flags for pad names
These will be used to record whether a pad entry is used as an lvalue
multiple times, or whether it is closed over multiple times. In either
case, it cannot be used as a constant.
M pad.h
M sv.c
M sv.h
commit d48d45bea0790a78aad99d42a8e80b7ad3c6fe15
Author: Father Chrysostomos <[email protected]>
Date: Thu Oct 30 08:56:44 2014 -0700
Update comments about sub(){$x} consting
It no longer has anything to do with constant.pm.
M pad.c
commit b0732b1885c4126594765eb0086453b4331b6800
Author: Father Chrysostomos <[email protected]>
Date: Thu Oct 30 08:52:56 2014 -0700
Donât turn sub:CustomAttr(){$outer_lex} into a const
We canât know what the attributes are for, and turning it into a con-
stant discards the attributes.
M ext/XS-APItest/t/call_checker.t
M op.c
commit bbb7196832de400e35aaf8f55247f43162b49c78
Author: Father Chrysostomos <[email protected]>
Date: Thu Oct 30 08:46:00 2014 -0700
Preserve :method in sub:method(){$outer_lex}
When we turn such a sub into a constant, we need to preserve the
attribute, since it changes behaviour.
M pad.c
M t/op/sub.t
commit 328e55b342f40c23319c2364ed9b971f463a0f15
Author: Father Chrysostomos <[email protected]>
Date: Thu Oct 30 05:08:19 2014 -0700
Make sub(){$outer_lexical} return a copy each time
We donât actually stop in from being inlined, but simply mark the
inlined value as PADTMP, so it gets copied in lvalue context.
M op.c
M t/op/sub.t
-----------------------------------------------------------------------
--
Perl5 Master Repository