Skip to content

Commit

Permalink
S_optimize_op(): remove anti-recursion deferring
Browse files Browse the repository at this point in the history
S_optimize_op() used to recursively work its way down an optree
marking ops as being in the appropriate context.

This commit removes the deferred mechanism, and instead makes use of the
newish OP_PARENT mechanism to iterate over the optree, following each
kid, then back up via the parent pointer to the next sibling etc.
  • Loading branch information
iabyn committed Jun 24, 2019
1 parent 73cdf3a commit 6eebe43
Showing 1 changed file with 36 additions and 15 deletions.
51 changes: 36 additions & 15 deletions op.c
Original file line number Diff line number Diff line change
Expand Up @@ -3510,17 +3510,20 @@ Perl_optimize_optree(pTHX_ OP* o)
}


/* helper for optimize_optree() which optimises on op then recurses
/* helper for optimize_optree() which optimises one op then recurses
* to optimise any children.
*/

STATIC void
S_optimize_op(pTHX_ OP* o)
{
dDEFER_OP;
OP *top_op = o;

PERL_ARGS_ASSERT_OPTIMIZE_OP;
do {

while (1) {
OP * next_kid = NULL;

assert(o->op_type != OP_FREED);

switch (o->op_type) {
Expand All @@ -3538,26 +3541,44 @@ S_optimize_op(pTHX_ OP* o)
break;

case OP_SUBST:
if (cPMOPo->op_pmreplrootu.op_pmreplroot)
DEFER_OP(cPMOPo->op_pmreplrootu.op_pmreplroot);
if (cPMOPo->op_pmreplrootu.op_pmreplroot) {
/* we can't assume that op_pmreplroot->op_sibparent == o
* and that it is thus possible to walk back up the tree
* past op_pmreplroot. So, although we try to avoid
* recursing through op trees, do it here. After all,
* there are unlikely to be many nested s///e's within
* the replacement part of a s///e.
*/
optimize_op(cPMOPo->op_pmreplrootu.op_pmreplroot);
}
break;

default:
break;
}

if (o->op_flags & OPf_KIDS) {
OP *kid;
IV child_count = 0;
for (kid = cUNOPo->op_first; kid; kid = OpSIBLING(kid)) {
DEFER_OP(kid);
++child_count;
}
DEFER_REVERSE(child_count);
if (o->op_flags & OPf_KIDS)
next_kid = cUNOPo->op_first;

/* if a kid hasn't been nominated to process, continue with the
* next sibling, or if no siblings left, go back to the parent's
* siblings and so on
*/
while (!next_kid) {
if (o == top_op)
return; /* at top; no parents/siblings to try */
if (OpHAS_SIBLING(o))
next_kid = o->op_sibparent;
else
o = o->op_sibparent; /*try parent's next sibling */
}
} while ( ( o = POP_DEFERRED_OP() ) );

DEFER_OP_CLEANUP;
/* this label not yet used. Goto here if any code above sets
* next-kid
get_next_op:
*/
o = next_kid;
}
}


Expand Down

0 comments on commit 6eebe43

Please sign in to comment.