This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add itersave field to LOOP context struct
authorDavid Mitchell <davem@iabyn.com>
Wed, 19 Aug 2015 11:33:24 +0000 (12:33 +0100)
committerDavid Mitchell <davem@iabyn.com>
Wed, 3 Feb 2016 08:59:39 +0000 (08:59 +0000)
When entering a for loop, rather than saving the original loop variable on
the save stack, save it in the context struct. Quicker and simpler.

Note that as of this commit, entering a for loop no longer saves anything
on the save stack.

cop.h
pp_ctl.c

diff --git a/cop.h b/cop.h
index e22617c..e430201 100644 (file)
--- a/cop.h
+++ b/cop.h
@@ -761,6 +761,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 */
@@ -804,7 +805,8 @@ struct block_loop {
        cx->blk_loop.state_u.ary.ary = NULL;                            \
        cx->blk_loop.state_u.ary.ix = 0;                                \
         cx->blk_loop.old_savestack_ix = PL_savestack_ix;                \
-       cx->blk_loop.itervar_u.svp = NULL;
+       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
@@ -812,13 +814,14 @@ 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->blk_loop.old_savestack_ix = PL_savestack_ix;                \
+        cx->blk_loop.itersave = isave;                                  \
         PUSHLOOP_FOR_setpad(cx);
 
 #define POPLOOP(cx)                                                    \
@@ -827,8 +830,24 @@ struct block_loop {
            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->blk_loop.itersave) {                                    \
+            SV **svp = (cx)->blk_loop.itervar_u.svp;                    \
+            SV *cursv;                                                  \
+            if (isGV((GV*)svp)) {                                       \
+                svp = &GvSV((GV*)svp);                                  \
+                cursv = *svp;                                           \
+                *svp = cx->blk_loop.itersave;                           \
+                SvREFCNT_dec_NN(cx->blk_loop.itersave);                 \
+            }                                                           \
+            else {                                                      \
+                cursv = *svp;                                           \
+                *svp = cx->blk_loop.itersave;                           \
+            }                                                           \
+            /* delayed rc-- in case of "for $x (...) { return $x }" */  \
+            sv_2mortal(cursv);                                          \
+        }                                                               \
 
 /* given/when context */
 struct block_givwhen {
index ea8ad0e..1fc7ac5 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -2118,25 +2118,27 @@ PP(pp_enteriter)
     PERL_CONTEXT *cx;
     const I32 gimme = GIMME_V;
     void *itervar; /* location of the iteration variable */
+    SV   *itersave; /* the old var in the iterator var slot */
     U8 cxtype = CXt_LOOP_FOR;
 
     ENTER_with_name("loop1");
     SAVETMPS;
 
     if (PL_op->op_targ) {                       /* "my" variable */
+       itervar = &PAD_SVl(PL_op->op_targ);
        if (PL_op->op_private & OPpLVAL_INTRO) {        /* for my $x (...) */
             /* the SV currently in the pad slot is never live during
              * iteration (the slot is always aliased to one of the items)
              * so it's always stale */
-           SvPADSTALE_on(PAD_SVl(PL_op->op_targ));
+           SvPADSTALE_on(*(SV**)itervar);
        }
-       SAVEPADSVANDMORTALIZE(PL_op->op_targ);
-       itervar = &PAD_SVl(PL_op->op_targ);
+        itersave = SvREFCNT_inc(*(SV**)itervar);
+        assert(itersave);
     }
     else if (LIKELY(isGV(TOPs))) {             /* symbol table variable */
        GV * const gv = MUTABLE_GV(POPs);
        SV** svp = &GvSV(gv);
-       save_pushptrptr(gv, SvREFCNT_inc(*svp), SAVEt_GVSV);
+        itersave = SvREFCNT_inc(*svp);
        *svp = newSV(0);
        itervar = (void *)gv;
     }
@@ -2147,6 +2149,7 @@ PP(pp_enteriter)
        assert(SvMAGIC(sv)->mg_type == PERL_MAGIC_lvref);
        itervar = (void *)sv;
        cxtype |= CXp_FOR_LVREF;
+        itersave = NULL;
     }
 
     if (PL_op->op_private & OPpITER_DEF)
@@ -2155,7 +2158,7 @@ PP(pp_enteriter)
     ENTER_with_name("loop2");
 
     PUSHBLOCK(cx, cxtype, SP);
-    PUSHLOOP_FOR(cx, itervar, MARK);
+    PUSHLOOP_FOR(cx, itervar, itersave, MARK);
     if (PL_op->op_flags & OPf_STACKED) {
        SV *maybe_ary = POPs;
        if (SvTYPE(maybe_ary) != SVt_PVAV) {