summaryrefslogtreecommitdiff
path: root/op.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2014-03-05 19:42:36 +0000
committerDavid Mitchell <davem@iabyn.com>2014-03-16 18:34:37 +0000
commite42737055d5d2ce05a8416a08c424c0d246ba839 (patch)
tree88ea299fbb587133fbe3296ce3459fa01915e95d /op.c
parent1022336546c7c8280b26bac6ed9c55bfd217804f (diff)
downloadperl-e42737055d5d2ce05a8416a08c424c0d246ba839.tar.gz
rpeep(): elide just-nulled ops
Perl_rpeep() currently spots "empty" ops like OP_NULL, OP_SCOPE and elides them from the op_next chain (by setting oldop->op_next to point to the op following the current op). However, if rpeep() itself op_null()'s the current op, then when the main loop is re-entered, that mechanism is bypassed. Modify re-entry to the loop in this case so that the just nulled op re-processed and thus elided. (Also document what the OP_SASSIGN/OP_SUBSTR optimisation is doing; studying that was what originally led me to this general fix.)
Diffstat (limited to 'op.c')
-rw-r--r--op.c29
1 files changed, 27 insertions, 2 deletions
diff --git a/op.c b/op.c
index 0297073293..b56ba801c2 100644
--- a/op.c
+++ b/op.c
@@ -12074,6 +12074,23 @@ Perl_rpeep(pTHX_ OP *o)
if (OP_GIMME(o,0) == G_VOID) {
OP *right = cBINOP->op_first;
if (right) {
+ /* sassign
+ * RIGHT
+ * substr
+ * pushmark
+ * arg1
+ * arg2
+ * ...
+ * becomes
+ *
+ * ex-sassign
+ * substr
+ * pushmark
+ * RIGHT
+ * arg1
+ * arg2
+ * ...
+ */
OP *left = right->op_sibling;
if (left->op_type == OP_SUBSTR
&& (left->op_private & 7) < 4) {
@@ -12099,8 +12116,16 @@ Perl_rpeep(pTHX_ OP *o)
}
}
- oldoldop = oldop;
- oldop = o;
+ /* did we just null the current op? If so, re-process it to handle
+ * eliding "empty" ops from the chain */
+ if (o->op_type == OP_NULL && oldop && oldop->op_next == o) {
+ o->op_opt = 0;
+ o = oldop;
+ }
+ else {
+ oldoldop = oldop;
+ oldop = o;
+ }
}
LEAVE;
}