$VERSION++ for all the non-dual life modules in ext/ that
[p5sagit/p5-mst-13.2.git] / cop.h
diff --git a/cop.h b/cop.h
index 5dee181..272dbcc 100644 (file)
--- a/cop.h
+++ b/cop.h
@@ -407,7 +407,7 @@ struct block_eval {
 #define CxOLD_IN_EVAL(cx)      (((cx)->blk_u16) & 0x7F)
 #define CxOLD_OP_TYPE(cx)      (((cx)->blk_u16) >> 7)
 
-#define PUSHEVAL(cx,n,fgv)                                             \
+#define PUSHEVAL(cx,n)                                                 \
     STMT_START {                                                       \
        assert(!(PL_in_eval & ~0x7F));                                  \
        assert(!(PL_op->op_type & ~0x1FF));                             \
@@ -436,57 +436,45 @@ struct block_loop {
     /* (except for non_ithreads we need to modify next_op in pp_ctl.c, hence
        why next_op is conditionally defined below.)  */
 #ifdef USE_ITHREADS
-    void *     iterdata;
-    PAD                *oldcomppad;
+    PAD                *oldcomppad; /* Also used for the GV, if targoffset is 0 */
+    /* This is also accesible via cx->blk_loop.my_op->op_targ */
+    PADOFFSET  targoffset;
 #else
     OP *       next_op;
     SV **      itervar;
 #endif
-    SV *       itersave;
-    /* (from inspection of source code) for a .. range of strings this is the
-       current string.  */
-    SV *       iterlval;
-    /* (from inspection of source code) for a foreach loop this is the array
-       being iterated over. For a .. range of numbers it's the current value.
-       A check is often made on the SvTYPE of iterary to determine whether
-       we are iterating over an array or a range. (numbers or strings)  */
-    AV *       iterary;
-    IV         iterix;
-    /* (from inspection of source code) for a .. range of numbers this is the
-       maximum value.  */
-    IV         itermax;
+    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;
+       } ary;
+       struct { /* valid if type is LOOP_LAZYIV */
+           IV cur;
+           IV end;
+       } lazyiv;
+       struct { /* valid if type if LOOP_LAZYSV */
+           SV * cur;
+           SV * end; /* maxiumum value (or minimum in reverse) */
+       } lazysv;
+    } state_u;
 };
-/* It might be possible to squeeze this structure further. As best I can tell
-   itermax and iterlval are never used at the same time, so it might be possible
-   to make them into a union. However, I'm not confident that there are enough
-   flag bits/NULLable pointers in this structure alone to encode which is
-   active. There is, however, U8 of space free in struct block, which could be
-   used. Right now it may not be worth squeezing this structure further, as it's
-   the largest part of struct block, and currently struct block is 64 bytes on
-   an ILP32 system, which will give good cache alignment.
-*/
 
 #ifdef USE_ITHREADS
 #  define CxITERVAR(c)                                                 \
-       ((c)->blk_loop.iterdata                                         \
-        ? (CxPADLOOP(cx)                                               \
-           ? &CX_CURPAD_SV( (c)->blk_loop,                             \
-                   INT2PTR(PADOFFSET, (c)->blk_loop.iterdata))         \
-           : &GvSV((GV*)(c)->blk_loop.iterdata))                       \
+       ((c)->blk_loop.oldcomppad                                       \
+        ? (CxPADLOOP(c)                                                \
+           ? &CX_CURPAD_SV( (c)->blk_loop, (c)->blk_loop.targoffset )  \
+           : &GvSV((GV*)(c)->blk_loop.oldcomppad))                     \
         : (SV**)NULL)
-#  define CX_ITERDATA_SET(cx,idata)                                    \
-       CX_CURPAD_SAVE(cx->blk_loop);                                   \
-       if ((cx->blk_loop.iterdata = (idata)))                          \
-           cx->blk_loop.itersave = SvREFCNT_inc(*CxITERVAR(cx));       \
+#  define CX_ITERDATA_SET(cx,idata,o)                                  \
+       if ((cx->blk_loop.targoffset = (o)))                            \
+           CX_CURPAD_SAVE(cx->blk_loop);                               \
        else                                                            \
-           cx->blk_loop.itersave = NULL;
+           cx->blk_loop.oldcomppad = (idata);
 #else
 #  define CxITERVAR(c)         ((c)->blk_loop.itervar)
-#  define CX_ITERDATA_SET(cx,ivar)                                     \
-       if ((cx->blk_loop.itervar = (SV**)(ivar)))                      \
-           cx->blk_loop.itersave = SvREFCNT_inc(*CxITERVAR(cx));       \
-       else                                                            \
-           cx->blk_loop.itersave = NULL;
+#  define CX_ITERDATA_SET(cx,ivar,o)                                   \
+       cx->blk_loop.itervar = (SV**)(ivar);
 #endif
 #define CxLABEL(c)     (0 + (c)->blk_oldcop->cop_label)
 #define CxHASARGS(c)   (((c)->cx_type & CXp_HASARGS) == CXp_HASARGS)
@@ -500,29 +488,29 @@ struct block_loop {
 #  define CX_LOOP_NEXTOP_GET(cx)       ((cx)->blk_loop.next_op + 0)
 #endif
 
-#define PUSHLOOP(cx, dat, s)                                           \
+#define PUSHLOOP_PLAIN(cx, s)                                          \
+       cx->blk_loop.resetsp = s - PL_stack_base;                       \
+       cx->blk_loop.my_op = cLOOP;                                     \
+       PUSHLOOP_OP_NEXT;                                               \
+       cx->blk_loop.state_u.ary.ary = NULL;                            \
+       cx->blk_loop.state_u.ary.ix = 0;                                \
+       CX_ITERDATA_SET(cx, NULL, 0);
+
+#define PUSHLOOP_FOR(cx, dat, s, offset)                               \
        cx->blk_loop.resetsp = s - PL_stack_base;                       \
        cx->blk_loop.my_op = cLOOP;                                     \
        PUSHLOOP_OP_NEXT;                                               \
-       cx->blk_loop.iterlval = NULL;                                   \
-       cx->blk_loop.iterary = NULL;                                    \
-       cx->blk_loop.iterix = -1;                                       \
-       CX_ITERDATA_SET(cx,dat);
+       cx->blk_loop.state_u.ary.ary = NULL;                            \
+       cx->blk_loop.state_u.ary.ix = 0;                                \
+       CX_ITERDATA_SET(cx, dat, offset);
 
 #define POPLOOP(cx)                                                    \
-       SvREFCNT_dec(cx->blk_loop.iterlval);                            \
-       if (CxITERVAR(cx)) {                                            \
-            if (SvPADMY(cx->blk_loop.itersave)) {                      \
-               SV ** const s_v_p = CxITERVAR(cx);                      \
-               sv_2mortal(*s_v_p);                                     \
-               *s_v_p = cx->blk_loop.itersave;                         \
-           }                                                           \
-           else {                                                      \
-               SvREFCNT_dec(cx->blk_loop.itersave);                    \
-           }                                                           \
+       if (CxTYPE(cx) == CXt_LOOP_LAZYSV) {                            \
+           SvREFCNT_dec(cx->blk_loop.state_u.lazysv.cur);              \
+           SvREFCNT_dec(cx->blk_loop.state_u.lazysv.end);              \
        }                                                               \
-       if (cx->blk_loop.iterary && cx->blk_loop.iterary != PL_curstack)\
-           SvREFCNT_dec(cx->blk_loop.iterary);
+       if (CxTYPE(cx) == CXt_LOOP_FOR)                                 \
+           SvREFCNT_dec(cx->blk_loop.state_u.ary.ary);
 
 /* given/when context */
 struct block_givwhen {
@@ -601,11 +589,10 @@ struct block {
 /* substitution context */
 struct subst {
     U8         sbu_type;       /* what kind of context this is */
-    U8         sbu_once;       /* Actually both booleans, but U8/U16 */
+    U8         sbu_rflags;
     U16                sbu_rxtainted;  /* matches struct block */
     I32                sbu_iters;
     I32                sbu_maxiters;
-    I32                sbu_rflags;
     I32                sbu_oldsave;
     char *     sbu_orig;
     SV *       sbu_dstr;
@@ -636,7 +623,6 @@ struct subst {
        cx->sb_maxiters         = maxiters,                             \
        cx->sb_rflags           = r_flags,                              \
        cx->sb_oldsave          = oldsave,                              \
-       cx->sb_once             = once,                                 \
        cx->sb_rxtainted        = rxtainted,                            \
        cx->sb_orig             = orig,                                 \
        cx->sb_dstr             = dstr,                                 \
@@ -646,10 +632,12 @@ struct subst {
        cx->sb_strend           = strend,                               \
        cx->sb_rxres            = NULL,                                 \
        cx->sb_rx               = rx,                                   \
-       cx->cx_type             = CXt_SUBST;                            \
+       cx->cx_type             = CXt_SUBST | (once ? CXp_ONCE : 0);    \
        rxres_save(&cx->sb_rxres, rx);                                  \
        (void)ReREFCNT_inc(rx)
 
+#define CxONCE(cx)             ((cx)->cx_type & CXp_ONCE)
+
 #define POPSUBST(cx) cx = &cxstack[cxstack_ix--];                      \
        rxres_free(&cx->sb_rxres);                                      \
        ReREFCNT_dec(cx->sb_rx)
@@ -662,53 +650,62 @@ struct context {
 };
 #define cx_type cx_u.cx_subst.sbu_type
 
+/* 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_SUB                1
-#define CXt_EVAL       2
-#define CXt_LOOP       3
-#define CXt_SUBST      4
-#define CXt_BLOCK      5
-#define CXt_FORMAT     6
-#define CXt_GIVEN      7
-#define CXt_WHEN       8
+#define CXt_WHEN       1
+#define CXt_BLOCK      2
+/* When micro-optimising :-) keep GIVEN next to the LOOPs, as these 5 share a
+   jump table in pp_ctl.c
+   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  0x0000040       /* part of a multicall (so don't
-                                          tear down context on exit). */ 
+#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_HASARGS    0x00000020
+#define CXp_HASARGS    0x20
 
 /* private flags for CXt_EVAL */
-#define CXp_REAL       0x00000010      /* truly eval'', not a lookalike */
-#define CXp_TRYBLOCK   0x00000020      /* eval{}, not eval'' or similar */
+#define CXp_REAL       0x20    /* truly eval'', not a lookalike */
+#define CXp_TRYBLOCK   0x40    /* eval{}, not eval'' or similar */
 
 /* private flags for CXt_LOOP */
-#define CXp_FOREACH    0x00000020      /* a foreach loop */
-#define CXp_FOR_DEF    0x00000040      /* foreach using $_ */
+#define CXp_FOR_DEF    0x10    /* foreach using $_ */
 #ifdef USE_ITHREADS
-#  define CXp_PADVAR   0x00000010      /* itervar lives on pad, iterdata
-                                          has pad offset; if not set,
-                                          iterdata holds GV* */
-#  define CxPADLOOP(c) (((c)->cx_type & (CXt_LOOP|CXp_PADVAR))         \
-                        == (CXt_LOOP|CXp_PADVAR))
+#  define CxPADLOOP(c) ((c)->blk_loop.targoffset)
 #endif
 
+/* 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)      (((c)->cx_type & 0xC) == 0x4)
 #define CxMULTICALL(c) (((c)->cx_type & CXp_MULTICALL)                 \
                         == 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)   (((c)->cx_type & (CXTYPEMASK|CXp_FOREACH))      \
-                         == (CXt_LOOP|CXp_FOREACH))
-#define CxFOREACHDEF(c)        (((c)->cx_type & (CXTYPEMASK|CXp_FOREACH|CXp_FOR_DEF))\
-                        == (CXt_LOOP|CXp_FOREACH|CXp_FOR_DEF))
+#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 CXINC (cxstack_ix < cxstack_max ? ++cxstack_ix : (cxstack_ix = cxinc()))