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 */
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
# 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) \
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 {
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;
}
assert(SvMAGIC(sv)->mg_type == PERL_MAGIC_lvref);
itervar = (void *)sv;
cxtype |= CXp_FOR_LVREF;
+ itersave = NULL;
}
if (PL_op->op_private & OPpITER_DEF)
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) {