diff options
-rw-r--r-- | ext/B/t/optree_misc.t | 66 | ||||
-rw-r--r-- | op.c | 65 |
2 files changed, 117 insertions, 14 deletions
diff --git a/ext/B/t/optree_misc.t b/ext/B/t/optree_misc.t index 648539b508..f9886cd0c7 100644 --- a/ext/B/t/optree_misc.t +++ b/ext/B/t/optree_misc.t @@ -10,7 +10,7 @@ BEGIN { } use OptreeCheck; use Config; -plan tests => 14; +plan tests => 16; SKIP: { skip "no perlio in this build", 4 unless $Config::Config{useperlio}; @@ -367,4 +367,68 @@ EOT_EOT EONT_EONT +checkOptree ( name => 'consolidate padranges and singletons', + code => sub { my ($a,$b); my $c; my ($d,$e); + my @f; my $g; my ($h,$i); my %j; 1 }, + strip_open_hints => 1, + skip => ($] < 5.017006), + expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT'); +# 5 <1> leavesub[1 ref] K/REFC,1 ->(end) +# - <@> lineseq KP ->5 +# 1 <;> nextstate(main 903 optree_misc.t:371) v ->2 +# - <@> list vKP ->- +# 2 <0> padrange[$a:903,910; $b:903,910; $c:904,910; $d:905,910; $e:905,910; @f:906,910; $g:907,910; $h:908,910; $i:908,910; %j:909,910] vM/LVINTRO,10 ->3 +# - <0> padsv[$a:903,910] vM/LVINTRO ->- +# - <0> padsv[$b:903,910] vM/LVINTRO ->- +# - <;> nextstate(main 904 optree_misc.t:371) v ->- +# - <0> padsv[$c:904,910] vM/LVINTRO ->- +# - <;> nextstate(main 905 optree_misc.t:371) v:{ ->- +# - <@> list vKP ->- +# - <0> pushmark vM/LVINTRO ->- +# - <0> padsv[$d:905,910] vM/LVINTRO ->- +# - <0> padsv[$e:905,910] vM/LVINTRO ->- +# - <;> nextstate(main 906 optree_misc.t:372) v:{ ->- +# - <0> padav[@f:906,910] vM/LVINTRO ->- +# - <;> nextstate(main 907 optree_misc.t:372) v:{ ->- +# - <0> padsv[$g:907,910] vM/LVINTRO ->- +# - <;> nextstate(main 908 optree_misc.t:372) v:{ ->- +# - <@> list vKP ->- +# - <0> pushmark vM/LVINTRO ->- +# - <0> padsv[$h:908,910] vM/LVINTRO ->- +# - <0> padsv[$i:908,910] vM/LVINTRO ->- +# - <;> nextstate(main 909 optree_misc.t:372) v:{ ->- +# - <0> padhv[%j:909,910] vM/LVINTRO ->3 +# 3 <;> nextstate(main 910 optree_misc.t:372) v:{ ->4 +# 4 <$> const[IV 1] s ->5 +EOT_EOT +# 5 <1> leavesub[1 ref] K/REFC,1 ->(end) +# - <@> lineseq KP ->5 +# 1 <;> nextstate(main 903 optree_misc.t:371) v ->2 +# - <@> list vKP ->- +# 2 <0> padrange[$a:903,910; $b:903,910; $c:904,910; $d:905,910; $e:905,910; @f:906,910; $g:907,910; $h:908,910; $i:908,910; %j:909,910] vM/LVINTRO,10 ->3 +# - <0> padsv[$a:903,910] vM/LVINTRO ->- +# - <0> padsv[$b:903,910] vM/LVINTRO ->- +# - <;> nextstate(main 904 optree_misc.t:371) v ->- +# - <0> padsv[$c:904,910] vM/LVINTRO ->- +# - <;> nextstate(main 905 optree_misc.t:371) v:{ ->- +# - <@> list vKP ->- +# - <0> pushmark vM/LVINTRO ->- +# - <0> padsv[$d:905,910] vM/LVINTRO ->- +# - <0> padsv[$e:905,910] vM/LVINTRO ->- +# - <;> nextstate(main 906 optree_misc.t:372) v:{ ->- +# - <0> padav[@f:906,910] vM/LVINTRO ->- +# - <;> nextstate(main 907 optree_misc.t:372) v:{ ->- +# - <0> padsv[$g:907,910] vM/LVINTRO ->- +# - <;> nextstate(main 908 optree_misc.t:372) v:{ ->- +# - <@> list vKP ->- +# - <0> pushmark vM/LVINTRO ->- +# - <0> padsv[$h:908,910] vM/LVINTRO ->- +# - <0> padsv[$i:908,910] vM/LVINTRO ->- +# - <;> nextstate(main 909 optree_misc.t:372) v:{ ->- +# - <0> padhv[%j:909,910] vM/LVINTRO ->3 +# 3 <;> nextstate(main 910 optree_misc.t:372) v:{ ->4 +# 4 <$> const(IV 1) s ->5 +EONT_EONT + + unlink $tmpfile; @@ -10945,6 +10945,7 @@ Perl_rpeep(pTHX_ register OP *o) PADOFFSET base = 0; /* init only to stop compiler whining */ U8 gimme = 0; /* init only to stop compiler whining */ bool defav = 0; /* seen (...) = @_ */ + bool reuse = 0; /* reuse an existing padrange op */ /* look for a pushmark -> gv[_] -> rv2av */ @@ -11077,10 +11078,12 @@ Perl_rpeep(pTHX_ register OP *o) followop = followop->op_next; /* skip OP_LIST */ /* consolidate two successive my(...);'s */ + if ( oldoldop && oldoldop->op_type == OP_PADRANGE && (oldoldop->op_flags & OPf_WANT) == OPf_WANT_VOID && (oldoldop->op_private & OPpLVAL_INTRO) == intro + && !(oldoldop->op_flags & OPf_SPECIAL) ) { U8 old_count; assert(oldoldop->op_next == oldop); @@ -11093,26 +11096,62 @@ Perl_rpeep(pTHX_ register OP *o) assert(oldoldop->op_targ + old_count == base); if (old_count < OPpPADRANGE_COUNTMASK - count) { - oldoldop->op_private = (intro | (old_count+count)); - oldoldop->op_next = followop; - break; + base = oldoldop->op_targ; + count += old_count; + reuse = 1; } } + + /* if there's any immediately following singleton + * my var's; then swallow them and the associated + * nextstates; i.e. + * my ($a,$b); my $c; my $d; + * is treated as + * my ($a,$b,$c,$d); + */ + + while ( ((p = followop->op_next)) + && ( p->op_type == OP_PADSV + || p->op_type == OP_PADAV + || p->op_type == OP_PADHV) + && (p->op_flags & OPf_WANT) == OPf_WANT_VOID + && (p->op_private & OPpLVAL_INTRO) == intro + && p->op_next + && ( p->op_next->op_type == OP_NEXTSTATE + || p->op_next->op_type == OP_DBSTATE) + && count < OPpPADRANGE_COUNTMASK + ) { + assert(base + count == p->op_targ); + count++; + followop = p->op_next; + } } else break; } - /* Convert the pushmark into a padrange */ - o->op_next = followop; - o->op_type = OP_PADRANGE; - o->op_ppaddr = PL_ppaddr[OP_PADRANGE]; - o->op_targ = base; - /* bit 7: INTRO; bit 6..0: count */ - o->op_private = (intro | count); - o->op_flags = ((o->op_flags & ~(OPf_WANT|OPf_SPECIAL)) - | gimme | (defav ? OPf_SPECIAL : 0)); - + if (reuse) { + assert(oldoldop->op_type == OP_PADRANGE); + oldoldop->op_next = followop; + oldoldop->op_private = (intro | count); + o = oldoldop; + oldop = NULL; + oldoldop = NULL; + } + else { + /* Convert the pushmark into a padrange. + * To make Deparse easier, we guarantee that a padrange was + * *always* formerly a pushmark */ + assert(o->op_type == OP_PUSHMARK); + o->op_next = followop; + o->op_type = OP_PADRANGE; + o->op_ppaddr = PL_ppaddr[OP_PADRANGE]; + o->op_targ = base; + /* bit 7: INTRO; bit 6..0: count */ + o->op_private = (intro | count); + o->op_flags = ((o->op_flags & ~(OPf_WANT|OPf_SPECIAL)) + | gimme | (defav ? OPf_SPECIAL : 0)); + } break; } |