summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2010-08-27 21:48:55 +0100
committerNicholas Clark <nick@ccl4.org>2010-08-27 21:48:55 +0100
commitac56e7de46621c6f2e373d11984c0a0fe4839b0b (patch)
treebb3bb0453fad0152bd4b0aaf97989c0c21cb192f
parentccfef76d964c8b719db5c7fd06ce897a3eb64c01 (diff)
downloadperl-ac56e7de46621c6f2e373d11984c0a0fe4839b0b.tar.gz
Peephole optimise adjacent pairs of nextstate ops.
Previously, in code such as use constant DEBUG=>0; sub GAK { warn if DEBUG; print "stuff\n"; } the ops for C<warn if DEBUG;> would be folded to a null op (ex-const), but the nextstate op would remain, resulting in a runtime op dispatch of nextstate, nextstate, ... The execution of a sequence of nexstate ops is indistinguishable from just the last nextstate op, so teach the peephole optimiser to eliminate the first of a pair of nextstate ops. (Except where the first carries a label, as labels mustn't be eliminated by the optimiser, and label usage isn't conclusively known at compile time.)
-rw-r--r--ext/B/t/optree_samples.t158
-rw-r--r--ext/B/t/optree_specials.t452
-rw-r--r--op.c54
-rw-r--r--t/op/goto.t8
4 files changed, 358 insertions, 314 deletions
diff --git a/ext/B/t/optree_samples.t b/ext/B/t/optree_samples.t
index 6003ab2a3c..2a789727ba 100644
--- a/ext/B/t/optree_samples.t
+++ b/ext/B/t/optree_samples.t
@@ -278,57 +278,57 @@ checkOptree ( name => '-basic sub { print "foo $_" foreach (1..10) }',
bcopts => '-basic',
strip_open_hints => 1,
expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
-# h <1> leavesub[1 ref] K/REFC,1 ->(end)
-# - <@> lineseq KP ->h
+# g <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->g
# 1 <;> nextstate(main 445 optree.t:167) v:>,<,% ->2
-# 2 <;> nextstate(main 445 optree.t:167) v:>,<,% ->3
-# g <2> leaveloop K/2 ->h
-# 7 <{> enteriter(next->d last->g redo->8) lKS/8 ->e
-# - <0> ex-pushmark s ->3
-# - <1> ex-list lK ->6
-# 3 <0> pushmark s ->4
-# 4 <$> const[IV 1] s ->5
-# 5 <$> const[IV 10] s ->6
-# 6 <#> gv[*_] s ->7
-# - <1> null K/1 ->g
-# f <|> and(other->8) K/1 ->g
-# e <0> iter s ->f
+# - <0> null v ->-
+# f <2> leaveloop K/2 ->g
+# 6 <{> enteriter(next->c last->f redo->7) lKS/8 ->d
+# - <0> ex-pushmark s ->2
+# - <1> ex-list lK ->5
+# 2 <0> pushmark s ->3
+# 3 <$> const[IV 1] s ->4
+# 4 <$> const[IV 10] s ->5
+# 5 <#> gv[*_] s ->6
+# - <1> null K/1 ->f
+# e <|> and(other->7) K/1 ->f
+# d <0> iter s ->e
# - <@> lineseq sK ->-
-# c <@> print vK ->d
-# 8 <0> pushmark s ->9
-# - <1> ex-stringify sK/1 ->c
-# - <0> ex-pushmark s ->9
-# b <2> concat[t2] sK/2 ->c
-# 9 <$> const[PV "foo "] s ->a
-# - <1> ex-rv2sv sK/1 ->b
-# a <#> gvsv[*_] s ->b
-# d <0> unstack s ->e
+# b <@> print vK ->c
+# 7 <0> pushmark s ->8
+# - <1> ex-stringify sK/1 ->b
+# - <0> ex-pushmark s ->8
+# a <2> concat[t2] sK/2 ->b
+# 8 <$> const[PV "foo "] s ->9
+# - <1> ex-rv2sv sK/1 ->a
+# 9 <#> gvsv[*_] s ->a
+# c <0> unstack s ->d
EOT_EOT
-# h <1> leavesub[1 ref] K/REFC,1 ->(end)
-# - <@> lineseq KP ->h
+# g <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->g
# 1 <;> nextstate(main 446 optree_samples.t:192) v:>,<,% ->2
-# 2 <;> nextstate(main 446 optree_samples.t:192) v:>,<,% ->3
-# g <2> leaveloop K/2 ->h
-# 7 <{> enteriter(next->d last->g redo->8) lKS/8 ->e
-# - <0> ex-pushmark s ->3
-# - <1> ex-list lK ->6
-# 3 <0> pushmark s ->4
-# 4 <$> const(IV 1) s ->5
-# 5 <$> const(IV 10) s ->6
-# 6 <$> gv(*_) s ->7
-# - <1> null K/1 ->g
-# f <|> and(other->8) K/1 ->g
-# e <0> iter s ->f
+# - <0> null v ->-
+# f <2> leaveloop K/2 ->g
+# 6 <{> enteriter(next->c last->f redo->7) lKS/8 ->d
+# - <0> ex-pushmark s ->2
+# - <1> ex-list lK ->5
+# 2 <0> pushmark s ->3
+# 3 <$> const(IV 1) s ->4
+# 4 <$> const(IV 10) s ->5
+# 5 <$> gv(*_) s ->6
+# - <1> null K/1 ->f
+# e <|> and(other->7) K/1 ->f
+# d <0> iter s ->e
# - <@> lineseq sK ->-
-# c <@> print vK ->d
-# 8 <0> pushmark s ->9
-# - <1> ex-stringify sK/1 ->c
-# - <0> ex-pushmark s ->9
-# b <2> concat[t1] sK/2 ->c
-# 9 <$> const(PV "foo ") s ->a
-# - <1> ex-rv2sv sK/1 ->b
-# a <$> gvsv(*_) s ->b
-# d <0> unstack s ->e
+# b <@> print vK ->c
+# 7 <0> pushmark s ->8
+# - <1> ex-stringify sK/1 ->b
+# - <0> ex-pushmark s ->8
+# a <2> concat[t1] sK/2 ->b
+# 8 <$> const(PV "foo ") s ->9
+# - <1> ex-rv2sv sK/1 ->a
+# 9 <$> gvsv(*_) s ->a
+# c <0> unstack s ->d
EONT_EONT
checkOptree ( name => '-exec -e foreach (1..10) {print qq{foo $_}}',
@@ -383,42 +383,40 @@ checkOptree ( name => '-exec sub { print "foo $_" foreach (1..10) }',
strip_open_hints => 1,
expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
# 1 <;> nextstate(main 445 optree.t:167) v:>,<,%
-# 2 <;> nextstate(main 445 optree.t:167) v:>,<,%
-# 3 <0> pushmark s
-# 4 <$> const[IV 1] s
-# 5 <$> const[IV 10] s
-# 6 <#> gv[*_] s
-# 7 <{> enteriter(next->d last->g redo->8) lKS/8
-# e <0> iter s
-# f <|> and(other->8) K/1
-# 8 <0> pushmark s
-# 9 <$> const[PV "foo "] s
-# a <#> gvsv[*_] s
-# b <2> concat[t2] sK/2
-# c <@> print vK
-# d <0> unstack s
-# goto e
-# g <2> leaveloop K/2
-# h <1> leavesub[1 ref] K/REFC,1
+# 2 <0> pushmark s
+# 3 <$> const[IV 1] s
+# 4 <$> const[IV 10] s
+# 5 <#> gv[*_] s
+# 6 <{> enteriter(next->c last->f redo->7) lKS/8
+# d <0> iter s
+# e <|> and(other->7) K/1
+# 7 <0> pushmark s
+# 8 <$> const[PV "foo "] s
+# 9 <#> gvsv[*_] s
+# a <2> concat[t2] sK/2
+# b <@> print vK
+# c <0> unstack s
+# goto d
+# f <2> leaveloop K/2
+# g <1> leavesub[1 ref] K/REFC,1
EOT_EOT
# 1 <;> nextstate(main 447 optree_samples.t:252) v:>,<,%
-# 2 <;> nextstate(main 447 optree_samples.t:252) v:>,<,%
-# 3 <0> pushmark s
-# 4 <$> const(IV 1) s
-# 5 <$> const(IV 10) s
-# 6 <$> gv(*_) s
-# 7 <{> enteriter(next->d last->g redo->8) lKS/8
-# e <0> iter s
-# f <|> and(other->8) K/1
-# 8 <0> pushmark s
-# 9 <$> const(PV "foo ") s
-# a <$> gvsv(*_) s
-# b <2> concat[t1] sK/2
-# c <@> print vK
-# d <0> unstack s
-# goto e
-# g <2> leaveloop K/2
-# h <1> leavesub[1 ref] K/REFC,1
+# 2 <0> pushmark s
+# 3 <$> const(IV 1) s
+# 4 <$> const(IV 10) s
+# 5 <$> gv(*_) s
+# 6 <{> enteriter(next->c last->f redo->7) lKS/8
+# d <0> iter s
+# e <|> and(other->7) K/1
+# 7 <0> pushmark s
+# 8 <$> const(PV "foo ") s
+# 9 <$> gvsv(*_) s
+# a <2> concat[t1] sK/2
+# b <@> print vK
+# c <0> unstack s
+# goto d
+# f <2> leaveloop K/2
+# g <1> leavesub[1 ref] K/REFC,1
EONT_EONT
pass("GREP: SAMPLES FROM PERLDOC -F GREP");
diff --git a/ext/B/t/optree_specials.t b/ext/B/t/optree_specials.t
index 1f813230af..25f7335867 100644
--- a/ext/B/t/optree_specials.t
+++ b/ext/B/t/optree_specials.t
@@ -48,104 +48,104 @@ checkOptree ( name => 'BEGIN',
strip_open_hints => 1,
expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
# BEGIN 1:
-# b <1> leavesub[1 ref] K/REFC,1 ->(end)
-# - <@> lineseq KP ->b
+# a <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->a
# 1 <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$ ->2
# 3 <1> require sK/1 ->4
# 2 <$> const[PV "strict.pm"] s/BARE ->3
# 4 <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$ ->5
# - <@> lineseq K ->-
-# 5 <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$ ->6
-# a <1> entersub[t1] KS*/TARG,2 ->b
-# 6 <0> pushmark s ->7
-# 7 <$> const[PV "strict"] sM ->8
-# 8 <$> const[PV "refs"] sM ->9
-# 9 <$> method_named[PV "unimport"] ->a
+# - <0> null ->5
+# 9 <1> entersub[t1] KS*/TARG,2 ->a
+# 5 <0> pushmark s ->6
+# 6 <$> const[PV "strict"] sM ->7
+# 7 <$> const[PV "refs"] sM ->8
+# 8 <$> method_named[PV "unimport"] ->9
# BEGIN 2:
-# m <1> leavesub[1 ref] K/REFC,1 ->(end)
-# - <@> lineseq K ->m
-# c <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->d
-# e <1> require sK/1 ->f
-# d <$> const[PV "strict.pm"] s/BARE ->e
-# f <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->g
+# k <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq K ->k
+# b <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->c
+# d <1> require sK/1 ->e
+# c <$> const[PV "strict.pm"] s/BARE ->d
+# e <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->f
# - <@> lineseq K ->-
-# g <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$ ->h
-# l <1> entersub[t1] KS*/TARG,2 ->m
-# h <0> pushmark s ->i
-# i <$> const[PV "strict"] sM ->j
-# j <$> const[PV "refs"] sM ->k
-# k <$> method_named[PV "unimport"] ->l
+# - <0> null ->f
+# j <1> entersub[t1] KS*/TARG,2 ->k
+# f <0> pushmark s ->g
+# g <$> const[PV "strict"] sM ->h
+# h <$> const[PV "refs"] sM ->i
+# i <$> method_named[PV "unimport"] ->j
# BEGIN 3:
-# x <1> leavesub[1 ref] K/REFC,1 ->(end)
-# - <@> lineseq KP ->x
-# n <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->o
-# p <1> require sK/1 ->q
-# o <$> const[PV "warnings.pm"] s/BARE ->p
-# q <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->r
+# u <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->u
+# l <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->m
+# n <1> require sK/1 ->o
+# m <$> const[PV "warnings.pm"] s/BARE ->n
+# o <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->p
# - <@> lineseq K ->-
-# r <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$ ->s
-# w <1> entersub[t1] KS*/TARG,2 ->x
-# s <0> pushmark s ->t
-# t <$> const[PV "warnings"] sM ->u
-# u <$> const[PV "qw"] sM ->v
-# v <$> method_named[PV "unimport"] ->w
+# - <0> null ->p
+# t <1> entersub[t1] KS*/TARG,2 ->u
+# p <0> pushmark s ->q
+# q <$> const[PV "warnings"] sM ->r
+# r <$> const[PV "qw"] sM ->s
+# s <$> method_named[PV "unimport"] ->t
# BEGIN 4:
-# 11 <1> leavesub[1 ref] K/REFC,1 ->(end)
-# - <@> lineseq KP ->11
-# y <;> nextstate(main 2 -e:1) v:>,<,%,{ ->z
-# 10 <1> postinc[t3] sK/1 ->11
-# - <1> ex-rv2sv sKRM/1 ->10
-# z <#> gvsv[*beg] s ->10
+# y <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->y
+# v <;> nextstate(main 2 -e:1) v:>,<,%,{ ->w
+# x <1> postinc[t3] sK/1 ->y
+# - <1> ex-rv2sv sKRM/1 ->x
+# w <#> gvsv[*beg] s ->x
EOT_EOT
# BEGIN 1:
-# b <1> leavesub[1 ref] K/REFC,1 ->(end)
-# - <@> lineseq KP ->b
+# a <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->a
# 1 <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$ ->2
# 3 <1> require sK/1 ->4
# 2 <$> const(PV "strict.pm") s/BARE ->3
# 4 <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$ ->5
# - <@> lineseq K ->-
-# 5 <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$ ->6
-# a <1> entersub[t1] KS*/TARG,2 ->b
-# 6 <0> pushmark s ->7
-# 7 <$> const(PV "strict") sM ->8
-# 8 <$> const(PV "refs") sM ->9
-# 9 <$> method_named(PV "unimport") ->a
+# - <0> null ->5
+# 9 <1> entersub[t1] KS*/TARG,2 ->a
+# 5 <0> pushmark s ->6
+# 6 <$> const(PV "strict") sM ->7
+# 7 <$> const(PV "refs") sM ->8
+# 8 <$> method_named(PV "unimport") ->9
# BEGIN 2:
-# m <1> leavesub[1 ref] K/REFC,1 ->(end)
-# - <@> lineseq K ->m
-# c <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->d
-# e <1> require sK/1 ->f
-# d <$> const(PV "strict.pm") s/BARE ->e
-# f <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->g
+# k <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq K ->k
+# b <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->c
+# d <1> require sK/1 ->e
+# c <$> const(PV "strict.pm") s/BARE ->d
+# e <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->f
# - <@> lineseq K ->-
-# g <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$ ->h
-# l <1> entersub[t1] KS*/TARG,2 ->m
-# h <0> pushmark s ->i
-# i <$> const(PV "strict") sM ->j
-# j <$> const(PV "refs") sM ->k
-# k <$> method_named(PV "unimport") ->l
+# - <0> null ->f
+# j <1> entersub[t1] KS*/TARG,2 ->k
+# f <0> pushmark s ->g
+# g <$> const(PV "strict") sM ->h
+# h <$> const(PV "refs") sM ->i
+# i <$> method_named(PV "unimport") ->j
# BEGIN 3:
-# x <1> leavesub[1 ref] K/REFC,1 ->(end)
-# - <@> lineseq KP ->x
-# n <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->o
-# p <1> require sK/1 ->q
-# o <$> const(PV "warnings.pm") s/BARE ->p
-# q <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->r
+# u <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->u
+# l <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->m
+# n <1> require sK/1 ->o
+# m <$> const(PV "warnings.pm") s/BARE ->n
+# o <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->p
# - <@> lineseq K ->-
-# r <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$ ->s
-# w <1> entersub[t1] KS*/TARG,2 ->x
-# s <0> pushmark s ->t
-# t <$> const(PV "warnings") sM ->u
-# u <$> const(PV "qw") sM ->v
-# v <$> method_named(PV "unimport") ->w
+# - <0> null ->p
+# t <1> entersub[t1] KS*/TARG,2 ->u
+# p <0> pushmark s ->q
+# q <$> const(PV "warnings") sM ->r
+# r <$> const(PV "qw") sM ->s
+# s <$> method_named(PV "unimport") ->t
# BEGIN 4:
-# 11 <1> leavesub[1 ref] K/REFC,1 ->(end)
-# - <@> lineseq KP ->11
-# y <;> nextstate(main 2 -e:1) v:>,<,%,{ ->z
-# 10 <1> postinc[t2] sK/1 ->11
-# - <1> ex-rv2sv sKRM/1 ->10
-# z <$> gvsv(*beg) s ->10
+# y <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->y
+# v <;> nextstate(main 2 -e:1) v:>,<,%,{ ->w
+# x <1> postinc[t2] sK/1 ->y
+# - <1> ex-rv2sv sKRM/1 ->x
+# w <$> gvsv(*beg) s ->x
EONT_EONT
@@ -253,124 +253,118 @@ checkOptree ( name => 'all of BEGIN END INIT CHECK UNITCHECK -exec',
# 2 <$> const[PV "strict.pm"] s/BARE
# 3 <1> require sK/1
# 4 <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
-# 5 <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$
-# 6 <0> pushmark s
-# 7 <$> const[PV "strict"] sM
-# 8 <$> const[PV "refs"] sM
-# 9 <$> method_named[PV "unimport"]
-# a <1> entersub[t1] KS*/TARG,2
-# b <1> leavesub[1 ref] K/REFC,1
+# 5 <0> pushmark s
+# 6 <$> const[PV "strict"] sM
+# 7 <$> const[PV "refs"] sM
+# 8 <$> method_named[PV "unimport"]
+# 9 <1> entersub[t1] KS*/TARG,2
+# a <1> leavesub[1 ref] K/REFC,1
# BEGIN 2:
-# c <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# d <$> const[PV "strict.pm"] s/BARE
-# e <1> require sK/1
-# f <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# g <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$
-# h <0> pushmark s
-# i <$> const[PV "strict"] sM
-# j <$> const[PV "refs"] sM
-# k <$> method_named[PV "unimport"]
-# l <1> entersub[t1] KS*/TARG,2
-# m <1> leavesub[1 ref] K/REFC,1
+# b <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# c <$> const[PV "strict.pm"] s/BARE
+# d <1> require sK/1
+# e <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# f <0> pushmark s
+# g <$> const[PV "strict"] sM
+# h <$> const[PV "refs"] sM
+# i <$> method_named[PV "unimport"]
+# j <1> entersub[t1] KS*/TARG,2
+# k <1> leavesub[1 ref] K/REFC,1
# BEGIN 3:
-# n <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# o <$> const[PV "warnings.pm"] s/BARE
-# p <1> require sK/1
-# q <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# r <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$
-# s <0> pushmark s
-# t <$> const[PV "warnings"] sM
-# u <$> const[PV "qw"] sM
-# v <$> method_named[PV "unimport"]
-# w <1> entersub[t1] KS*/TARG,2
-# x <1> leavesub[1 ref] K/REFC,1
+# l <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# m <$> const[PV "warnings.pm"] s/BARE
+# n <1> require sK/1
+# o <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# p <0> pushmark s
+# q <$> const[PV "warnings"] sM
+# r <$> const[PV "qw"] sM
+# s <$> method_named[PV "unimport"]
+# t <1> entersub[t1] KS*/TARG,2
+# u <1> leavesub[1 ref] K/REFC,1
# BEGIN 4:
-# y <;> nextstate(main 2 -e:1) v:>,<,%,{
-# z <#> gvsv[*beg] s
-# 10 <1> postinc[t3] sK/1
-# 11 <1> leavesub[1 ref] K/REFC,1
+# v <;> nextstate(main 2 -e:1) v:>,<,%,{
+# w <#> gvsv[*beg] s
+# x <1> postinc[t3] sK/1
+# y <1> leavesub[1 ref] K/REFC,1
# END 1:
-# 12 <;> nextstate(main 5 -e:1) v:>,<,%,{
-# 13 <#> gvsv[*end] s
-# 14 <1> postinc[t3] sK/1
-# 15 <1> leavesub[1 ref] K/REFC,1
+# z <;> nextstate(main 5 -e:1) v:>,<,%,{
+# 10 <#> gvsv[*end] s
+# 11 <1> postinc[t3] sK/1
+# 12 <1> leavesub[1 ref] K/REFC,1
# INIT 1:
-# 16 <;> nextstate(main 4 -e:1) v:>,<,%,{
-# 17 <#> gvsv[*init] s
-# 18 <1> postinc[t3] sK/1
-# 19 <1> leavesub[1 ref] K/REFC,1
+# 13 <;> nextstate(main 4 -e:1) v:>,<,%,{
+# 14 <#> gvsv[*init] s
+# 15 <1> postinc[t3] sK/1
+# 16 <1> leavesub[1 ref] K/REFC,1
# CHECK 1:
-# 1a <;> nextstate(main 3 -e:1) v:>,<,%,{
-# 1b <#> gvsv[*chk] s
-# 1c <1> postinc[t3] sK/1
-# 1d <1> leavesub[1 ref] K/REFC,1
+# 17 <;> nextstate(main 3 -e:1) v:>,<,%,{
+# 18 <#> gvsv[*chk] s
+# 19 <1> postinc[t3] sK/1
+# 1a <1> leavesub[1 ref] K/REFC,1
# UNITCHECK 1:
-# 1e <;> nextstate(main 6 -e:1) v:>,<,%,{
-# 1f <#> gvsv[*uc] s
-# 1g <1> postinc[t3] sK/1
-# 1h <1> leavesub[1 ref] K/REFC,1
+# 1b <;> nextstate(main 6 -e:1) v:>,<,%,{
+# 1c <#> gvsv[*uc] s
+# 1d <1> postinc[t3] sK/1
+# 1e <1> leavesub[1 ref] K/REFC,1
EOT_EOT
# BEGIN 1:
# 1 <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
# 2 <$> const(PV "strict.pm") s/BARE
# 3 <1> require sK/1
# 4 <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
-# 5 <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$
-# 6 <0> pushmark s
-# 7 <$> const(PV "strict") sM
-# 8 <$> const(PV "refs") sM
-# 9 <$> method_named(PV "unimport")
-# a <1> entersub[t1] KS*/TARG,2
-# b <1> leavesub[1 ref] K/REFC,1
+# 5 <0> pushmark s
+# 6 <$> const(PV "strict") sM
+# 7 <$> const(PV "refs") sM
+# 8 <$> method_named(PV "unimport")
+# 9 <1> entersub[t1] KS*/TARG,2
+# a <1> leavesub[1 ref] K/REFC,1
# BEGIN 2:
-# c <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# d <$> const(PV "strict.pm") s/BARE
-# e <1> require sK/1
-# f <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# g <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$
-# h <0> pushmark s
-# i <$> const(PV "strict") sM
-# j <$> const(PV "refs") sM
-# k <$> method_named(PV "unimport")
-# l <1> entersub[t1] KS*/TARG,2
-# m <1> leavesub[1 ref] K/REFC,1
+# b <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# c <$> const(PV "strict.pm") s/BARE
+# d <1> require sK/1
+# e <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# f <0> pushmark s
+# g <$> const(PV "strict") sM
+# h <$> const(PV "refs") sM
+# i <$> method_named(PV "unimport")
+# j <1> entersub[t1] KS*/TARG,2
+# k <1> leavesub[1 ref] K/REFC,1
# BEGIN 3:
-# n <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# o <$> const(PV "warnings.pm") s/BARE
-# p <1> require sK/1
-# q <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# r <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$
-# s <0> pushmark s
-# t <$> const(PV "warnings") sM
-# u <$> const(PV "qw") sM
-# v <$> method_named(PV "unimport")
-# w <1> entersub[t1] KS*/TARG,2
-# x <1> leavesub[1 ref] K/REFC,1
+# l <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# m <$> const(PV "warnings.pm") s/BARE
+# n <1> require sK/1
+# o <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# p <0> pushmark s
+# q <$> const(PV "warnings") sM
+# r <$> const(PV "qw") sM
+# s <$> method_named(PV "unimport")
+# t <1> entersub[t1] KS*/TARG,2
+# u <1> leavesub[1 ref] K/REFC,1
# BEGIN 4:
-# y <;> nextstate(main 2 -e:1) v:>,<,%,{
-# z <$> gvsv(*beg) s
-# 10 <1> postinc[t2] sK/1
-# 11 <1> leavesub[1 ref] K/REFC,1
+# v <;> nextstate(main 2 -e:1) v:>,<,%,{
+# w <$> gvsv(*beg) s
+# x <1> postinc[t2] sK/1
+# y <1> leavesub[1 ref] K/REFC,1
# END 1:
-# 12 <;> nextstate(main 5 -e:1) v:>,<,%,{
-# 13 <$> gvsv(*end) s
-# 14 <1> postinc[t2] sK/1
-# 15 <1> leavesub[1 ref] K/REFC,1
+# z <;> nextstate(main 5 -e:1) v:>,<,%,{
+# 10 <$> gvsv(*end) s
+# 11 <1> postinc[t2] sK/1
+# 12 <1> leavesub[1 ref] K/REFC,1
# INIT 1:
-# 16 <;> nextstate(main 4 -e:1) v:>,<,%,{
-# 17 <$> gvsv(*init) s
-# 18 <1> postinc[t2] sK/1
-# 19 <1> leavesub[1 ref] K/REFC,1
+# 13 <;> nextstate(main 4 -e:1) v:>,<,%,{
+# 14 <$> gvsv(*init) s
+# 15 <1> postinc[t2] sK/1
+# 16 <1> leavesub[1 ref] K/REFC,1
# CHECK 1:
-# 1a <;> nextstate(main 3 -e:1) v:>,<,%,{
-# 1b <$> gvsv(*chk) s
-# 1c <1> postinc[t2] sK/1
-# 1d <1> leavesub[1 ref] K/REFC,1
+# 17 <;> nextstate(main 3 -e:1) v:>,<,%,{
+# 18 <$> gvsv(*chk) s
+# 19 <1> postinc[t2] sK/1
+# 1a <1> leavesub[1 ref] K/REFC,1
# UNITCHECK 1:
-# 1e <;> nextstate(main 6 -e:1) v:>,<,%,{
-# 1f <$> gvsv(*uc) s
-# 1g <1> postinc[t2] sK/1
-# 1h <1> leavesub[1 ref] K/REFC,1
+# 1b <;> nextstate(main 6 -e:1) v:>,<,%,{
+# 1c <$> gvsv(*uc) s
+# 1d <1> postinc[t2] sK/1
+# 1e <1> leavesub[1 ref] K/REFC,1
EONT_EONT
@@ -388,72 +382,66 @@ checkOptree ( name => 'regression test for patch 25352',
# 2 <$> const[PV "strict.pm"] s/BARE
# 3 <1> require sK/1
# 4 <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
-# 5 <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$
-# 6 <0> pushmark s
-# 7 <$> const[PV "strict"] sM
-# 8 <$> const[PV "refs"] sM
-# 9 <$> method_named[PV "unimport"]
-# a <1> entersub[t1] KS*/TARG,2
-# b <1> leavesub[1 ref] K/REFC,1
+# 5 <0> pushmark s
+# 6 <$> const[PV "strict"] sM
+# 7 <$> const[PV "refs"] sM
+# 8 <$> method_named[PV "unimport"]
+# 9 <1> entersub[t1] KS*/TARG,2
+# a <1> leavesub[1 ref] K/REFC,1
# BEGIN 2:
-# c <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# d <$> const[PV "strict.pm"] s/BARE
-# e <1> require sK/1
-# f <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# g <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$
-# h <0> pushmark s
-# i <$> const[PV "strict"] sM
-# j <$> const[PV "refs"] sM
-# k <$> method_named[PV "unimport"]
-# l <1> entersub[t1] KS*/TARG,2
-# m <1> leavesub[1 ref] K/REFC,1
+# b <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# c <$> const[PV "strict.pm"] s/BARE
+# d <1> require sK/1
+# e <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# f <0> pushmark s
+# g <$> const[PV "strict"] sM
+# h <$> const[PV "refs"] sM
+# i <$> method_named[PV "unimport"]
+# j <1> entersub[t1] KS*/TARG,2
+# k <1> leavesub[1 ref] K/REFC,1
# BEGIN 3:
-# n <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# o <$> const[PV "warnings.pm"] s/BARE
-# p <1> require sK/1
-# q <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# r <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$
-# s <0> pushmark s
-# t <$> const[PV "warnings"] sM
-# u <$> const[PV "qw"] sM
-# v <$> method_named[PV "unimport"]
-# w <1> entersub[t1] KS*/TARG,2
-# x <1> leavesub[1 ref] K/REFC,1
+# l <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# m <$> const[PV "warnings.pm"] s/BARE
+# n <1> require sK/1
+# o <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# p <0> pushmark s
+# q <$> const[PV "warnings"] sM
+# r <$> const[PV "qw"] sM
+# s <$> method_named[PV "unimport"]
+# t <1> entersub[t1] KS*/TARG,2
+# u <1> leavesub[1 ref] K/REFC,1
EOT_EOT
# BEGIN 1:
# 1 <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
# 2 <$> const(PV "strict.pm") s/BARE
# 3 <1> require sK/1
# 4 <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
-# 5 <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$
-# 6 <0> pushmark s
-# 7 <$> const(PV "strict") sM
-# 8 <$> const(PV "refs") sM
-# 9 <$> method_named(PV "unimport")
-# a <1> entersub[t1] KS*/TARG,2
-# b <1> leavesub[1 ref] K/REFC,1
+# 5 <0> pushmark s
+# 6 <$> const(PV "strict") sM
+# 7 <$> const(PV "refs") sM
+# 8 <$> method_named(PV "unimport")
+# 9 <1> entersub[t1] KS*/TARG,2
+# a <1> leavesub[1 ref] K/REFC,1
# BEGIN 2:
-# c <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# d <$> const(PV "strict.pm") s/BARE
-# e <1> require sK/1
-# f <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# g <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$
-# h <0> pushmark s
-# i <$> const(PV "strict") sM
-# j <$> const(PV "refs") sM
-# k <$> method_named(PV "unimport")
-# l <1> entersub[t1] KS*/TARG,2
-# m <1> leavesub[1 ref] K/REFC,1
+# b <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# c <$> const(PV "strict.pm") s/BARE
+# d <1> require sK/1
+# e <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# f <0> pushmark s
+# g <$> const(PV "strict") sM
+# h <$> const(PV "refs") sM
+# i <$> method_named(PV "unimport")
+# j <1> entersub[t1] KS*/TARG,2
+# k <1> leavesub[1 ref] K/REFC,1
# BEGIN 3:
-# n <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# o <$> const(PV "warnings.pm") s/BARE
-# p <1> require sK/1
-# q <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# r <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$
-# s <0> pushmark s
-# t <$> const(PV "warnings") sM
-# u <$> const(PV "qw") sM
-# v <$> method_named(PV "unimport")
-# w <1> entersub[t1] KS*/TARG,2
-# x <1> leavesub[1 ref] K/REFC,1
+# l <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# m <$> const(PV "warnings.pm") s/BARE
+# n <1> require sK/1
+# o <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# p <0> pushmark s
+# q <$> const(PV "warnings") sM
+# r <$> const(PV "qw") sM
+# s <$> method_named(PV "unimport")
+# t <1> entersub[t1] KS*/TARG,2
+# u <1> leavesub[1 ref] K/REFC,1
EONT_EONT
diff --git a/op.c b/op.c
index 3699674118..433faceae1 100644
--- a/op.c
+++ b/op.c
@@ -8862,10 +8862,62 @@ Perl_rpeep(pTHX_ register OP *o)
o->op_opt = 1;
PL_op = o;
switch (o->op_type) {
- case OP_NEXTSTATE:
case OP_DBSTATE:
PL_curcop = ((COP*)o); /* for warnings */
break;
+ case OP_NEXTSTATE:
+ PL_curcop = ((COP*)o); /* for warnings */
+
+ /* Two NEXTSTATEs in a row serve no purpose. Except if they happen
+ to carry two labels. For now, take the easier option, and skip
+ this optimisation if the first NEXTSTATE has a label. */
+ if (!CopLABEL((COP*)o)) {
+ OP *nextop = o->op_next;
+ while (nextop && nextop->op_type == OP_NULL)
+ nextop = nextop->op_next;
+
+ if (nextop && (nextop->op_type == OP_NEXTSTATE)) {
+ COP *firstcop = (COP *)o;
+ COP *secondcop = (COP *)nextop;
+ /* We want the COP pointed to by o (and anything else) to
+ become the next COP down the line. */
+ cop_free(firstcop);
+
+ firstcop->op_next = secondcop->op_next;
+
+ /* Now steal all its pointers, and duplicate the other
+ data. */
+ firstcop->cop_line = secondcop->cop_line;
+#ifdef USE_ITHREADS
+ firstcop->cop_stashpv = secondcop->cop_stashpv;
+ firstcop->cop_file = secondcop->cop_file;
+#else
+ firstcop->cop_stash = secondcop->cop_stash;
+ firstcop->cop_filegv = secondcop->cop_filegv;
+#endif
+ firstcop->cop_hints = secondcop->cop_hints;
+ firstcop->cop_seq = secondcop->cop_seq;
+ firstcop->cop_warnings = secondcop->cop_warnings;
+ firstcop->cop_hints_hash = secondcop->cop_hints_hash;
+
+#ifdef USE_ITHREADS
+ secondcop->cop_stashpv = NULL;
+ secondcop->cop_file = NULL;
+#else
+ secondcop->cop_stash = NULL;
+ secondcop->cop_filegv = NULL;
+#endif
+ secondcop->cop_warnings = NULL;
+ secondcop->cop_hints_hash = NULL;
+
+ /* If we use op_null(), and hence leave an ex-COP, some
+ warnings are misreported. For example, the compile-time
+ error in 'use strict; no strict refs;' */
+ secondcop->op_type = OP_NULL;
+ secondcop->op_ppaddr = PL_ppaddr[OP_NULL];
+ }
+ }
+ break;
case OP_CONST:
if (cSVOPo->op_private & OPpCONST_STRICT)
diff --git a/t/op/goto.t b/t/op/goto.t
index 0a8aeeecbb..a98e35496d 100644
--- a/t/op/goto.t
+++ b/t/op/goto.t
@@ -10,7 +10,7 @@ BEGIN {
use warnings;
use strict;
-plan tests => 67;
+plan tests => 68;
our $TODO;
my $deprecated = 0;
@@ -483,3 +483,9 @@ is($deprecated, 0);
is($x, 10,
'labels outside evals can be distinguished from the start of the eval');
}
+
+goto wham_eth;
+die "You can't get here";
+
+wham_eth: 1 if 0;
+ouch_eth: pass('labels persist even if their statement is optimised away');