This is a live mirror of the Perl 5 development currently hosted at
Perl_rpeep: undo tail recursion optimisation
authorDavid Mitchell <>
Mon, 18 Jul 2011 19:14:10 +0000 (20:14 +0100)
committerDavid Mitchell <>
Mon, 18 Jul 2011 19:24:42 +0000 (20:24 +0100)
commit 3c78429c102e0fe2ad30c60dfe52636b6071ef19 reduced the depth
of recursion in rpeep(), by deferring recursion into branches until a bit
later (so that the recursive call to rpeep was then likely to be shallow).
However, it went one step further: when the chain of op_next's had been
exhausted in the main loop, it processed any remaining deferrred branches
in the main loop rather than recursing. All nice and efficient, but it
broke the expectation that someone who had hooked into rpeep could follow
the chain of op_nexts in each call and visit *all* ops.

This commit removes that optimisation and restores the rpeep hook
expectancy. This shouldn't have any major effect on the depth of
recursion, and its minor inefficiency doesn't really matter for a
one-time compilation-time pass.


index 87d749b..bfcc9eb 100644 (file)
@@ -23,7 +23,8 @@ is($rrecord->[0], 'affe');
 # A deep-enough nesting of conditionals defeats the deferring mechanism
 # and triggers recursion. Note that this test is sensitive to the details
 # rpeep: the main thing it is testing is that rpeep is called more than
-# peep; the details are less important.
+# peep, and that all branches are covered; the order of branch calling is
+# less important.
 my $code =  q[my ($a,$b); $a =];
 $code .= qq{ \$b ? "foo$_" :} for (1..10);
@@ -33,4 +34,5 @@ eval $code;
 is_deeply($record,  [ "foo11" ]);
-is_deeply($rrecord, [ qw(foo1 foo2 foo3 foo4 foo5 foo6 foo11) ]);
+is_deeply($rrecord, [
+    qw(foo1 foo2 foo3 foo4 foo5 foo6 foo10 foo9 foo8 foo7 foo11) ]);
diff --git a/op.c b/op.c
index e7cff45..6a94db4 100644 (file)
--- a/op.c
+++ b/op.c
@@ -9338,8 +9338,7 @@ Perl_rpeep(pTHX_ register OP *o)
        while (!o) {
            if (defer_ix < 0)
-           o = defer_queue[(defer_base + defer_ix--) % MAX_DEFERRED];
-           oldop = NULL;
+           CALL_RPEEP(defer_queue[(defer_base + defer_ix--) % MAX_DEFERRED]);
        if (!o)