/* 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;
/* 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;
GV * dfoutgv;
};
+/* free all savestack items back to the watermark of the specified context */
+
+#define CX_LEAVE_SCOPE(cx) \
+ LEAVE_SCOPE(cx->cx_u.cx_blk.blku_old_savestack_ix)
+
/* 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 */
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; \
+ cx->cx_u.cx_blk.blku_old_tmpsfloor = PL_tmps_floor; \
PL_tmps_floor = PL_tmps_ix;
#define PUSHSUB_GET_LVALUE_MASK(func) \
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; \
+ cx->cx_u.cx_blk.blku_old_savestack_ix = PL_savestack_ix; \
+ cx->cx_u.cx_blk.blku_old_tmpsfloor = PL_tmps_floor; \
PL_tmps_floor = PL_tmps_ix; \
SvREFCNT_inc_simple_void_NN(cv); \
CvDEPTH(cv)++; \
AvFILLp(ary) = -1; \
} STMT_END
-#define POPSUB(cx,sv) \
+#define POPSUB(cx) \
STMT_START { \
- LEAVE_SCOPE(cx->blk_sub.old_savestack_ix); \
+ CX_LEAVE_SCOPE(cx); \
if (!(cx->blk_u16 & CxPOPSUB_DONE)) { \
cx->blk_u16 |= CxPOPSUB_DONE; \
RETURN_PROBE(CvNAMED(cx->blk_sub.cv) \
} \
} \
} \
- 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); \
+ CvDEPTH((const CV*)cx->blk_sub.cv) = cx->blk_sub.olddepth; \
+ SvREFCNT_dec_NN(cx->blk_sub.cv); \
+ PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor; \
} STMT_END
#define POPFORMAT(cx) \
STMT_START { \
- LEAVE_SCOPE(cx->blk_format.old_savestack_ix); \
+ CX_LEAVE_SCOPE(cx); \
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; \
SvREFCNT_dec_NN(cx->blk_format.cv); \
SvREFCNT_dec_NN(dfuot); \
} \
+ PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor; \
} STMT_END
/* 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;
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; \
+ cx->cx_u.cx_blk.blku_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; \
#define POPEVAL(cx) \
STMT_START { \
+ CX_LEAVE_SCOPE(cx); \
PL_in_eval = CxOLD_IN_EVAL(cx); \
optype = CxOLD_OP_TYPE(cx); \
PL_eval_root = cx->blk_eval.old_eval_root; \
SvREFCNT_dec_NN(cx->blk_eval.cur_text); \
if (cx->blk_eval.old_namesv) \
sv_2mortal(cx->blk_eval.old_namesv); \
+ PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor; \
} STMT_END
/* loop context */
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 */
#endif
};
-#define CxITERVAR(c) \
- (CxPADLOOP(c) \
- ? (c)->blk_loop.itervar_u.svp \
- : (c)->blk_loop.itervar_u.svp \
- ? isGV((c)->blk_loop.itervar_u.gv) \
- ? &GvSV((c)->blk_loop.itervar_u.gv) \
- : (SV **)&(c)->blk_loop.itervar_u.gv \
- : (SV**)NULL)
+#define CxITERVAR(c) \
+ (CxPADLOOP(c) \
+ ? (c)->blk_loop.itervar_u.svp \
+ : ((c)->cx_type & CXp_FOR_GV) \
+ ? &GvSV((c)->blk_loop.itervar_u.gv) \
+ : (SV **)&(c)->blk_loop.itervar_u.gv)
#define CxLABEL(c) (0 + CopLABEL((c)->blk_oldcop))
#define CxLABEL_len(c,len) (0 + CopLABEL_len((c)->blk_oldcop, len))
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 = NULL;
+ cx->cx_u.cx_blk.blku_old_savestack_ix = PL_savestack_ix; \
+ cx->cx_u.cx_blk.blku_old_tmpsfloor = PL_tmps_floor; \
+ PL_tmps_floor = PL_tmps_ix; \
+ 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->cx_u.cx_blk.blku_old_savestack_ix = PL_savestack_ix; \
+ cx->cx_u.cx_blk.blku_old_tmpsfloor = PL_tmps_floor; \
+ PL_tmps_floor = PL_tmps_ix; \
+ cx->blk_loop.itersave = isave; \
PUSHLOOP_FOR_setpad(cx);
#define POPLOOP(cx) \
+ CX_LEAVE_SCOPE(cx); \
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); \
} \
- 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->cx_type & (CXp_FOR_PAD|CXp_FOR_GV)) { \
+ SV *cursv; \
+ 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; \
+ SvREFCNT_dec(cursv); \
+ } \
+ PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
/* given/when context */
struct block_givwhen {
OP *leave_op;
+ SV *defsv_save; /* the original $_ */
};
-#define PUSHGIVEN(cx) \
+#define PUSHWHEN(cx) \
+ cx->cx_u.cx_blk.blku_old_savestack_ix = PL_savestack_ix; \
+ cx->cx_u.cx_blk.blku_old_tmpsfloor = PL_tmps_floor; \
+ PL_tmps_floor = PL_tmps_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) \
+ CX_LEAVE_SCOPE(cx); \
+ PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
+
+#define POPGIVEN(cx) \
+ CX_LEAVE_SCOPE(cx); \
+ SvREFCNT_dec(GvSV(PL_defgv)); \
+ GvSV(PL_defgv) = cx->blk_givwhen.defsv_save; \
+ PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
+
+
+/* basic block, i.e. pp_enter/leave */
+
+#define PUSHBASICBLK(cx) \
+ cx->cx_u.cx_blk.blku_old_savestack_ix = PL_savestack_ix; \
+ cx->cx_u.cx_blk.blku_old_tmpsfloor = PL_tmps_floor; \
+ PL_tmps_floor = PL_tmps_ix;
+
+#define POPBASICBLK(cx) \
+ CX_LEAVE_SCOPE(cx); \
+ PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
+
/* context common to subroutines, evals and loops */
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 */
+ I32 blku_old_savestack_ix; /* saved PL_savestack_ix */
union {
struct block_sub blku_sub;
#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_u.cx_blk.blku_old_savestack_ix),\
__FILE__, __LINE__));
/* Enter a block. */
/* Exit a block (RETURN and LAST). */
#define POPBLOCK(cx,pm) \
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;
+ pm = cx->blk_oldpm;
/* Continue a block elsewhere (NEXT and REDO). */
#define TOPBLOCK(cx) \
/* private flags for CXt_LOOP */
#define CXp_FOR_DEF 0x10 /* foreach using $_ */
#define CXp_FOR_LVREF 0x20 /* foreach using \$var */
-#define CxPADLOOP(c) ((c)->blk_loop.my_op->op_targ)
+#define CXp_FOR_GV 0x40 /* foreach using package var */
+#define CXp_FOR_PAD 0x80 /* foreach using lexical var */
+#define CxPADLOOP(c) ((c)->cx_type & CXp_FOR_PAD)
/* private flags for CXt_SUBST */
#define CXp_ONCE 0x10 /* What was sbu_once in struct subst */
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_u.cx_blk.blku_old_savestack_ix = PL_savestack_ix; \
SAVEVPTR(PL_op); \
if (!(flags & CXp_SUB_RE_FAKE)) \
CvDEPTH(cv)++; \
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); \
+ CX_LEAVE_SCOPE(cx); \
PL_comppad = cx->blk_sub.prevcomppad; \
PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL; \
+ SvREFCNT_dec_NN(multicall_cv); \
+ /* these two set for backcompat by callers */ \
+ newsp = PL_stack_base + cx->blk_oldsp; \
+ gimme = cx->blk_gimme; \
+ POPBLOCK(cx,PL_curpm); \
+ cxstack_ix--; \
POPSTACK; \
CATCH_SET(multicall_oldcatch); \
SPAGAIN; \
cx = &cxstack[cxstack_ix]; \
assert(cx->cx_type & CXp_MULTICALL); \
CvDEPTH(multicall_cv) = cx->blk_sub.olddepth; \
- LEAVESUB(multicall_cv); \
+ SvREFCNT_dec_NN(multicall_cv); \
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 old_floor = cx->cx_u.cx_blk.blku_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; \
+ cx->cx_u.cx_blk.blku_old_tmpsfloor = old_floor; \
PL_tmps_floor = floor; \
} \
if (!(flags & CXp_SUB_RE_FAKE)) \