diff options
-rw-r--r-- | cop.h | 52 | ||||
-rw-r--r-- | perl.h | 7 | ||||
-rw-r--r-- | pp_ctl.c | 58 | ||||
-rw-r--r-- | pp_hot.c | 79 | ||||
-rw-r--r-- | scope.c | 11 | ||||
-rw-r--r-- | sv.c | 17 |
6 files changed, 117 insertions, 107 deletions
@@ -444,23 +444,19 @@ struct block_loop { #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 @@ -501,22 +497,23 @@ struct block_loop { 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); \ @@ -527,8 +524,8 @@ struct block_loop { 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 { @@ -680,8 +677,7 @@ struct context { /* 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 @@ -4365,12 +4365,15 @@ EXTCONST char* const PL_block_type[] = { "NULL", "SUB", "EVAL", - "LOOP", + "WHEN", "SUBST", "BLOCK", "FORMAT", "GIVEN", - "WHEN" + "LOOP_FOR", + "LOOP_PLAIN", + "LOOP_LAZYSV", + "LOOP_LAZYIV", }; #else EXTCONST char* PL_block_type[]; @@ -1257,7 +1257,7 @@ S_dopoptolabel(pTHX_ const char *label) 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)) ) { @@ -1375,7 +1375,7 @@ S_dopoptoloop(pTHX_ I32 startingblock) 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)); @@ -1402,7 +1402,7 @@ S_dopoptogiven(pTHX_ I32 startingblock) 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)); @@ -1455,7 +1455,7 @@ Perl_dounwind(pTHX_ I32 cxix) 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); @@ -1873,7 +1873,7 @@ PP(pp_enteriter) 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); @@ -1881,13 +1881,14 @@ PP(pp_enteriter) 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 */ @@ -1912,16 +1913,23 @@ PP(pp_enteriter) (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); @@ -1929,22 +1937,26 @@ PP(pp_enteriter) 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; } } @@ -2165,7 +2177,7 @@ PP(pp_last) 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); @@ -2212,7 +2224,7 @@ PP(pp_last) 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; @@ -2572,7 +2584,7 @@ PP(pp_goto) } /* 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; @@ -1902,8 +1902,9 @@ PP(pp_iter) 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]; @@ -1911,17 +1912,14 @@ PP(pp_iter) 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 */ @@ -1943,15 +1941,16 @@ PP(pp_iter) 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 { @@ -1959,47 +1958,52 @@ PP(pp_iter) * 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]; } } @@ -2008,31 +2012,24 @@ PP(pp_iter) 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; @@ -1084,7 +1084,7 @@ Perl_cx_dump(pTHX_ PERL_CONTEXT *cx) 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)); @@ -1094,17 +1094,16 @@ Perl_cx_dump(pTHX_ PERL_CONTEXT *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: @@ -10543,12 +10543,18 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max, CLONE_PARAMS* param) 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, @@ -10558,9 +10564,6 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max, CLONE_PARAMS* param) 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); |