#endif
SV * itersave;
union {
- /* (from inspection of source code) for a .. range of strings this is the
- current string. */
- SV * iterlval;
- /* (from inspection of source code) for a .. range of numbers this is the
- maximum value. */
- IV itermax;
- } lval_max_u;
- union {
- /* (from inspection of source code) for a foreach loop this is the array
- being iterated over. For a .. range of numbers it's the current value.
- A check is often made on the SvTYPE of iterary to determine whether
- we are iterating over an array or a range. (numbers or strings) */
- AV * iterary;
- /* Minimum stack index when reverse iterating as CXt_LOOP_STACK */
- IV itermin;
- } ary_min_u;
- IV iterix;
+ struct { /* valid if type is LOOP_FOR or LOOP_PLAIN (but {NULL,0})*/
+ AV * ary; /* use the stack if this is NULL */
+ IV ix;
+ } ary;
+ struct { /* valid if type is LOOP_LAZYIV */
+ IV cur;
+ IV end;
+ } lazyiv;
+ struct { /* valid if type if LOOP_LAZYSV */
+ SV * cur;
+ SV * end; /* maxiumum value (or minimum in reverse) */
+ } lazysv;
+ } state_u;
};
#ifdef USE_ITHREADS
cx->blk_loop.resetsp = s - PL_stack_base; \
cx->blk_loop.my_op = cLOOP; \
PUSHLOOP_OP_NEXT; \
- cx->blk_loop.lval_max_u.iterlval = NULL; \
- cx->blk_loop.ary_min_u.iterary = NULL; \
+ cx->blk_loop.state_u.ary.ary = NULL; \
+ cx->blk_loop.state_u.ary.ix = 0; \
CX_ITERDATA_SET(cx,NULL);
#define PUSHLOOP_FOR(cx, dat, s) \
cx->blk_loop.resetsp = s - PL_stack_base; \
cx->blk_loop.my_op = cLOOP; \
PUSHLOOP_OP_NEXT; \
- cx->blk_loop.lval_max_u.iterlval = NULL; \
- cx->blk_loop.ary_min_u.iterary = NULL; \
- cx->blk_loop.iterix = -1; \
+ cx->blk_loop.state_u.ary.ary = NULL; \
+ cx->blk_loop.state_u.ary.ix = 0; \
CX_ITERDATA_SET(cx,dat);
#define POPLOOP(cx) \
- if (CxTYPE(cx) != CXt_LOOP_LAZYIV) \
- SvREFCNT_dec(cx->blk_loop.lval_max_u.iterlval); \
+ if (CxTYPE(cx) == CXt_LOOP_LAZYSV) { \
+ SvREFCNT_dec(cx->blk_loop.state_u.lazysv.cur); \
+ SvREFCNT_dec(cx->blk_loop.state_u.lazysv.end); \
+ } \
if (CxITERVAR(cx)) { \
if (SvPADMY(cx->blk_loop.itersave)) { \
SV ** const s_v_p = CxITERVAR(cx); \
SvREFCNT_dec(cx->blk_loop.itersave); \
} \
} \
- if ((CxTYPE(cx) != CXt_LOOP_STACK) && cx->blk_loop.ary_min_u.iterary) \
- SvREFCNT_dec(cx->blk_loop.ary_min_u.iterary);
+ if (CxTYPE(cx) == CXt_LOOP_FOR) \
+ SvREFCNT_dec(cx->blk_loop.state_u.ary.ary);
/* given/when context */
struct block_givwhen {
/* This is first so that CXt_LOOP_FOR|CXt_LOOP_LAZYIV is CXt_LOOP_LAZYIV */
#define CXt_LOOP_FOR 8
#define CXt_LOOP_PLAIN 9
-/* Foreach on a temporary list on the stack */
-#define CXt_LOOP_STACK 10
+#define CXt_LOOP_LAZYSV 10
#define CXt_LOOP_LAZYIV 11
/* private flags for CXt_SUB and CXt_NULL
"NULL",
"SUB",
"EVAL",
- "LOOP",
+ "WHEN",
"SUBST",
"BLOCK",
"FORMAT",
"GIVEN",
- "WHEN"
+ "LOOP_FOR",
+ "LOOP_PLAIN",
+ "LOOP_LAZYSV",
+ "LOOP_LAZYIV",
};
#else
EXTCONST char* PL_block_type[];
return -1;
break;
case CXt_LOOP_LAZYIV:
- case CXt_LOOP_STACK:
+ case CXt_LOOP_LAZYSV:
case CXt_LOOP_FOR:
case CXt_LOOP_PLAIN:
if ( !CxLABEL(cx) || strNE(label, CxLABEL(cx)) ) {
return -1;
break;
case CXt_LOOP_LAZYIV:
- case CXt_LOOP_STACK:
+ case CXt_LOOP_LAZYSV:
case CXt_LOOP_FOR:
case CXt_LOOP_PLAIN:
DEBUG_l( Perl_deb(aTHX_ "(Found loop #%ld)\n", (long)i));
assert(!CxFOREACHDEF(cx));
break;
case CXt_LOOP_LAZYIV:
- case CXt_LOOP_STACK:
+ case CXt_LOOP_LAZYSV:
case CXt_LOOP_FOR:
if (CxFOREACHDEF(cx)) {
DEBUG_l( Perl_deb(aTHX_ "(Found foreach #%ld)\n", (long)i));
POPEVAL(cx);
break;
case CXt_LOOP_LAZYIV:
- case CXt_LOOP_STACK:
+ case CXt_LOOP_LAZYSV:
case CXt_LOOP_FOR:
case CXt_LOOP_PLAIN:
POPLOOP(cx);
ENTER;
- cxtype |= (PL_op->op_flags & OPf_STACKED) ? CXt_LOOP_FOR : CXt_LOOP_STACK;
+ cxtype |= CXt_LOOP_FOR;
PUSHBLOCK(cx, cxtype, SP);
#ifdef USE_ITHREADS
PUSHLOOP_FOR(cx, iterdata, MARK);
PUSHLOOP_FOR(cx, svp, MARK);
#endif
if (PL_op->op_flags & OPf_STACKED) {
- cx->blk_loop.ary_min_u.iterary = (AV*)SvREFCNT_inc(POPs);
- if (SvTYPE(cx->blk_loop.ary_min_u.iterary) != SVt_PVAV) {
+ SV *maybe_ary = POPs;
+ if (SvTYPE(maybe_ary) != SVt_PVAV) {
dPOPss;
- SV * const right = (SV*)cx->blk_loop.ary_min_u.iterary;
+ SV * const right = maybe_ary;
SvGETMAGIC(sv);
SvGETMAGIC(right);
if (RANGE_IS_NUMERIC(sv,right)) {
+ cx->cx_type &= ~CXTYPEMASK;
cx->cx_type |= CXt_LOOP_LAZYIV;
/* Make sure that no-one re-orders cop.h and breaks our
assumptions */
(SvNV(right) > (NV)UV_MAX))))))
#endif
DIE(aTHX_ "Range iterator outside integer range");
- cx->blk_loop.iterix = SvIV(sv);
- cx->blk_loop.lval_max_u.itermax = SvIV(right);
+ cx->blk_loop.state_u.lazyiv.cur = SvIV(sv);
+ cx->blk_loop.state_u.lazyiv.end = SvIV(right);
#ifdef DEBUGGING
/* for correct -Dstv display */
cx->blk_oldsp = sp - PL_stack_base;
#endif
}
else {
- cx->blk_loop.lval_max_u.iterlval = newSVsv(sv);
- (void) SvPV_force_nolen(cx->blk_loop.lval_max_u.iterlval);
+ cx->cx_type &= ~CXTYPEMASK;
+ cx->cx_type |= CXt_LOOP_LAZYSV;
+ /* Make sure that no-one re-orders cop.h and breaks our
+ assumptions */
+ assert(CxTYPE(cx) == CXt_LOOP_LAZYSV);
+ cx->blk_loop.state_u.lazysv.cur = newSVsv(sv);
+ cx->blk_loop.state_u.lazysv.end = right;
+ SvREFCNT_inc(right);
+ (void) SvPV_force_nolen(cx->blk_loop.state_u.lazysv.cur);
/* This will do the upgrade to SVt_PV, and warn if the value
is uninitialised. */
(void) SvPV_nolen_const(right);
to replace !SvOK() with a pointer to "". */
if (!SvOK(right)) {
SvREFCNT_dec(right);
- cx->blk_loop.ary_min_u.iterary = (AV*) &PL_sv_no;
+ cx->blk_loop.state_u.lazysv.end = &PL_sv_no;
}
}
}
- else if (PL_op->op_private & OPpITER_REVERSED) {
- cx->blk_loop.iterix = AvFILL(cx->blk_loop.ary_min_u.iterary) + 1;
-
+ else /* SvTYPE(maybe_ary) == SVt_PVAV */ {
+ cx->blk_loop.state_u.ary.ary = (AV*)maybe_ary;
+ SvREFCNT_inc(maybe_ary);
+ cx->blk_loop.state_u.ary.ix =
+ (PL_op->op_private & OPpITER_REVERSED) ?
+ AvFILL(cx->blk_loop.state_u.ary.ary) + 1 :
+ -1;
}
}
- else {
+ else { /* iterating over items on the stack */
+ cx->blk_loop.state_u.ary.ary = NULL; /* means to use the stack */
if (PL_op->op_private & OPpITER_REVERSED) {
- cx->blk_loop.ary_min_u.itermin = MARK - PL_stack_base + 1;
- cx->blk_loop.iterix = cx->blk_oldsp + 1;
+ cx->blk_loop.state_u.ary.ix = cx->blk_oldsp + 1;
}
else {
- cx->blk_loop.iterix = MARK - PL_stack_base;
+ cx->blk_loop.state_u.ary.ix = MARK - PL_stack_base;
}
}
mark = newsp;
switch (CxTYPE(cx)) {
case CXt_LOOP_LAZYIV:
- case CXt_LOOP_STACK:
+ case CXt_LOOP_LAZYSV:
case CXt_LOOP_FOR:
case CXt_LOOP_PLAIN:
pop2 = CxTYPE(cx);
switch (pop2) {
case CXt_LOOP_LAZYIV:
case CXt_LOOP_PLAIN:
- case CXt_LOOP_STACK:
+ case CXt_LOOP_LAZYSV:
case CXt_LOOP_FOR:
POPLOOP(cx); /* release loop vars ... */
LEAVE;
}
/* else fall through */
case CXt_LOOP_LAZYIV:
- case CXt_LOOP_STACK:
+ case CXt_LOOP_LAZYSV:
case CXt_LOOP_FOR:
case CXt_LOOP_PLAIN:
gotoprobe = cx->blk_oldcop->op_sibling;
dVAR; dSP;
register PERL_CONTEXT *cx;
SV *sv, *oldsv;
- AV* av;
SV **itersvp;
+ AV *av = NULL; /* used for LOOP_FOR on arrays and the stack */
+ bool av_is_stack = FALSE;
EXTEND(SP, 1);
cx = &cxstack[cxstack_ix];
DIE(aTHX_ "panic: pp_iter");
itersvp = CxITERVAR(cx);
- av = (CxTYPE(cx) == CXt_LOOP_STACK)
- ? PL_curstack : cx->blk_loop.ary_min_u.iterary;
- if (SvTYPE(av) != SVt_PVAV) {
- /* iterate ($min .. $max) */
- if (CxTYPE(cx) != CXt_LOOP_LAZYIV) {
+ if (CxTYPE(cx) == CXt_LOOP_LAZYSV) {
/* string increment */
- register SV* cur = cx->blk_loop.lval_max_u.iterlval;
+ SV* cur = cx->blk_loop.state_u.lazysv.cur;
+ SV *end = cx->blk_loop.state_u.lazysv.end;
/* If the maximum is !SvOK(), pp_enteriter substitutes PL_sv_no.
It has SvPVX of "" and SvCUR of 0, which is what we want. */
STRLEN maxlen = 0;
- const char *max = SvPV_const((SV*)av, maxlen);
+ const char *max = SvPV_const(end, maxlen);
if (!SvNIOK(cur) && SvCUR(cur) <= maxlen) {
if (SvREFCNT(*itersvp) == 1 && !SvMAGICAL(*itersvp)) {
/* safe to reuse old SV */
RETPUSHYES;
}
RETPUSHNO;
- }
+ }
+ else if (CxTYPE(cx) == CXt_LOOP_LAZYIV) {
/* integer increment */
- if (cx->blk_loop.iterix > cx->blk_loop.lval_max_u.itermax)
+ if (cx->blk_loop.state_u.lazyiv.cur > cx->blk_loop.state_u.lazyiv.end)
RETPUSHNO;
/* don't risk potential race */
if (SvREFCNT(*itersvp) == 1 && !SvMAGICAL(*itersvp)) {
/* safe to reuse old SV */
- sv_setiv(*itersvp, cx->blk_loop.iterix++);
+ sv_setiv(*itersvp, cx->blk_loop.state_u.lazyiv.cur++);
}
else
{
* completely new SV for closures/references to work as they
* used to */
oldsv = *itersvp;
- *itersvp = newSViv(cx->blk_loop.iterix++);
+ *itersvp = newSViv(cx->blk_loop.state_u.lazyiv.cur++);
SvREFCNT_dec(oldsv);
}
/* Handle end of range at IV_MAX */
- if ((cx->blk_loop.iterix == IV_MIN) &&
- (cx->blk_loop.lval_max_u.itermax == IV_MAX))
+ if ((cx->blk_loop.state_u.lazyiv.cur == IV_MIN) &&
+ (cx->blk_loop.state_u.lazyiv.end == IV_MAX))
{
- cx->blk_loop.iterix++;
- cx->blk_loop.lval_max_u.itermax++;
+ cx->blk_loop.state_u.lazyiv.cur++;
+ cx->blk_loop.state_u.lazyiv.end++;
}
RETPUSHYES;
}
/* iterate array */
+ assert(CxTYPE(cx) == CXt_LOOP_FOR);
+ av = cx->blk_loop.state_u.ary.ary;
+ if (!av) {
+ av_is_stack = TRUE;
+ av = PL_curstack;
+ }
if (PL_op->op_private & OPpITER_REVERSED) {
- /* In reverse, use itermax as the min :-) */
- if (cx->blk_loop.iterix <= (CxTYPE(cx) == CXt_LOOP_STACK
- ? cx->blk_loop.ary_min_u.itermin : 0))
+ if (cx->blk_loop.state_u.ary.ix <= (av_is_stack
+ ? cx->blk_loop.resetsp + 1 : 0))
RETPUSHNO;
if (SvMAGICAL(av) || AvREIFY(av)) {
- SV * const * const svp = av_fetch(av, --cx->blk_loop.iterix, FALSE);
+ SV * const * const svp = av_fetch(av, --cx->blk_loop.state_u.ary.ix, FALSE);
sv = svp ? *svp : NULL;
}
else {
- sv = AvARRAY(av)[--cx->blk_loop.iterix];
+ sv = AvARRAY(av)[--cx->blk_loop.state_u.ary.ix];
}
}
else {
- if (cx->blk_loop.iterix >= (av == PL_curstack ? cx->blk_oldsp :
+ if (cx->blk_loop.state_u.ary.ix >= (av_is_stack ? cx->blk_oldsp :
AvFILL(av)))
RETPUSHNO;
if (SvMAGICAL(av) || AvREIFY(av)) {
- SV * const * const svp = av_fetch(av, ++cx->blk_loop.iterix, FALSE);
+ SV * const * const svp = av_fetch(av, ++cx->blk_loop.state_u.ary.ix, FALSE);
sv = svp ? *svp : NULL;
}
else {
- sv = AvARRAY(av)[++cx->blk_loop.iterix];
+ sv = AvARRAY(av)[++cx->blk_loop.state_u.ary.ix];
}
}
Perl_croak(aTHX_ "Use of freed value in iteration");
}
- if (sv)
+ if (sv) {
SvTEMP_off(sv);
+ SvREFCNT_inc_simple_void_NN(sv);
+ }
else
sv = &PL_sv_undef;
- if (av != PL_curstack && sv == &PL_sv_undef) {
- SV *lv = cx->blk_loop.lval_max_u.iterlval;
- if (lv && SvREFCNT(lv) > 1) {
- SvREFCNT_dec(lv);
- lv = NULL;
- }
- if (lv)
- SvREFCNT_dec(LvTARG(lv));
- else {
- lv = cx->blk_loop.lval_max_u.iterlval = newSV_type(SVt_PVLV);
- LvTYPE(lv) = 'y';
- sv_magic(lv, NULL, PERL_MAGIC_defelem, NULL, 0);
- }
+ if (!av_is_stack && sv == &PL_sv_undef) {
+ SV *lv = newSV_type(SVt_PVLV);
+ LvTYPE(lv) = 'y';
+ sv_magic(lv, NULL, PERL_MAGIC_defelem, NULL, 0);
LvTARG(lv) = SvREFCNT_inc_simple(av);
- LvTARGOFF(lv) = cx->blk_loop.iterix;
+ LvTARGOFF(lv) = cx->blk_loop.state_u.ary.ix;
LvTARGLEN(lv) = (STRLEN)UV_MAX;
- sv = (SV*)lv;
+ sv = lv;
}
oldsv = *itersvp;
- *itersvp = SvREFCNT_inc_simple_NN(sv);
+ *itersvp = sv;
SvREFCNT_dec(oldsv);
RETPUSHYES;
break;
case CXt_LOOP_LAZYIV:
- case CXt_LOOP_STACK:
+ case CXt_LOOP_LAZYSV:
case CXt_LOOP_FOR:
case CXt_LOOP_PLAIN:
PerlIO_printf(Perl_debug_log, "BLK_LOOP.LABEL = %s\n", CxLABEL(cx));
PTR2UV(cx->blk_loop.my_op));
PerlIO_printf(Perl_debug_log, "BLK_LOOP.NEXT_OP = 0x%"UVxf"\n",
PTR2UV(CX_LOOP_NEXTOP_GET(cx)));
- PerlIO_printf(Perl_debug_log, "BLK_LOOP.ITERIX = %ld\n",
- (long)cx->blk_loop.iterix);
+ /* XXX: not accurate for LAZYSV/IV */
PerlIO_printf(Perl_debug_log, "BLK_LOOP.ITERARY = 0x%"UVxf"\n",
- PTR2UV(cx->blk_loop.ary_min_u.iterary));
+ PTR2UV(cx->blk_loop.state_u.ary.ary));
+ PerlIO_printf(Perl_debug_log, "BLK_LOOP.ITERIX = %ld\n",
+ (long)cx->blk_loop.state_u.ary.ix);
PerlIO_printf(Perl_debug_log, "BLK_LOOP.ITERVAR = 0x%"UVxf"\n",
PTR2UV(CxITERVAR(cx)));
if (CxITERVAR(cx))
PerlIO_printf(Perl_debug_log, "BLK_LOOP.ITERSAVE = 0x%"UVxf"\n",
PTR2UV(cx->blk_loop.itersave));
- PerlIO_printf(Perl_debug_log, "BLK_LOOP.ITERLVAL = 0x%"UVxf"\n",
- PTR2UV(cx->blk_loop.lval_max_u.iterlval));
break;
case CXt_SUBST:
param);
ncx->blk_eval.cur_text = sv_dup(ncx->blk_eval.cur_text, param);
break;
- case CXt_LOOP_LAZYIV:
+ case CXt_LOOP_LAZYSV:
+ ncx->blk_loop.state_u.lazysv.cur
+ = sv_dup_inc(ncx->blk_loop.state_u.lazysv.cur, param);
+ ncx->blk_loop.state_u.lazysv.end
+ = sv_dup_inc(ncx->blk_loop.state_u.lazysv.end, param);
+ goto dup_cxt_loop;
case CXt_LOOP_FOR:
- ncx->blk_loop.ary_min_u.iterary
- = av_dup_inc(ncx->blk_loop.ary_min_u.iterary, param);
- case CXt_LOOP_STACK:
+ ncx->blk_loop.state_u.ary.ary
+ = av_dup_inc(ncx->blk_loop.state_u.ary.ary, param);
+ case CXt_LOOP_LAZYIV:
case CXt_LOOP_PLAIN:
+ dup_cxt_loop:
ncx->blk_loop.iterdata = (CxPADLOOP(ncx)
? ncx->blk_loop.iterdata
: gv_dup((GV*)ncx->blk_loop.iterdata,
ncx->blk_loop.oldcomppad);
ncx->blk_loop.itersave = sv_dup_inc(ncx->blk_loop.itersave,
param);
- if (CxTYPE(ncx) != CXt_LOOP_LAZYIV)
- ncx->blk_loop.lval_max_u.iterlval
- = sv_dup_inc(ncx->blk_loop.lval_max_u.iterlval, param);
break;
case CXt_FORMAT:
ncx->blk_format.cv = cv_dup(ncx->blk_format.cv, param);