Front page | perl.perl5.porters |
Postings from November 2014
Re: [perl #123092] Sub inlining inconsistencies
Thread Previous
|
Thread Next
From:
demerphq
Date:
November 2, 2014 07:30
Subject:
Re: [perl #123092] Sub inlining inconsistencies
Message ID:
CANgJU+UJzcsgdHDx7BtYNCytq1cj3+MJLLsab9igKM7JWKL85Q@mail.gmail.com
On 31 October 2014 06:08, Father Chrysostomos <perlbug-followup@perl.org>
wrote:
> # New Ticket Created by Father Chrysostomos
> # Please include the string: [perl #123092]
> # in the subject line of all future correspondence about this issue.
> # <URL: https://rt.perl.org/Ticket/Display.html?id=123092 >
>
>
> It is documented that you can thwart inlining of a subroutine with an
> explicit return:
>
> sub not_inlined () { return 23 }
>
> But the sub *will* be inlined, if it is a closure:
>
> BEGIN {
> my $x;
> *not_inlined = sub () { ++$x if 0; return 23 }
> }
> print not_inlined;
>
> Run that through perl -MO=Deparse and you will see:
>
> sub BEGIN {
> my $x;
> *not_inlined = sub () {
> '???';
> return 23;
> }
> ;
> }
> print 23;
> - syntax OK
>
> Similarly sub () { return $outer_lexical } will not be inlined, but if
> there is a statement before it that is optimised away, it is inlined:
>
> BEGIN {
> my $x = 43;
> *foo = sub () { die if 0; return return return $x }
> }
> print foo;
>
> In bleadperl (5.21.5), ‘state $x;’ or ‘our $x;’ is optimised away, so you
> could even put that there and have the sub inlined.
>
> And deparsed output will include ‘print 43’.
>
> In perl 5.005, the code for fetching a constant from a sub’s op tree
> actually made sense. It was based on the order in which the ops were
> executed. If the op chain consisted of a constant or closure variable
> followed by sub exit (via return or reaching the end of the sub), then it
> would be inlinable. So it applied to sub(){return 3} and sub(){return $x}
> and sub foo_set () { if (FLAG_MASK & FLAG_FOO) { 1 } }.
>
> It was changed later for various reasons, becoming a piece of code that
> doesn’t make sense and only works by accident. Later the documentation
> changed to mention the exception for explicit return.
>
> So, how should this work?
>
> The reason I ask is that I am trying to fix those cases where turning
> lexicals into constants breaks things, but still allowing lexicals
> unreferenced elsewhere to be inlined. But touching this code at all tends
> to change the behaviour of various subs, making things that were not
> inlinable inlinable and vice versa.
>
> Do we make any promises about what gets inlined and what does not?
> perlsub seems pretty clear about explicit return, but can we just optimise
> all other cases consistently (based on the execution chain)? Or should we
> only optimise a single statement, not allowing extra statements that were
> optimised away?
>
> This is what perlsub says about explicit return:
>
> The warning is considered severe enough not to be affected by the
> B<-w> switch (or its absence) because previously compiled invocations
> of the function will still be using the old value of the function. If
> you need to be able to redefine the subroutine, you need to ensure
> that it isn't inlined, either by dropping the C<()> prototype (which
> changes calling semantics, so beware) or by thwarting the inlining
> mechanism in some other way, e.g. by adding an explicit C<return>:
>
> sub not_inlined () { return 23 }
>
Seems to me the problem here is that the () prototype does too much, in
that it is used to mark a sub as constant, and to mark as sub as
argumentless. Since changing that at all will break lots of stuff, I think
the safest solution is to leave it alone, possibly in the long term
deprecating it, and add two new prototype's which do the two jobs
separately, once they have been in the wild for a while you can deprecate
and then remove the () prototype.
With these two behaviours separated there is no need for code detection,
any sub with a "C" prototye would be executed once at compile time, and
then its result used in place of any call to it in the code. (Which is how
this should have been done in the first place.)
IOW, I think you are trying to solve this problem the wrong way. Don't
bother fixing it, make it unnecessary to do at all.
Yves
--
perl -Mre=debug -e "/just|another|perl|hacker/"
Thread Previous
|
Thread Next