/* 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)
+#define CX_LEAVE_SCOPE(cx) LEAVE_SCOPE(cx->blk_oldsaveix)
+
+#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
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->cx_u.cx_blk.blku_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 */ \
cx->blk_format.dfoutgv = PL_defoutgv; \
cx->blk_format.prevcomppad = PL_comppad; \
cx->blk_u16 = 0; \
- 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_oldsaveix = PL_savestack_ix; \
SvREFCNT_inc_simple_void_NN(cv); \
CvDEPTH(cv)++; \
SvREFCNT_inc_void(cx->blk_format.dfoutgv)
STMT_START { \
AV *av = GvAV(PL_defgv); \
GvAV(PL_defgv) = cx->blk_sub.savearray; \
+ cx->blk_sub.savearray = NULL; \
SvREFCNT_dec(av); \
} STMT_END
AvFILLp(ary) = -1; \
} STMT_END
-#define POPSUB(cx,sv) \
+
+/* subsets of POPSUB */
+
+#define POPSUB_COMMON(cx) \
+ STMT_START { \
+ CV *cv; \
+ PL_comppad = cx->blk_sub.prevcomppad; \
+ PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL; \
+ cv = cx->blk_sub.cv; \
+ CvDEPTH(cv) = cx->blk_sub.olddepth; \
+ cx->blk_sub.cv = NULL; \
+ SvREFCNT_dec(cv); \
+ } STMT_END
+
+/* 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 { \
- CX_LEAVE_SCOPE(cx); \
- if (!(cx->blk_u16 & CxPOPSUB_DONE)) { \
- cx->blk_u16 |= CxPOPSUB_DONE; \
RETURN_PROBE(CvNAMED(cx->blk_sub.cv) \
? HEK_KEY(CvNAME_HEK(cx->blk_sub.cv)) \
: GvENAME(CvGV(cx->blk_sub.cv)), \
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->cx_u.cx_blk.blku_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 { \
- 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->cx_u.cx_blk.blku_old_tmpsfloor; \
- setdefout(dfuot); \
+ CV *cv; \
+ GV * const dfout = cx->blk_format.dfoutgv; \
+ setdefout(dfout); \
+ cx->blk_format.dfoutgv = NULL; \
+ SvREFCNT_dec_NN(dfout); /* the cx->defoutgv ref */ \
PL_comppad = cx->blk_format.prevcomppad; \
PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL; \
+ cv = cx->blk_format.cv; \
+ cx->blk_format.cv = NULL;; \
--CvDEPTH(cv); \
- SvREFCNT_dec_NN(cx->blk_format.cv); \
- SvREFCNT_dec_NN(dfuot); \
- } \
+ SvREFCNT_dec_NN(cv); \
} STMT_END
/* eval context */
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->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; \
cx->blk_eval.cur_text = PL_parser ? PL_parser->linestr : NULL; \
- cx->blk_eval.cv = NULL; /* set by doeval(), as applicable */ \
+ cx->blk_eval.cv = NULL; /* set by doeval_compile() as applicable */ \
cx->blk_eval.retop = NULL; \
cx->blk_eval.cur_top_env = PL_top_env; \
} STMT_END
#define POPEVAL(cx) \
STMT_START { \
- CX_LEAVE_SCOPE(cx); \
+ SV *sv; \
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); \
- if (cx->blk_eval.old_namesv) \
- sv_2mortal(cx->blk_eval.old_namesv); \
+ sv = cx->blk_eval.cur_text; \
+ if (sv && SvSCREAM(sv)) { \
+ cx->blk_eval.cur_text = NULL; \
+ SvREFCNT_dec_NN(sv); \
+ } \
+ sv = cx->blk_eval.old_namesv; \
+ if (sv && !SvTEMP(sv))/* TEMP => POPEVAL re-entrantly called */ \
+ sv_2mortal(sv); \
} STMT_END
/* loop context */
struct block_loop {
- I32 resetsp;
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 */
} 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 */
- IV ix;
+ struct { /* CXt_LOOP_ARY, C<for (@ary)> */
+ AV *ary; /* array being iterated over */
+ IV ix; /* index relative to base of array */
} ary;
- struct { /* valid if type is LOOP_LAZYIV */
+ struct { /* CXt_LOOP_LIST, C<for (list)> */
+ I32 basesp; /* first element of list on stack */
+ IV ix; /* index relative to basesp */
+ } stack;
+ struct { /* CXt_LOOP_LAZYIV, C<for (1..9)> */
IV cur;
IV end;
} lazyiv;
- struct { /* valid if type if LOOP_LAZYSV */
+ struct { /* CXt_LOOP_LAZYSV C<for ('a'..'z')> */
SV * cur;
SV * end; /* maxiumum value (or minimum in reverse) */
} lazysv;
#define CxLABEL_len_flags(c,len,flags) (0 + CopLABEL_len_flags((c)->blk_oldcop, len, flags))
#define CxHASARGS(c) (((c)->cx_type & CXp_HASARGS) == CXp_HASARGS)
#define CxLVAL(c) (0 + ((c)->blk_u16 & 0xff))
-/* POPSUB has already been performed on this context frame */
-#define CxPOPSUB_DONE 0x100
-#define PUSHLOOP_PLAIN(cx, s) \
- cx->blk_loop.resetsp = s - PL_stack_base; \
+#define PUSHLOOP_PLAIN(cx) \
cx->blk_loop.my_op = cLOOP; \
- cx->blk_loop.state_u.ary.ary = NULL; \
- cx->blk_loop.state_u.ary.ix = 0; \
- 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;
+ cx->blk_oldsaveix = PL_savestack_ix;
#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, isave, s) \
- cx->blk_loop.resetsp = s - PL_stack_base; \
+#define PUSHLOOP_FOR(cx, ivar, isave) \
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_oldsaveix = PL_savestack_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); \
} \
- else if (CxTYPE(cx) == CXt_LOOP_FOR) \
+ else if (CxTYPE(cx) == CXt_LOOP_ARY) \
SvREFCNT_dec(cx->blk_loop.state_u.ary.ary); \
if (cx->cx_type & (CXp_FOR_PAD|CXp_FOR_GV)) { \
SV *cursv; \
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 {
};
#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_oldsaveix = PL_savestack_ix; \
cx->blk_givwhen.leave_op = cLOGOP->op_other;
#define PUSHGIVEN(cx, orig_var) \
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;
+ NOOP;
#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;
+ GvSV(PL_defgv) = cx->blk_givwhen.defsv_save;
/* 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;
+ cx->blk_oldsaveix = PL_savestack_ix;
#define POPBASICBLK(cx) \
- CX_LEAVE_SCOPE(cx); \
- PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
+ NOOP;
/* context common to subroutines, evals and loops */
U8 blku_type; /* what kind of context this is */
U8 blku_gimme; /* is this block running in list context? */
U16 blku_u16; /* used by block_sub and block_eval (so far) */
- I32 blku_oldsp; /* stack pointer to copy stuff down to */
- COP * blku_oldcop; /* old curcop pointer */
+ I32 blku_oldsaveix; /* saved PL_savestack_ix */
+ /* all the fields above must be aligned with same-sized fields as sbu */
+ I32 blku_oldsp; /* current sp floor: where nextstate pops to */
I32 blku_oldmarksp; /* mark stack index */
- I32 blku_oldscopesp; /* scope stack index */
+ COP * blku_oldcop; /* old curcop pointer */
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 */
+ I32 blku_oldscopesp; /* scope stack index */
union {
struct block_sub blku_sub;
#define blk_oldpm cx_u.cx_blk.blku_oldpm
#define blk_gimme cx_u.cx_blk.blku_gimme
#define blk_u16 cx_u.cx_blk.blku_u16
+#define blk_oldsaveix cx_u.cx_blk.blku_oldsaveix
#define blk_sub cx_u.cx_blk.blk_u.blku_sub
#define blk_format cx_u.cx_blk.blk_u.blku_format
#define blk_eval cx_u.cx_blk.blk_u.blku_eval
(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),\
+ (long)(cxstack[cxstack_ix].blk_oldsaveix), \
__FILE__, __LINE__));
/* Enter a 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--], \
PL_curcop = cx->blk_oldcop, \
PL_markstack_ptr = PL_markstack + cx->blk_oldmarksp, \
PL_scopestack_ix = cx->blk_oldscopesp, \
- pm = cx->blk_oldpm;
+ /* 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->blk_oldsaveix); \
+ 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) \
/* substitution context */
struct subst {
- U8 sbu_type; /* what kind of context this is */
+ U8 sbu_type; /* same as blku_type */
U8 sbu_rflags;
- U16 sbu_rxtainted; /* matches struct block */
- I32 sbu_oldsave;
+ U16 sbu_rxtainted;
+ I32 sbu_oldsaveix; /* same as blku_oldsaveix */
+ /* all the fields above must be aligned with same-sized fields as blku * */
SSize_t sbu_iters;
SSize_t sbu_maxiters;
char * sbu_orig;
#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
#ifdef PERL_CORE
# define PUSHSUBST(cx) CXINC, cx = &cxstack[cxstack_ix], \
+ cx->blk_oldsaveix = 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, \
(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)
/* 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
The first 4 don't have a 'case' in at least one switch statement in pp_ctl.c
*/
#define CXt_GIVEN 3
-/* This is first so that CXt_LOOP_FOR|CXt_LOOP_LAZYIV is CXt_LOOP_LAZYIV */
-#define CXt_LOOP_FOR 4
-#define CXt_LOOP_PLAIN 5
-#define CXt_LOOP_LAZYSV 6
-#define CXt_LOOP_LAZYIV 7
-#define CXt_SUB 8
-#define CXt_FORMAT 9
-#define CXt_EVAL 10
-#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). */
+/* be careful of the ordering of these five. Macros like CxTYPE_is_LOOP,
+ * CxFOREACH compare ranges */
+#define CXt_LOOP_PLAIN 4 /* {} */
+#define CXt_LOOP_LAZYIV 5 /* for (1..9) {} */
+#define CXt_LOOP_LAZYSV 6 /* for ('a'..'z') {} */
+#define CXt_LOOP_LIST 7 /* for (1,2,3) {} */
+#define CXt_LOOP_ARY 8 /* for (@ary) {} */
+
+#define CXt_SUB 9
+#define CXt_FORMAT 10
+#define CXt_EVAL 11
+#define CXt_SUBST 12
+/* SUBST doesn't feature in all switch statements. */
/* 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 */
#define CXp_ONCE 0x10 /* What was sbu_once in struct subst */
#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 CxTYPE_is_LOOP(c) ( CxTYPE(cx) >= CXt_LOOP_PLAIN \
+ && CxTYPE(cx) <= CXt_LOOP_ARY)
+#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)) \
== (CXt_EVAL|CXp_TRYBLOCK))
-#define CxFOREACH(c) (CxTYPE_is_LOOP(c) && CxTYPE(c) != CXt_LOOP_PLAIN)
-#define CxFOREACHDEF(c) ((CxTYPE_is_LOOP(c) && CxTYPE(c) != CXt_LOOP_PLAIN) \
- && ((c)->cx_type & CXp_FOR_DEF))
+#define CxFOREACH(c) ( CxTYPE(cx) >= CXt_LOOP_LAZYSV \
+ && CxTYPE(cx) <= CXt_LOOP_ARY)
#define CXINC (cxstack_ix < cxstack_max ? ++cxstack_ix : (cxstack_ix = cxinc()))
PUSHSTACKi(PERLSI_MULTICALL); \
PUSHBLOCK(cx, (CXt_SUB|CXp_MULTICALL|flags), PL_stack_sp); \
PUSHSUB(cx); \
- cx->cx_u.cx_blk.blku_old_savestack_ix = PL_savestack_ix; \
+ cx->blk_oldsaveix = PL_savestack_ix; \
SAVEVPTR(PL_op); \
if (!(flags & CXp_SUB_RE_FAKE)) \
CvDEPTH(cv)++; \
} \
PAD_SET_CUR_NOSAVE(padlist, CvDEPTH(cv)); \
multicall_cv = cv; \
+ PERL_UNUSED_VAR(multicall_cv); /* for API */ \
multicall_cop = CvSTART(cv); \
} STMT_END
#define POP_MULTICALL \
STMT_START { \
cx = &cxstack[cxstack_ix]; \
- CvDEPTH(multicall_cv) = cx->blk_sub.olddepth; \
- LEAVESUB(multicall_cv); \
- POPBLOCK(cx,PL_curpm); \
- /* these two set for backcompat by callers */ \
+ CX_LEAVE_SCOPE(cx); \
+ POPSUB_COMMON(cx); \
newsp = PL_stack_base + cx->blk_oldsp; \
gimme = cx->blk_gimme; \
- /* includes partial unrolled POPSUB(): */ \
- CX_LEAVE_SCOPE(cx); \
- PL_comppad = cx->blk_sub.prevcomppad; \
- PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL; \
+ PERL_UNUSED_VAR(newsp); /* for API */ \
+ PERL_UNUSED_VAR(gimme); /* for API */ \
+ POPBLOCK(cx); \
+ CX_POP(cx); \
POPSTACK; \
CATCH_SET(multicall_oldcatch); \
SPAGAIN; \
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->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->cx_u.cx_blk.blku_old_tmpsfloor = old_floor; \
- PL_tmps_floor = floor; \
- } \
+ PUSHSUB(cx); \
if (!(flags & CXp_SUB_RE_FAKE)) \
CvDEPTH(cv)++; \
if (CvDEPTH(cv) >= 2) { \