summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/B/t/optree_misc.t66
-rw-r--r--op.c65
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;
diff --git a/op.c b/op.c
index fdb509420b..b4a845e7b2 100644
--- a/op.c
+++ b/op.c
@@ -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;
}