Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Commit 97bc409

Browse files
iabynrurban
authored andcommitted
pp_iter(): jump directly to op after OP_AND
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?
1 parent 1b6e616 commit 97bc409

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

pod/perlcdelta.pod

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,14 @@ the "Attempt to access disallowed key %s in the restricted hash
163163
%CLASS::" errors. Stash lookup now got a B<GV_CLASS> flag and C<hv_fetch*_ifexists>
164164
macros, which does the EXISTS and FETCH hash actions in the stash on one.
165165

166+
=item *
167+
168+
Optimized the loop op ITER to jump directly to the subsequent AND op.
169+
For an empty body, this cuts about 20% off the time of an iteration.
170+
Backported from perl-5.27.3. This is a simplier implementation of
171+
the cperl F<feature/gh138-iter-and> branch from L<[cperl
172+
#138]|https://github.com/perl11/cperl/issues/138>.
173+
166174
=back
167175

168176
=head1 Modules and Pragmata

pp_hot.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3177,7 +3177,6 @@ PP(pp_iter)
31773177
PERL_CONTEXT *cx;
31783178
SV *oldsv;
31793179
SV **itersvp;
3180-
SV *retsv;
31813180

31823181
SV *sv;
31833182
AV *av;
@@ -3349,18 +3348,28 @@ PP(pp_iter)
33493348
DIE(aTHX_ "panic: pp_iter, type=%u", CxTYPE(cx));
33503349
}
33513350

3352-
retsv = SV_YES;
3353-
if (0) {
3354-
retno:
3355-
retsv = SV_NO;
3356-
}
3351+
/* Bypass pushing &PL_sv_yes and calling pp_and(); instead
3352+
* jump straight to the AND op's op_other */
3353+
assert(OpNEXT(PL_op)->op_type == OP_AND);
3354+
assert(OpNEXT(PL_op)->op_ppaddr == Perl_pp_and);
3355+
return OpOTHER(OpNEXT(PL_op));
3356+
3357+
retno:
3358+
/* Bypass pushing &PL_sv_no and calling pp_and(); instead
3359+
* jump straight to the AND op's op_next */
3360+
assert(OpNEXT(PL_op)->op_type == OP_AND);
3361+
assert(OpNEXT(PL_op)->op_ppaddr == Perl_pp_and);
33573362
/* pp_enteriter should have pre-extended the stack */
33583363
assert(PL_stack_sp < PL_stack_max);
3359-
*++PL_stack_sp =retsv;
3360-
3361-
return PL_op->op_next;
3364+
/* we only need this for the rare case where the OP_AND isn't
3365+
* in void context, e.g. $x = do { for (..) {...} };
3366+
* but its cheaper to just push it rather than testing first
3367+
*/
3368+
*++PL_stack_sp = SV_NO;
3369+
return OpNEXT(OpNEXT(PL_op));
33623370
}
33633371

3372+
33643373
/*
33653374
A description of how taint works in pattern matching and substitution.
33663375

0 commit comments

Comments
 (0)