From f0bb9bf76bbed7ffe177496880af0e8873394453 Mon Sep 17 00:00:00 2001 From: David Mitchell Date: Wed, 19 Aug 2015 12:33:24 +0100 Subject: [PATCH] Add itersave field to LOOP context struct When entering a for loop, rather than saving the original loop variable on the save stack, save it in the context struct. Quicker and simpler. Note that as of this commit, entering a for loop no longer saves anything on the save stack. --- cop.h | 27 +++++++++++++++++++++++---- pp_ctl.c | 13 ++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/cop.h b/cop.h index e22617c..e430201 100644 --- a/cop.h +++ b/cop.h @@ -761,6 +761,7 @@ struct block_loop { SV **svp; /* for lexicals: address of pad slot */ GV *gv; /* for package vars */ } itervar_u; + SV *itersave; /* the original iteration var */ union { struct { /* valid if type is LOOP_FOR or LOOP_PLAIN (but {NULL,0})*/ AV * ary; /* use the stack if this is NULL */ @@ -804,7 +805,8 @@ struct block_loop { cx->blk_loop.state_u.ary.ary = NULL; \ cx->blk_loop.state_u.ary.ix = 0; \ cx->blk_loop.old_savestack_ix = PL_savestack_ix; \ - cx->blk_loop.itervar_u.svp = NULL; + cx->blk_loop.itervar_u.svp = NULL; \ + cx->blk_loop.itersave = NULL; #ifdef USE_ITHREADS # define PUSHLOOP_FOR_setpad(c) (c)->blk_loop.oldcomppad = PL_comppad @@ -812,13 +814,14 @@ struct block_loop { # define PUSHLOOP_FOR_setpad(c) NOOP #endif -#define PUSHLOOP_FOR(cx, ivar, s) \ +#define PUSHLOOP_FOR(cx, ivar, isave, s) \ cx->blk_loop.resetsp = s - PL_stack_base; \ cx->blk_loop.my_op = cLOOP; \ cx->blk_loop.state_u.ary.ary = NULL; \ cx->blk_loop.state_u.ary.ix = 0; \ cx->blk_loop.itervar_u.svp = (SV**)(ivar); \ cx->blk_loop.old_savestack_ix = PL_savestack_ix; \ + cx->blk_loop.itersave = isave; \ PUSHLOOP_FOR_setpad(cx); #define POPLOOP(cx) \ @@ -827,8 +830,24 @@ struct block_loop { SvREFCNT_dec_NN(cx->blk_loop.state_u.lazysv.cur); \ SvREFCNT_dec_NN(cx->blk_loop.state_u.lazysv.end); \ } \ - if (CxTYPE(cx) == CXt_LOOP_FOR) \ - SvREFCNT_dec(cx->blk_loop.state_u.ary.ary); + else if (CxTYPE(cx) == CXt_LOOP_FOR) \ + SvREFCNT_dec(cx->blk_loop.state_u.ary.ary); \ + if (cx->blk_loop.itersave) { \ + SV **svp = (cx)->blk_loop.itervar_u.svp; \ + SV *cursv; \ + if (isGV((GV*)svp)) { \ + svp = &GvSV((GV*)svp); \ + cursv = *svp; \ + *svp = cx->blk_loop.itersave; \ + SvREFCNT_dec_NN(cx->blk_loop.itersave); \ + } \ + else { \ + cursv = *svp; \ + *svp = cx->blk_loop.itersave; \ + } \ + /* delayed rc-- in case of "for $x (...) { return $x }" */ \ + sv_2mortal(cursv); \ + } \ /* given/when context */ struct block_givwhen { diff --git a/pp_ctl.c b/pp_ctl.c index ea8ad0e..1fc7ac5 100644 --- a/pp_ctl.c +++ b/pp_ctl.c @@ -2118,25 +2118,27 @@ PP(pp_enteriter) PERL_CONTEXT *cx; const I32 gimme = GIMME_V; void *itervar; /* location of the iteration variable */ + SV *itersave; /* the old var in the iterator var slot */ U8 cxtype = CXt_LOOP_FOR; ENTER_with_name("loop1"); SAVETMPS; if (PL_op->op_targ) { /* "my" variable */ + itervar = &PAD_SVl(PL_op->op_targ); if (PL_op->op_private & OPpLVAL_INTRO) { /* for my $x (...) */ /* the SV currently in the pad slot is never live during * iteration (the slot is always aliased to one of the items) * so it's always stale */ - SvPADSTALE_on(PAD_SVl(PL_op->op_targ)); + SvPADSTALE_on(*(SV**)itervar); } - SAVEPADSVANDMORTALIZE(PL_op->op_targ); - itervar = &PAD_SVl(PL_op->op_targ); + itersave = SvREFCNT_inc(*(SV**)itervar); + assert(itersave); } else if (LIKELY(isGV(TOPs))) { /* symbol table variable */ GV * const gv = MUTABLE_GV(POPs); SV** svp = &GvSV(gv); - save_pushptrptr(gv, SvREFCNT_inc(*svp), SAVEt_GVSV); + itersave = SvREFCNT_inc(*svp); *svp = newSV(0); itervar = (void *)gv; } @@ -2147,6 +2149,7 @@ PP(pp_enteriter) assert(SvMAGIC(sv)->mg_type == PERL_MAGIC_lvref); itervar = (void *)sv; cxtype |= CXp_FOR_LVREF; + itersave = NULL; } if (PL_op->op_private & OPpITER_DEF) @@ -2155,7 +2158,7 @@ PP(pp_enteriter) ENTER_with_name("loop2"); PUSHBLOCK(cx, cxtype, SP); - PUSHLOOP_FOR(cx, itervar, MARK); + PUSHLOOP_FOR(cx, itervar, itersave, MARK); if (PL_op->op_flags & OPf_STACKED) { SV *maybe_ary = POPs; if (SvTYPE(maybe_ary) != SVt_PVAV) { -- 1.8.3.1