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

Reply via email to