This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
pp_given: avoid using savestack for old var
[perl5.git] / cop.h
diff --git a/cop.h b/cop.h
index 04e4d76..d455478 100644 (file)
--- a/cop.h
+++ b/cop.h
@@ -551,11 +551,11 @@ be zero.
 struct block_sub {
     OP *       retop;  /* op to execute on exit from sub */
     /* Above here is the same for sub, format and eval.  */
+    PAD                *prevcomppad; /* the caller's PL_comppad */
     CV *       cv;
     /* Above here is the same for sub and format.  */
-    AV *       savearray;
     I32                olddepth;
-    PAD                *prevcomppad; /* the caller's PL_comppad */
+    AV         *savearray;
 };
 
 
@@ -563,11 +563,11 @@ struct block_sub {
 struct block_format {
     OP *       retop;  /* op to execute on exit from sub */
     /* Above here is the same for sub, format and eval.  */
+    PAD                *prevcomppad; /* the caller's PL_comppad */
     CV *       cv;
     /* Above here is the same for sub and format.  */
     GV *       gv;
     GV *       dfoutgv;
-    PAD                *prevcomppad; /* the caller's PL_comppad */
 };
 
 /* base for the next two macros. Don't use directly.
@@ -587,7 +587,9 @@ 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);
+        SvREFCNT_inc_simple_void_NN(cv);                                \
+        cx->cx_u.cx_blk.blku_old_tmpsfloor = PL_tmps_floor;             \
+        PL_tmps_floor = PL_tmps_ix;
 
 #define PUSHSUB_GET_LVALUE_MASK(func) \
        /* If the context is indeterminate, then only the lvalue */     \
@@ -620,6 +622,9 @@ struct block_format {
        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;                                     \
        SvREFCNT_inc_simple_void_NN(cv);                                \
        CvDEPTH(cv)++;                                                  \
        SvREFCNT_inc_void(cx->blk_format.dfoutgv)
@@ -643,7 +648,7 @@ struct block_format {
 
 #define POPSUB(cx,sv)                                                  \
     STMT_START {                                                       \
-       const I32 olddepth = cx->blk_sub.olddepth;                      \
+       LEAVE_SCOPE(cx->cx_u.cx_blk.blku_old_savestack_ix);             \
         if (!(cx->blk_u16 & CxPOPSUB_DONE)) {                           \
         cx->blk_u16 |= CxPOPSUB_DONE;                                   \
        RETURN_PROBE(CvNAMED(cx->blk_sub.cv)                            \
@@ -654,30 +659,25 @@ struct block_format {
                CopSTASHPV((COP*)CvSTART((const CV*)cx->blk_sub.cv)));  \
                                                                        \
        if (CxHASARGS(cx)) {                                            \
-            AV *av = MUTABLE_AV(PAD_SVl(0));                            \
+            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 */                          \
-           if (AvREAL(av)) {                                           \
-               const SSize_t fill = AvFILLp(av);                       \
-               SvREFCNT_dec_NN(av);                                    \
-                av = newAV();                                           \
-               av_extend(av, fill);                                    \
-               AvREIFY_only(av);                                       \
-                PAD_SVl(0) = MUTABLE_SV(av);                            \
-           }                                                           \
+            av = MUTABLE_AV(PAD_SVl(0));                                \
+           if (UNLIKELY(AvREAL(av)))                                   \
+                clear_defarray(av, 0);                                  \
            else {                                                      \
                CLEAR_ARGARRAY(av);                                     \
            }                                                           \
        }                                                               \
         }                                                               \
-       sv = MUTABLE_SV(cx->blk_sub.cv);                                \
-       LEAVE_SCOPE(PL_scopestack[cx->blk_oldscopesp-1]);               \
+        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;    \
-        CvDEPTH((const CV*)sv) = olddepth;                              \
+       sv = MUTABLE_SV(cx->blk_sub.cv);                                \
+        CvDEPTH((const CV*)sv) = cx->blk_sub.olddepth;                  \
     } STMT_END
 
 #define LEAVESUB(sv)                                                   \
@@ -687,12 +687,13 @@ struct block_format {
 
 #define POPFORMAT(cx)                                                  \
     STMT_START {                                                       \
+       LEAVE_SCOPE(cx->cx_u.cx_blk.blku_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->cx_u.cx_blk.blku_old_tmpsfloor;             \
        setdefout(dfuot);                                               \
-       LEAVE_SCOPE(PL_scopestack[cx->blk_oldscopesp-1]);               \
         PL_comppad = cx->blk_format.prevcomppad;                        \
         PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL;    \
        --CvDEPTH(cv);                                                  \
@@ -724,6 +725,8 @@ 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->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;  \
@@ -751,6 +754,7 @@ struct block_loop {
        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 */
@@ -770,14 +774,12 @@ struct block_loop {
 #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))
@@ -793,7 +795,9 @@ 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.itervar_u.svp = NULL;
+        cx->cx_u.cx_blk.blku_old_savestack_ix = PL_savestack_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
@@ -801,31 +805,54 @@ struct block_loop {
 #  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->blk_loop.itersave = isave;                                  \
         PUSHLOOP_FOR_setpad(cx);
 
 #define POPLOOP(cx)                                                    \
+       LEAVE_SCOPE(cx->cx_u.cx_blk.blku_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);           \
        }                                                               \
-       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);                                        \
+        }
 
 /* given/when context */
 struct block_givwhen {
        OP *leave_op;
+        SV *defsv_save; /* the original $_ */
 };
 
-#define PUSHGIVEN(cx)                                                  \
+#define PUSHWHEN(cx)                                                   \
        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;
+
 
 /* context common to subroutines, evals and loops */
 struct block {
@@ -837,6 +864,8 @@ 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;
@@ -861,12 +890,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_u.cx_blk.blku_old_savestack_ix),\
                    __FILE__, __LINE__));
 
 /* Enter a block. */
@@ -1008,7 +1039,9 @@ struct context {
 /* 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 */
@@ -1227,13 +1260,13 @@ See L<perlcall/LIGHTWEIGHT CALLBACKS>.
        CV * const _nOnclAshIngNamE_ = the_cv;                          \
        CV * const cv = _nOnclAshIngNamE_;                              \
        PADLIST * const padlist = CvPADLIST(cv);                        \
-       ENTER;                                                          \
        multicall_oldcatch = CATCH_GET;                                 \
-       SAVETMPS; SAVEVPTR(PL_op);                                      \
        CATCH_SET(TRUE);                                                \
        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;        \
+       SAVEVPTR(PL_op);                                                \
         if (!(flags & CXp_SUB_RE_FAKE))                                 \
             CvDEPTH(cv)++;                                             \
        if (CvDEPTH(cv) >= 2) {                                         \
@@ -1258,12 +1291,11 @@ See L<perlcall/LIGHTWEIGHT CALLBACKS>.
         LEAVESUB(multicall_cv);                                        \
        POPBLOCK(cx,PL_curpm);                                          \
         /* includes partial unrolled POPSUB(): */                       \
-       LEAVE_SCOPE(PL_scopestack[cx->blk_oldscopesp-1]);               \
+       LEAVE_SCOPE(cx->cx_u.cx_blk.blku_old_savestack_ix);             \
         PL_comppad = cx->blk_sub.prevcomppad;                           \
         PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL;    \
        POPSTACK;                                                       \
        CATCH_SET(multicall_oldcatch);                                  \
-       LEAVE;                                                          \
        SPAGAIN;                                                        \
     } STMT_END
 
@@ -1275,14 +1307,22 @@ See L<perlcall/LIGHTWEIGHT CALLBACKS>.
        CV * const _nOnclAshIngNamE_ = the_cv;                          \
        CV * const cv = _nOnclAshIngNamE_;                              \
        PADLIST * const padlist = CvPADLIST(cv);                        \
-        PAD * const prevcomppad = cx->blk_sub.prevcomppad;              \
        cx = &cxstack[cxstack_ix];                                      \
        assert(cx->cx_type & CXp_MULTICALL);                            \
        CvDEPTH(multicall_cv) = cx->blk_sub.olddepth;                   \
         LEAVESUB(multicall_cv);                                                \
        cx->cx_type = (CXt_SUB|CXp_MULTICALL|flags);                    \
-       PUSHSUB(cx);                                                    \
-        cx->blk_sub.prevcomppad = prevcomppad ; /* undo PUSHSUB */      \
+        {                                                               \
+            /* 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;                                      \
+        }                                                               \
         if (!(flags & CXp_SUB_RE_FAKE))                                 \
             CvDEPTH(cv)++;                                             \
        if (CvDEPTH(cv) >= 2) {                                         \