develooper Front page | perl.perl5.porters | Postings from June 2008

Re: [perl #56150] return return

Thread Previous | Thread Next
From:
Reini Urban
Date:
June 25, 2008 04:15
Subject:
Re: [perl #56150] return return
Message ID:
48611B82.8060304@x-ray.at
David Nicol schrieb:
> On Mon, Jun 23, 2008 at 10:20 AM, Aristotle Pagaltzis <pagaltzis@gmx.de> wrote:
> 
>> And those of us who prefer to use guard clauses and not contort
>> subroutines into nested single expressions cannot avoid `return`
>> at all.
> 
> leaving the question, why doesn't the optimizer get rid of return?
> 
> tentative answer: because the optimizer authors didn't get around to it,
> seeing once-per-subroutine as not enough savings to justify the effort.

The optimizer does something with the op_type OP_RETURN.
The ck_return() does change all kids to OP_LEAVESUBLV if lvalue'd.
The problem is the tokenizer.

Concise does not help - identical results.
$ perl5.11.0d -MO=Concise,-exec  -e'sub foo {return return}; foo'
1  <0> enter
2  <;> nextstate(main 2 -e:1) v:{
3  <0> pushmark s
4  <#> gv[*foo] s
5  <1> entersub[t2] vKS/TARG,1
6  <@> leave[1 ref] vKP/REFC

$ perl5.11.0d -MO=Concise,-exec  -e'sub foo {return}; foo'
1  <0> enter
2  <;> nextstate(main 2 -e:1) v:{
3  <0> pushmark s
4  <#> gv[*foo] s
5  <1> entersub[t2] vKS/TARG,1
6  <@> leave[1 ref] vKP/REFC

At least -Dt (and -MO=Bytecode,-S) show something useful:

$ perl5.11.0d -Dt -e'sub foo {return return}; foo'
EXECUTING...
(-e:0)  enter
(-e:0)  nextstate
(-e:1)  pushmark
(-e:1)  gv(main::foo)
(-e:1)  entersub
(-e:1)  nextstate
(-e:1)  pushmark
(-e:1)  pushmark
(-e:1)  return
(-e:1)  leave

$ perl5.11.0d -Dt -e'sub foo {return}; foo'
EXECUTING...
(-e:0)  enter
(-e:0)  nextstate
(-e:1)  pushmark
(-e:1)  gv(main::foo)
(-e:1)  entersub
(-e:1)  nextstate
(-e:1)  pushmark
(-e:1)  return
(-e:1)  leave

The disassembler perl -MO=Bytecode,-S -e'sub foo {return return}; foo'
shows the two returns contain op_flags 4 (KIDS) and nothing else.

So I thought ck_return could check if the kid is also a return and warn 
then. ck_return is called twice, but it turns out that this op_return 
has no next and no sibling pointer at this stage.
So the new warning is never triggered.

diff -u op.c.orig op.c
--- op.c.orig   2008-06-17 11:25:08.000000000 +0000
+++ op.c        2008-06-24 16:00:28.437500000 +0000
@@ -7568,6 +7568,14 @@
          OP *kid;
         for (kid = cLISTOPo->op_first->op_sibling; kid; kid = 
kid->op_sibling)
             mod(kid, OP_LEAVESUBLV);
+    } else {
+        OP *kid;
+       kid = cLISTOPo->op_first->op_sibling;
+       if (kid->op_type == OP_RETURN) {
+           Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
+                       "Ignored return return");
+           mod(o->op_next, OP_NULL);
+       }
      }
      return o;
  }

Breakpoint 1, Perl_ck_return (my_perl=0x1871fd0, o=0x18728a8) at 
opmini.c:7565
7565        PERL_ARGS_ASSERT_CK_RETURN;
(gdb) p *o
$2 = {op_next = 0x0, op_sibling = 0x0, op_ppaddr = 0x5a8f19 
<Perl_pp_return>,
   op_madprop = 0x0, op_targ = 0, op_type = 190, op_opt = 0, op_latefree 
= 0,
   op_latefreed = 0, op_attached = 0, op_spare = 0, op_flags = 4 '\004',
   op_private = 0 '\0'}
(gdb) c

So it must be done in peep().
-- 
Reini Urban
http://phpwiki.org/  http://murbreak.at/

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About