develooper Front page | perl.perl5.porters | Postings from October 2014

[perl #123092] Sub inlining inconsistencies

Thread Previous | Thread Next
Father Chrysostomos
October 31, 2014 05:08
[perl #123092] Sub inlining inconsistencies
Message ID:
# New Ticket Created by  Father Chrysostomos 
# Please include the string:  [perl #123092]
# in the subject line of all future correspondence about this issue. 
# <URL: >

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:

  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:

  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 }


Father Chrysostomos

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About