diff options
author | Nicholas Clark <nick@ccl4.org> | 2010-08-27 21:48:55 +0100 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2010-08-27 21:48:55 +0100 |
commit | ac56e7de46621c6f2e373d11984c0a0fe4839b0b (patch) | |
tree | bb3bb0453fad0152bd4b0aaf97989c0c21cb192f /op.c | |
parent | ccfef76d964c8b719db5c7fd06ce897a3eb64c01 (diff) | |
download | perl-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.)
Diffstat (limited to 'op.c')
-rw-r--r-- | op.c | 54 |
1 files changed, 53 insertions, 1 deletions
@@ -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) |