This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
pp_iter(): jump directly to op after OP_AND
authorDavid Mitchell <davem@iabyn.com>
Sat, 15 Jul 2017 12:27:09 +0000 (13:27 +0100)
committerDavid Mitchell <davem@iabyn.com>
Thu, 27 Jul 2017 10:30:23 +0000 (11:30 +0100)
AN OP_ITER's op_next field always points to an OP_AND node. Rather than
pushing &PL_sv_yes or &PL_sv_no and then passing control to the OP_AND,
make pp_iter() return the OP_AND's op_next or op_other directly, depending
on whether this is the last iteration or not.

For an empty body, this cuts about 20% off the time of an iteration.

It's possible that some weird optree-munging XS module may break this
assumption. For now I've just added asserts that the next op is OP_AND
with an op_ppaddr of Perl_pp_and; if that assertion fails, it may be
necessary to convert pp_iter()s' asserts into conditional statements.

In the longer term it might be worthwhile converting OP_ITER from a
BASEOP into a LOGOP and eliminate the OP_AND from the optree altogether.

Alternatively, perhaps pp_iter could just tail call Perl_op_leavesub
directly after the last iteration?

pp_hot.c

index da514e2..d4b32c9 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -2910,7 +2910,6 @@ PP(pp_iter)
     PERL_CONTEXT *cx;
     SV *oldsv;
     SV **itersvp;
-    SV *retsv;
 
     SV *sv;
     AV *av;
@@ -3073,18 +3072,28 @@ PP(pp_iter)
        DIE(aTHX_ "panic: pp_iter, type=%u", CxTYPE(cx));
     }
 
-    retsv = &PL_sv_yes;
-    if (0) {
-      retno:
-        retsv = &PL_sv_no;
-    }
+    /* Bypass pushing &PL_sv_yes and calling pp_and(); instead
+     * jump straight to the AND op's op_other */
+    assert(PL_op->op_next->op_type == OP_AND);
+    assert(PL_op->op_next->op_ppaddr == Perl_pp_and);
+    return cLOGOPx(PL_op->op_next)->op_other;
+
+  retno:
+    /* Bypass pushing &PL_sv_no and calling pp_and(); instead
+     * jump straight to the AND op's op_next */
+    assert(PL_op->op_next->op_type == OP_AND);
+    assert(PL_op->op_next->op_ppaddr == Perl_pp_and);
     /* pp_enteriter should have pre-extended the stack */
     EXTEND_SKIP(PL_stack_sp, 1);
-    *++PL_stack_sp =retsv;
-
-    return PL_op->op_next;
+    /* we only need this for the rare case where the OP_AND isn't
+     * in void context, e.g. $x = do { for (..) {...} };
+     * but its cheaper to just push it rather than testing first
+     */
+    *++PL_stack_sp = &PL_sv_no;
+    return PL_op->op_next->op_next;
 }
 
+
 /*
 A description of how taint works in pattern matching and substitution.