X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/9af0df0b57d248c9c26f1464e1f1c18f24c642c2..42831ce4bbb728b1e5cfa313cf99a85712eb080f:/cop.h?ds=sidebyside diff --git a/cop.h b/cop.h index c708cb7..525f546 100644 --- a/cop.h +++ b/cop.h @@ -550,8 +550,6 @@ be zero. /* subroutine context */ struct block_sub { OP * retop; /* op to execute on exit from sub */ - I32 old_savestack_ix; /* saved PL_savestack_ix (also CXt_NULL) */ - SSize_t old_tmpsfloor; /* also used in CXt_NULL sort block */ /* Above here is the same for sub, format and eval. */ PAD *prevcomppad; /* the caller's PL_comppad */ CV * cv; @@ -564,8 +562,6 @@ struct block_sub { /* format context */ struct block_format { OP * retop; /* op to execute on exit from sub */ - I32 old_savestack_ix; /* saved PL_savestack_ix (also CXt_NULL) */ - SSize_t old_tmpsfloor; /* also used in CXt_NULL sort block */ /* Above here is the same for sub, format and eval. */ PAD *prevcomppad; /* the caller's PL_comppad */ CV * cv; @@ -574,6 +570,23 @@ struct block_format { GV * dfoutgv; }; +/* free all savestack items back to the watermark of the specified context */ + +#define CX_LEAVE_SCOPE(cx) LEAVE_SCOPE(cx->cx_old_savestack_ix) + +#ifdef DEBUGGING +/* on debugging builds, poison cx afterwards so we know no code + * uses it - because after doing cxstack_ix--, any ties, exceptions etc + * may overwrite the current stack frame */ +# define CX_POP(cx) \ + assert(&cxstack[cxstack_ix] == cx); \ + cxstack_ix--; \ + cx = NULL; +#else +# define CX_POP(cx) cxstack_ix--; +#endif + + /* base for the next two macros. Don't use directly. * The context frame holds a reference to the CV so that it can't be * freed while we're executing it */ @@ -591,9 +604,7 @@ struct block_format { cx->blk_sub.prevcomppad = PL_comppad; \ cx->cx_type |= (hasargs) ? CXp_HASARGS : 0; \ cx->blk_sub.retop = NULL; \ - SvREFCNT_inc_simple_void_NN(cv); \ - cx->blk_sub.old_tmpsfloor = PL_tmps_floor; \ - PL_tmps_floor = PL_tmps_ix; + SvREFCNT_inc_simple_void_NN(cv); #define PUSHSUB_GET_LVALUE_MASK(func) \ /* If the context is indeterminate, then only the lvalue */ \ @@ -626,9 +637,7 @@ struct block_format { cx->blk_format.dfoutgv = PL_defoutgv; \ cx->blk_format.prevcomppad = PL_comppad; \ cx->blk_u16 = 0; \ - cx->blk_format.old_savestack_ix = PL_savestack_ix; \ - cx->blk_format.old_tmpsfloor = PL_tmps_floor; \ - PL_tmps_floor = PL_tmps_ix; \ + cx->cx_old_savestack_ix = PL_savestack_ix; \ SvREFCNT_inc_simple_void_NN(cv); \ CvDEPTH(cv)++; \ SvREFCNT_inc_void(cx->blk_format.dfoutgv) @@ -650,9 +659,35 @@ struct block_format { AvFILLp(ary) = -1; \ } STMT_END -#define POPSUB(cx,sv) \ + +/* subsets of POPSUB */ + +#define POPSUB_COMMON(cx) \ + PL_comppad = cx->blk_sub.prevcomppad; \ + PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL; \ + CvDEPTH((const CV*)cx->blk_sub.cv) = cx->blk_sub.olddepth; \ + SvREFCNT_dec_NN(cx->blk_sub.cv); + +/* handle the @_ part of leaving a sub */ + +#define POPSUB_ARGS(cx) \ + STMT_START { \ + AV *av; \ + assert(AvARRAY(MUTABLE_AV( \ + PadlistARRAY(CvPADLIST(cx->blk_sub.cv))[ \ + CvDEPTH(cx->blk_sub.cv)])) == PL_curpad); \ + POP_SAVEARRAY(); \ + /* abandon @_ if it got reified */ \ + av = MUTABLE_AV(PAD_SVl(0)); \ + if (UNLIKELY(AvREAL(av))) \ + clear_defarray(av, 0); \ + else { \ + CLEAR_ARGARRAY(av); \ + } \ + } STMT_END + +#define POPSUB(cx) \ STMT_START { \ - LEAVE_SCOPE(cx->blk_sub.old_savestack_ix); \ if (!(cx->blk_u16 & CxPOPSUB_DONE)) { \ cx->blk_u16 |= CxPOPSUB_DONE; \ RETURN_PROBE(CvNAMED(cx->blk_sub.cv) \ @@ -663,40 +698,18 @@ struct block_format { CopSTASHPV((COP*)CvSTART((const CV*)cx->blk_sub.cv))); \ \ if (CxHASARGS(cx)) { \ - AV *av; \ - assert(AvARRAY(MUTABLE_AV( \ - PadlistARRAY(CvPADLIST(cx->blk_sub.cv))[ \ - CvDEPTH(cx->blk_sub.cv)])) == PL_curpad); \ - POP_SAVEARRAY(); \ - /* abandon @_ if it got reified */ \ - av = MUTABLE_AV(PAD_SVl(0)); \ - if (UNLIKELY(AvREAL(av))) \ - clear_defarray(av, 0); \ - else { \ - CLEAR_ARGARRAY(av); \ - } \ + POPSUB_ARGS(cx); \ } \ } \ - PL_tmps_floor = cx->blk_sub.old_tmpsfloor; \ - PL_comppad = cx->blk_sub.prevcomppad; \ - PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL; \ - sv = MUTABLE_SV(cx->blk_sub.cv); \ - CvDEPTH((const CV*)sv) = cx->blk_sub.olddepth; \ - } STMT_END - -#define LEAVESUB(sv) \ - STMT_START { \ - SvREFCNT_dec(sv); \ + POPSUB_COMMON(cx); \ } STMT_END #define POPFORMAT(cx) \ STMT_START { \ - LEAVE_SCOPE(cx->blk_format.old_savestack_ix); \ if (!(cx->blk_u16 & CxPOPSUB_DONE)) { \ CV * const cv = cx->blk_format.cv; \ GV * const dfuot = cx->blk_format.dfoutgv; \ cx->blk_u16 |= CxPOPSUB_DONE; \ - PL_tmps_floor = cx->blk_format.old_tmpsfloor; \ setdefout(dfuot); \ PL_comppad = cx->blk_format.prevcomppad; \ PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL; \ @@ -709,8 +722,6 @@ struct block_format { /* eval context */ struct block_eval { OP * retop; /* op to execute on exit from eval */ - I32 old_savestack_ix; /* saved PL_savestack_ix (also CXt_NULL) */ - SSize_t old_tmpsfloor; /* also used in CXt_NULL sort block */ /* Above here is the same for sub, format and eval. */ SV * old_namesv; OP * old_eval_root; @@ -731,8 +742,6 @@ struct block_eval { assert(!(PL_in_eval & ~0x7F)); \ assert(!(PL_op->op_type & ~0x1FF)); \ cx->blk_u16 = (PL_in_eval & 0x7F) | ((U16)PL_op->op_type << 7); \ - cx->blk_eval.old_tmpsfloor = PL_tmps_floor; \ - PL_tmps_floor = PL_tmps_ix; \ cx->blk_eval.old_namesv = (n ? newSVpv(n,0) : NULL); \ cx->blk_eval.old_eval_root = PL_eval_root; \ cx->blk_eval.cur_text = PL_parser ? PL_parser->linestr : NULL; \ @@ -744,7 +753,6 @@ struct block_eval { #define POPEVAL(cx) \ STMT_START { \ PL_in_eval = CxOLD_IN_EVAL(cx); \ - optype = CxOLD_OP_TYPE(cx); \ PL_eval_root = cx->blk_eval.old_eval_root; \ if (cx->blk_eval.cur_text && SvSCREAM(cx->blk_eval.cur_text)) \ SvREFCNT_dec_NN(cx->blk_eval.cur_text); \ @@ -755,7 +763,6 @@ struct block_eval { /* loop context */ struct block_loop { I32 resetsp; - I32 old_savestack_ix; /* saved PL_savestack_ix (also CXt_NULL) */ LOOP * my_op; /* My op, that contains redo, next and last ops. */ union { /* different ways of locating the iteration variable */ SV **svp; /* for lexicals: address of pad slot */ @@ -802,7 +809,7 @@ struct block_loop { 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.old_savestack_ix = PL_savestack_ix; \ + cx->cx_old_savestack_ix = PL_savestack_ix; \ cx->blk_loop.itervar_u.svp = NULL; \ cx->blk_loop.itersave = NULL; @@ -818,12 +825,11 @@ struct block_loop { 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->cx_old_savestack_ix = PL_savestack_ix; \ cx->blk_loop.itersave = isave; \ PUSHLOOP_FOR_setpad(cx); #define POPLOOP(cx) \ - LEAVE_SCOPE(cx->blk_loop.old_savestack_ix); \ if (CxTYPE(cx) == CXt_LOOP_LAZYSV) { \ SvREFCNT_dec_NN(cx->blk_loop.state_u.lazysv.cur); \ SvREFCNT_dec_NN(cx->blk_loop.state_u.lazysv.end); \ @@ -831,29 +837,45 @@ struct block_loop { else if (CxTYPE(cx) == CXt_LOOP_FOR) \ SvREFCNT_dec(cx->blk_loop.state_u.ary.ary); \ if (cx->cx_type & (CXp_FOR_PAD|CXp_FOR_GV)) { \ - SV **svp = (cx)->blk_loop.itervar_u.svp; \ SV *cursv; \ - if ((cx->cx_type & CXp_FOR_GV)) { \ + SV **svp = (cx)->blk_loop.itervar_u.svp; \ + if ((cx->cx_type & CXp_FOR_GV)) \ svp = &GvSV((GV*)svp); \ - cursv = *svp; \ - *svp = cx->blk_loop.itersave; \ - } \ - else { \ - cursv = *svp; \ - *svp = cx->blk_loop.itersave; \ - } \ + cursv = *svp; \ + *svp = cx->blk_loop.itersave; \ SvREFCNT_dec(cursv); \ } /* given/when context */ struct block_givwhen { OP *leave_op; + SV *defsv_save; /* the original $_ */ }; -#define PUSHGIVEN(cx) \ +#define PUSHWHEN(cx) \ + cx->cx_old_savestack_ix = PL_savestack_ix; \ cx->blk_givwhen.leave_op = cLOGOP->op_other; -#define PUSHWHEN PUSHGIVEN +#define PUSHGIVEN(cx, orig_var) \ + PUSHWHEN(cx); \ + cx->blk_givwhen.defsv_save = orig_var; + +#define POPWHEN(cx) \ + NOOP; + +#define POPGIVEN(cx) \ + SvREFCNT_dec(GvSV(PL_defgv)); \ + GvSV(PL_defgv) = cx->blk_givwhen.defsv_save; + + +/* basic block, i.e. pp_enter/leave */ + +#define PUSHBASICBLK(cx) \ + cx->cx_old_savestack_ix = PL_savestack_ix; + +#define POPBASICBLK(cx) \ + NOOP; + /* context common to subroutines, evals and loops */ struct block { @@ -865,6 +887,7 @@ struct block { I32 blku_oldmarksp; /* mark stack index */ I32 blku_oldscopesp; /* scope stack index */ PMOP * blku_oldpm; /* values of pattern match vars */ + SSize_t blku_old_tmpsfloor; /* saved PL_tmps_floor */ union { struct block_sub blku_sub; @@ -889,12 +912,14 @@ struct block { #define DEBUG_CX(action) \ DEBUG_l( \ - Perl_deb(aTHX_ "CX %ld %s %s (scope %ld,%ld) at %s:%d\n", \ + Perl_deb(aTHX_ "CX %ld %s %s (scope %ld,%ld) (save %ld,%ld) at %s:%d\n",\ (long)cxstack_ix, \ action, \ PL_block_type[CxTYPE(&cxstack[cxstack_ix])], \ (long)PL_scopestack_ix, \ (long)(cxstack[cxstack_ix].blk_oldscopesp), \ + (long)PL_savestack_ix, \ + (long)(cxstack[cxstack_ix].cx_old_savestack_ix), \ __FILE__, __LINE__)); /* Enter a block. */ @@ -906,18 +931,23 @@ struct block { cx->blk_oldscopesp = PL_scopestack_ix, \ cx->blk_oldpm = PL_curpm, \ cx->blk_gimme = (U8)gimme; \ + cx->cx_u.cx_blk.blku_old_tmpsfloor = PL_tmps_floor; \ + PL_tmps_floor = PL_tmps_ix; \ DEBUG_CX("PUSH"); /* Exit a block (RETURN and LAST). */ -#define POPBLOCK(cx,pm) \ +#define POPBLOCK(cx) \ DEBUG_CX("POP"); \ - cx = &cxstack[cxstack_ix--], \ - newsp = PL_stack_base + cx->blk_oldsp, \ PL_curcop = cx->blk_oldcop, \ PL_markstack_ptr = PL_markstack + cx->blk_oldmarksp, \ PL_scopestack_ix = cx->blk_oldscopesp, \ - pm = cx->blk_oldpm, \ - gimme = cx->blk_gimme; + /* LEAVE_SCOPE() should have made this true. /(?{})/ cheats + * and leaves a CX entry lying around for repeated use, so + * skip for multicall */ \ + assert( (CxTYPE(cx) == CXt_SUB && CxMULTICALL(cx)) \ + || PL_savestack_ix == cx->cx_old_savestack_ix); \ + PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor; \ + PL_curpm = cx->blk_oldpm; /* Continue a block elsewhere (NEXT and REDO). */ #define TOPBLOCK(cx) \ @@ -933,7 +963,6 @@ struct subst { U8 sbu_type; /* what kind of context this is */ U8 sbu_rflags; U16 sbu_rxtainted; /* matches struct block */ - I32 sbu_oldsave; SSize_t sbu_iters; SSize_t sbu_maxiters; char * sbu_orig; @@ -948,7 +977,6 @@ struct subst { #define sb_iters cx_u.cx_subst.sbu_iters #define sb_maxiters cx_u.cx_subst.sbu_maxiters #define sb_rflags cx_u.cx_subst.sbu_rflags -#define sb_oldsave cx_u.cx_subst.sbu_oldsave #define sb_rxtainted cx_u.cx_subst.sbu_rxtainted #define sb_orig cx_u.cx_subst.sbu_orig #define sb_dstr cx_u.cx_subst.sbu_dstr @@ -961,10 +989,10 @@ struct subst { #ifdef PERL_CORE # define PUSHSUBST(cx) CXINC, cx = &cxstack[cxstack_ix], \ + cx->cx_old_savestack_ix = oldsave, \ cx->sb_iters = iters, \ cx->sb_maxiters = maxiters, \ cx->sb_rflags = r_flags, \ - cx->sb_oldsave = oldsave, \ cx->sb_rxtainted = rxtainted, \ cx->sb_orig = orig, \ cx->sb_dstr = dstr, \ @@ -979,7 +1007,7 @@ struct subst { (void)ReREFCNT_inc(rx); \ SvREFCNT_inc_void_NN(targ) -# define POPSUBST(cx) cx = &cxstack[cxstack_ix--]; \ +# define POPSUBST(cx) \ rxres_free(&cx->sb_rxres); \ ReREFCNT_dec(cx->sb_rx); \ SvREFCNT_dec_NN(cx->sb_targ) @@ -988,6 +1016,7 @@ struct subst { #define CxONCE(cx) ((cx)->cx_type & CXp_ONCE) struct context { + I32 cx_old_savestack_ix; /* saved PL_savestack_ix */ union { struct block cx_blk; struct subst cx_subst; @@ -998,7 +1027,7 @@ struct context { /* If you re-order these, there is also an array of uppercase names in perl.h and a static array of context names in pp_ctl.c */ #define CXTYPEMASK 0xf -#define CXt_NULL 0 +#define CXt_NULL 0 /* currently only used for sort BLOCK */ #define CXt_WHEN 1 #define CXt_BLOCK 2 /* When micro-optimising :-) keep GIVEN next to the LOOPs, as these 5 share a @@ -1017,14 +1046,9 @@ struct context { #define CXt_SUBST 11 /* SUBST doesn't feature in all switch statements. */ -/* private flags for CXt_SUB and CXt_NULL - However, this is checked in many places which do not check the type, so - this bit needs to be kept clear for most everything else. For reasons I - haven't investigated, it can coexist with CXp_FOR_DEF */ -#define CXp_MULTICALL 0x10 /* part of a multicall (so don't - tear down context on exit). */ - /* private flags for CXt_SUB and CXt_FORMAT */ +#define CXp_MULTICALL 0x10 /* part of a multicall (so don't tear down + context on exit). (not CXt_FORMAT) */ #define CXp_HASARGS 0x20 #define CXp_SUB_RE 0x40 /* code called within regex, i.e. (?{}) */ #define CXp_SUB_RE_FAKE 0x80 /* fake sub CX for (?{}) in current scope */ @@ -1045,8 +1069,7 @@ struct context { #define CxTYPE(c) ((c)->cx_type & CXTYPEMASK) #define CxTYPE_is_LOOP(c) (((c)->cx_type & 0xC) == 0x4) -#define CxMULTICALL(c) (((c)->cx_type & CXp_MULTICALL) \ - == CXp_MULTICALL) +#define CxMULTICALL(c) ((c)->cx_type & CXp_MULTICALL) #define CxREALEVAL(c) (((c)->cx_type & (CXTYPEMASK|CXp_REAL)) \ == (CXt_EVAL|CXp_REAL)) #define CxTRYBLOCK(c) (((c)->cx_type & (CXTYPEMASK|CXp_TRYBLOCK)) \ @@ -1262,7 +1285,7 @@ See L. PUSHSTACKi(PERLSI_MULTICALL); \ PUSHBLOCK(cx, (CXt_SUB|CXp_MULTICALL|flags), PL_stack_sp); \ PUSHSUB(cx); \ - cx->blk_sub.old_savestack_ix = PL_savestack_ix; \ + cx->cx_old_savestack_ix = PL_savestack_ix; \ SAVEVPTR(PL_op); \ if (!(flags & CXp_SUB_RE_FAKE)) \ CvDEPTH(cv)++; \ @@ -1272,6 +1295,7 @@ See L. } \ PAD_SET_CUR_NOSAVE(padlist, CvDEPTH(cv)); \ multicall_cv = cv; \ + PERL_UNUSED_VAR(multicall_cv); /* for API */ \ multicall_cop = CvSTART(cv); \ } STMT_END @@ -1284,13 +1308,14 @@ See L. #define POP_MULTICALL \ STMT_START { \ cx = &cxstack[cxstack_ix]; \ - CvDEPTH(multicall_cv) = cx->blk_sub.olddepth; \ - LEAVESUB(multicall_cv); \ - POPBLOCK(cx,PL_curpm); \ - /* includes partial unrolled POPSUB(): */ \ - LEAVE_SCOPE(cx->blk_sub.old_savestack_ix); \ - PL_comppad = cx->blk_sub.prevcomppad; \ - PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL; \ + CX_LEAVE_SCOPE(cx); \ + POPSUB_COMMON(cx); \ + newsp = PL_stack_base + cx->blk_oldsp; \ + gimme = cx->blk_gimme; \ + PERL_UNUSED_VAR(newsp); /* for API */ \ + PERL_UNUSED_VAR(gimme); /* for API */ \ + POPBLOCK(cx); \ + CX_POP(cx); \ POPSTACK; \ CATCH_SET(multicall_oldcatch); \ SPAGAIN; \ @@ -1305,21 +1330,10 @@ See L. CV * const cv = _nOnclAshIngNamE_; \ PADLIST * const padlist = CvPADLIST(cv); \ cx = &cxstack[cxstack_ix]; \ - assert(cx->cx_type & CXp_MULTICALL); \ - CvDEPTH(multicall_cv) = cx->blk_sub.olddepth; \ - LEAVESUB(multicall_cv); \ + assert(CxMULTICALL(cx)); \ + POPSUB_COMMON(cx); \ cx->cx_type = (CXt_SUB|CXp_MULTICALL|flags); \ - { \ - /* save a few things that we don't want PUSHSUB to zap */ \ - PAD * const prevcomppad = cx->blk_sub.prevcomppad; \ - SSize_t old_floor = cx->blk_sub.old_tmpsfloor; \ - SSize_t floor = PL_tmps_floor; \ - PUSHSUB(cx); \ - /* undo the stuff that PUSHSUB zapped */ \ - cx->blk_sub.prevcomppad = prevcomppad ; \ - cx->blk_sub.old_tmpsfloor = old_floor; \ - PL_tmps_floor = floor; \ - } \ + PUSHSUB(cx); \ if (!(flags & CXp_SUB_RE_FAKE)) \ CvDEPTH(cv)++; \ if (CvDEPTH(cv) >= 2) { \