This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
factor out common actions in TOPBLOCK and POPBLOCK
[perl5.git] / cop.h
diff --git a/cop.h b/cop.h
index 208223f..b7727d9 100644 (file)
--- a/cop.h
+++ b/cop.h
@@ -647,7 +647,7 @@ struct block_format {
        SvREFCNT_inc_void(cx->blk_format.dfoutgv)
 
 /* Restore old @_ */
-#define POP_SAVEARRAY()                                                \
+#define POP_SAVEARRAY(cx)                                              \
     STMT_START {                                                       \
         AV *av = GvAV(PL_defgv);                                        \
        GvAV(PL_defgv) = cx->blk_sub.savearray;                         \
@@ -686,10 +686,10 @@ struct block_format {
         assert(AvARRAY(MUTABLE_AV(                                      \
             PadlistARRAY(CvPADLIST(cx->blk_sub.cv))[                    \
                     CvDEPTH(cx->blk_sub.cv)])) == PL_curpad);           \
-        POP_SAVEARRAY();                                               \
-        /* abandon @_ if it got reified */                             \
+        POP_SAVEARRAY(cx);                                             \
         av = MUTABLE_AV(PAD_SVl(0));                                    \
         if (UNLIKELY(AvREAL(av)))                                      \
+            /* abandon @_ if it got reified */                         \
             clear_defarray(av, 0);                                      \
         else {                                                         \
             CLEAR_ARGARRAY(av);                                                \
@@ -835,19 +835,20 @@ struct block_loop {
         PUSHLOOP_FOR_setpad(cx);
 
 #define POPLOOP(cx)                                                    \
-       if (CxTYPE(cx) == CXt_LOOP_LAZYSV) {                            \
+       if (  CxTYPE(cx) == CXt_LOOP_ARY                                \
+           || CxTYPE(cx) == CXt_LOOP_LAZYSV)                            \
+        {                                                              \
+            /* Free ary or cur. This assumes that state_u.ary.ary       \
+             * aligns with state_u.lazysv.cur. See cx_dup() */          \
             SV *sv = cx->blk_loop.state_u.lazysv.cur;                   \
             cx->blk_loop.state_u.lazysv.cur = NULL;                     \
            SvREFCNT_dec_NN(sv);                                        \
-            sv = cx->blk_loop.state_u.lazysv.end;                       \
-            cx->blk_loop.state_u.lazysv.end = NULL;                     \
-           SvREFCNT_dec_NN(sv);                                        \
+            if (CxTYPE(cx) == CXt_LOOP_LAZYSV) {                        \
+                sv = cx->blk_loop.state_u.lazysv.end;                   \
+                cx->blk_loop.state_u.lazysv.end = NULL;                 \
+                SvREFCNT_dec_NN(sv);                                   \
+            }                                                           \
        }                                                               \
-       else if (CxTYPE(cx) == CXt_LOOP_ARY) {                          \
-            AV *av = cx->blk_loop.state_u.ary.ary;                      \
-            cx->blk_loop.state_u.ary.ary = NULL;                        \
-           SvREFCNT_dec(av);                                           \
-        }                                                               \
         if (cx->cx_type & (CXp_FOR_PAD|CXp_FOR_GV)) {                   \
             SV *cursv;                                                  \
             SV **svp = (cx)->blk_loop.itervar_u.svp;                    \
@@ -955,28 +956,31 @@ struct block {
         PL_tmps_floor           = PL_tmps_ix;                           \
        CX_DEBUG(cx, "PUSH");
 
+#define _POPBLOCK_COMMON(cx)                                           \
+       PL_markstack_ptr = PL_markstack + cx->blk_oldmarksp,            \
+       PL_scopestack_ix = cx->blk_oldscopesp,                          \
+       PL_curpm         = cx->blk_oldpm,
+
 /* Exit a block (RETURN and LAST). */
 #define POPBLOCK(cx)                                                   \
        CX_DEBUG(cx, "POP");                                            \
-       PL_curcop        = cx->blk_oldcop,                              \
-       PL_markstack_ptr = PL_markstack + cx->blk_oldmarksp,            \
-       PL_scopestack_ix = cx->blk_oldscopesp,                          \
+        _POPBLOCK_COMMON(cx)                                            \
         /* 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_curcop     = cx->blk_oldcop,                                 \
         PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;             \
-       PL_curpm         = cx->blk_oldpm;
 
-/* Continue a block elsewhere (NEXT and REDO). */
+/* Continue a block elsewhere (e.g. NEXT, REDO, GOTO).
+ * Whereas POPBLOCK restores the state to the point just before PUSHBLOCK
+ * was called,  TOPBLOCK restores it to the point just *after* PUSHBLOCK
+ * was called. */
 #define TOPBLOCK(cx)                                                   \
-       cx = CX_CUR();                                                  \
        CX_DEBUG(cx, "TOP");                                            \
-       PL_stack_sp      = PL_stack_base + cx->blk_oldsp,               \
-       PL_markstack_ptr = PL_markstack + cx->blk_oldmarksp,            \
-       PL_scopestack_ix = cx->blk_oldscopesp,                          \
-       PL_curpm         = cx->blk_oldpm;
+        _POPBLOCK_COMMON(cx)                                            \
+       PL_stack_sp      = PL_stack_base + cx->blk_oldsp;
 
 /* substitution context */
 struct subst {
@@ -984,7 +988,7 @@ struct subst {
     U8         sbu_rflags;
     U16                sbu_rxtainted;
     I32                sbu_oldsaveix; /* same as blku_oldsaveix */
-    /* all the fields above must be aligned with same-sized fields as blku * */
+    /* all the fields above must be aligned with same-sized fields as blk_u */
     SSize_t    sbu_iters;
     SSize_t    sbu_maxiters;
     char *     sbu_orig;
@@ -1064,11 +1068,11 @@ struct context {
 
 /* 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_ARY   4 /* for (@ary)     {} */
+#define CXt_LOOP_LAZYSV        5 /* for ('a'..'z') {} */
+#define CXt_LOOP_LAZYIV        6 /* for (1..9)     {} */
 #define CXt_LOOP_LIST  7 /* for (1,2,3)    {} */
-#define CXt_LOOP_ARY   8 /* for (@ary)     {} */
+#define CXt_LOOP_PLAIN 8 /*                {} */
 
 #define CXt_SUB                9
 #define CXt_FORMAT     10
@@ -1088,25 +1092,29 @@ struct context {
 #define CXp_TRYBLOCK   0x40    /* eval{}, not eval'' or similar */
 
 /* private flags for CXt_LOOP */
+
+/* this is only set in conjunction with CXp_FOR_GV */
 #define CXp_FOR_DEF    0x10    /* foreach using $_ */
+/* these 3 are mutually exclusive */
 #define CXp_FOR_LVREF  0x20    /* foreach using \$var */
 #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 */
 
 #define CxTYPE(c)      ((c)->cx_type & CXTYPEMASK)
-#define CxTYPE_is_LOOP(c) (   CxTYPE(cx) >= CXt_LOOP_PLAIN              \
-                           && CxTYPE(cx) <= CXt_LOOP_ARY)
+#define CxTYPE_is_LOOP(c) (   CxTYPE(cx) >= CXt_LOOP_ARY                \
+                           && CxTYPE(cx) <= CXt_LOOP_PLAIN)
 #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(cx) >= CXt_LOOP_LAZYSV               \
-                         && CxTYPE(cx) <= CXt_LOOP_ARY)
+#define CxFOREACH(c)   (   CxTYPE(cx) >= CXt_LOOP_ARY                  \
+                         && CxTYPE(cx) <= CXt_LOOP_LIST)
 
 #define CXINC (cxstack_ix < cxstack_max ? ++cxstack_ix : (cxstack_ix = cxinc()))