This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Make remaining context types avoid ENTER/LEAVE
authorDavid Mitchell <davem@iabyn.com>
Fri, 28 Aug 2015 15:11:50 +0000 (16:11 +0100)
committerDavid Mitchell <davem@iabyn.com>
Wed, 3 Feb 2016 08:59:40 +0000 (08:59 +0000)
Previous commits have made the 'subbish' context types like SUB, EVAL
use the context stack to save the old values of PL_savestack_ix and
PL_tmps_floor rather than using ENTER/SAVETMPS/LEAVE; extend this
to the remaining contexts types; specifically loops, bare blocks and
given/when.

Note that this means that during context stack unwinding (e.g. in
dounwind()), LEAVE_SCOPE() is called for every context popped, whereas
before it was only done for each subbish context type.

This makes the ordering of the actions in scope unwinding match much more
closely the reverse order in which things were done during scope pushing;
for example entering and leaving a for loop will now do:

    PUSHLOOP_FOR();
    ...
    ... code within loop which pushes stuff on the savestack
    ...
    LEAVE_SCOPE(); /* pops the stuff from above */
    POPLOOP();

The main reason for this commit (apart from increased consistency)
is that its a lot faster.

cop.h
pp_ctl.c
pp_hot.c

diff --git a/cop.h b/cop.h
index d455478..afaea1a 100644 (file)
--- a/cop.h
+++ b/cop.h
@@ -796,6 +796,8 @@ struct block_loop {
        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;
 
@@ -812,6 +814,8 @@ struct block_loop {
        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_loop.itersave = isave;                                  \
         PUSHLOOP_FOR_setpad(cx);
 
@@ -831,7 +835,8 @@ struct block_loop {
             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 {
@@ -840,6 +845,9 @@ 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_givwhen.leave_op = cLOGOP->op_other;
 
 #define PUSHGIVEN(cx, orig_var)                                         \
@@ -847,11 +855,14 @@ struct block_givwhen {
         cx->blk_givwhen.defsv_save = orig_var;
 
 #define POPWHEN(cx)                                                     \
-        NOOP;
+        LEAVE_SCOPE(cx->cx_u.cx_blk.blku_old_savestack_ix);             \
+        PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
 
 #define POPGIVEN(cx)                                                    \
+        LEAVE_SCOPE(cx->cx_u.cx_blk.blku_old_savestack_ix);             \
         SvREFCNT_dec(GvSV(PL_defgv));                                   \
-        GvSV(PL_defgv) = cx->blk_givwhen.defsv_save;
+        GvSV(PL_defgv) = cx->blk_givwhen.defsv_save;                    \
+        PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
 
 
 /* context common to subroutines, evals and loops */
index e400c57..518b755 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -1519,6 +1519,8 @@ Perl_dounwind(pTHX_ I32 cxix)
            break;
        case CXt_EVAL:
            POPEVAL(cx);
+            /* FALLTHROUGH */
+       case CXt_BLOCK:
             LEAVE_SCOPE(cx->cx_u.cx_blk.blku_old_savestack_ix);
             PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
            break;
@@ -2060,10 +2062,10 @@ PP(pp_enter)
     PERL_CONTEXT *cx;
     I32 gimme = GIMME_V;
 
-    ENTER_with_name("block");
-
-    SAVETMPS;
     PUSHBLOCK(cx, CXt_BLOCK, SP);
+    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;
 
     RETURN;
 }
@@ -2090,9 +2092,10 @@ PP(pp_leave)
         : leave_common(newsp, SP, newsp, gimme, SVs_PADTMP|SVs_TEMP,
                                PL_op->op_private & OPpLVALUE);
 
-    PL_curpm = newpm;  /* Don't pop $1 et al till now */
+    LEAVE_SCOPE(cx->cx_u.cx_blk.blku_old_savestack_ix);
+    PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
 
-    LEAVE_with_name("block");
+    PL_curpm = newpm;  /* Don't pop $1 et al till now */
 
     RETURN;
 }
@@ -2128,9 +2131,6 @@ PP(pp_enteriter)
     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 */
        itervarp = &PAD_SVl(PL_op->op_targ);
         itersave = *(SV**)itervarp;
@@ -2168,8 +2168,6 @@ PP(pp_enteriter)
     if (PL_op->op_private & OPpITER_DEF)
        cxtype |= CXp_FOR_DEF;
 
-    ENTER_with_name("loop2");
-
     PUSHBLOCK(cx, cxtype, SP);
     PUSHLOOP_FOR(cx, itervarp, itersave, MARK);
     if (PL_op->op_flags & OPf_STACKED) {
@@ -2246,10 +2244,6 @@ PP(pp_enterloop)
     PERL_CONTEXT *cx;
     const I32 gimme = GIMME_V;
 
-    ENTER_with_name("loop1");
-    SAVETMPS;
-    ENTER_with_name("loop2");
-
     PUSHBLOCK(cx, CXt_LOOP_PLAIN, SP);
     PUSHLOOP_PLAIN(cx, SP);
 
@@ -2279,9 +2273,6 @@ PP(pp_leaveloop)
     POPLOOP(cx);       /* Stack values are safe: release loop vars ... */
     PL_curpm = newpm;  /* ... and pop $1 et al */
 
-    LEAVE_with_name("loop2");
-    LEAVE_with_name("loop1");
-
     return NORMAL;
 }
 
@@ -2578,11 +2569,9 @@ PP(pp_last)
     TAINT_NOT;
     PL_stack_sp = newsp;
 
-    LEAVE_with_name("loop2");
     cxstack_ix--;
     /* Stack values are safe: */
     POPLOOP(cx);       /* release loop vars ... */
-    LEAVE_with_name("loop1");
     PL_curpm = newpm;  /* ... and pop $1 et al */
 
     PERL_UNUSED_VAR(gimme);
@@ -2592,15 +2581,10 @@ PP(pp_last)
 PP(pp_next)
 {
     PERL_CONTEXT *cx;
-    const I32 inner = PL_scopestack_ix;
 
     S_unwind_loop(aTHX_ "next");
 
-    /* clear off anything above the scope we're re-entering, but
-     * save the rest until after a possible continue block */
     TOPBLOCK(cx);
-    if (PL_scopestack_ix < inner)
-       leave_scope(PL_scopestack[PL_scopestack_ix]);
     PL_curcop = cx->blk_oldcop;
     PERL_ASYNC_CHECK();
     return (cx)->blk_loop.my_op->op_nextop;
@@ -2610,7 +2594,6 @@ PP(pp_redo)
 {
     const I32 cxix = S_unwind_loop(aTHX_ "redo");
     PERL_CONTEXT *cx;
-    I32 oldsave;
     OP* redo_op = cxstack[cxix].blk_loop.my_op->op_redoop;
 
     if (redo_op->op_type == OP_ENTER) {
@@ -2621,8 +2604,7 @@ PP(pp_redo)
     }
 
     TOPBLOCK(cx);
-    oldsave = PL_scopestack[PL_scopestack_ix - 1];
-    LEAVE_SCOPE(oldsave);
+    LEAVE_SCOPE(cx->cx_u.cx_blk.blku_old_savestack_ix);
     FREETMPS;
     PL_curcop = cx->blk_oldcop;
     PERL_ASYNC_CHECK();
@@ -3051,14 +3033,10 @@ PP(pp_goto)
        /* pop unwanted frames */
 
        if (ix < cxstack_ix) {
-           I32 oldsave;
-
            if (ix < 0)
                DIE(aTHX_ "panic: docatch: illegal ix=%ld", (long)ix);
            dounwind(ix);
            TOPBLOCK(cx);
-           oldsave = PL_scopestack[PL_scopestack_ix];
-           LEAVE_SCOPE(oldsave);
        }
 
        /* push wanted frames */
@@ -4419,9 +4397,6 @@ PP(pp_entergiven)
     SV *origsv = DEFSV;
     SV *newsv = POPs;
     
-    ENTER_with_name("given");
-    SAVETMPS;
-
     assert(!PL_op->op_targ); /* used to be set for lexical $_ */
     GvSV(PL_defgv) = SvREFCNT_inc(newsv);
 
@@ -4450,7 +4425,6 @@ PP(pp_leavegiven)
 
     PL_curpm = newpm;  /* Don't pop $1 et al till now */
 
-    LEAVE_with_name("given");
     RETURN;
 }
 
@@ -5003,9 +4977,6 @@ PP(pp_enterwhen)
     if ((0 == (PL_op->op_flags & OPf_SPECIAL)) && !SvTRUEx(POPs))
        RETURNOP(cLOGOP->op_other->op_next);
 
-    ENTER_with_name("when");
-    SAVETMPS;
-
     PUSHBLOCK(cx, CXt_WHEN, SP);
     PUSHWHEN(cx);
 
@@ -5037,8 +5008,6 @@ PP(pp_leavewhen)
 
     PL_curpm = newpm;   /* pop $1 et al */
 
-    LEAVE_with_name("when");
-
     if (cxix < cxstack_ix)
         dounwind(cxix);
 
@@ -5082,11 +5051,11 @@ PP(pp_continue)
     
     POPBLOCK(cx,newpm);
     assert(CxTYPE(cx) == CXt_WHEN);
+    POPWHEN(cx);
 
     SP = newsp;
     PL_curpm = newpm;   /* pop $1 et al */
 
-    LEAVE_with_name("when");
     RETURNOP(cx->blk_givwhen.leave_op->op_next);
 }
 
index 6568ca1..fce942b 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -240,13 +240,21 @@ PP(pp_cond_expr)
 
 PP(pp_unstack)
 {
+    PERL_CONTEXT *cx;
     PERL_ASYNC_CHECK();
     TAINT_NOT;         /* Each statement is presumed innocent */
-    PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
+    cx  = &cxstack[cxstack_ix];
+    PL_stack_sp = PL_stack_base + cx->blk_oldsp;
     FREETMPS;
     if (!(PL_op->op_flags & OPf_SPECIAL)) {
-       I32 oldsave = PL_scopestack[PL_scopestack_ix - 1];
-       LEAVE_SCOPE(oldsave);
+        assert(
+               CxTYPE(cx) == CXt_BLOCK
+            || CxTYPE(cx) == CXt_LOOP_FOR
+            || CxTYPE(cx) == CXt_LOOP_PLAIN
+            || CxTYPE(cx) == CXt_LOOP_LAZYSV
+            || CxTYPE(cx) == CXt_LOOP_LAZYIV
+        );
+        LEAVE_SCOPE(cx->cx_u.cx_blk.blku_old_savestack_ix);
     }
     return NORMAL;
 }