This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
eliminate weird gimme calc in pp_leave()
[perl5.git] / pp_ctl.c
index 4286d6f..ebc5c71 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -1452,8 +1452,10 @@ S_dopoptoloop(pTHX_ I32 startingblock)
     return i;
 }
 
+/* find the next GIVEN or FOR loop context block */
+
 STATIC I32
-S_dopoptogiven(pTHX_ I32 startingblock)
+S_dopoptogivenfor(pTHX_ I32 startingblock)
 {
     I32 i;
     for (i = startingblock; i >= 0; i--) {
@@ -1462,7 +1464,7 @@ S_dopoptogiven(pTHX_ I32 startingblock)
        default:
            continue;
        case CXt_GIVEN:
-           DEBUG_l( Perl_deb(aTHX_ "(dopoptogiven(): found given at cx=%ld)\n", (long)i));
+           DEBUG_l( Perl_deb(aTHX_ "(dopoptogivenfor(): found given at cx=%ld)\n", (long)i));
            return i;
        case CXt_LOOP_PLAIN:
            assert(!CxFOREACHDEF(cx));
@@ -1471,7 +1473,7 @@ S_dopoptogiven(pTHX_ I32 startingblock)
        case CXt_LOOP_LAZYSV:
        case CXt_LOOP_FOR:
            if (CxFOREACHDEF(cx)) {
-               DEBUG_l( Perl_deb(aTHX_ "(dopoptogiven(): found foreach at cx=%ld)\n", (long)i));
+               DEBUG_l( Perl_deb(aTHX_ "(dopoptogivenfor(): found foreach at cx=%ld)\n", (long)i));
                return i;
            }
        }
@@ -1505,7 +1507,6 @@ Perl_dounwind(pTHX_ I32 cxix)
        return;
 
     while (cxstack_ix > cxix) {
-       SV *sv;
         PERL_CONTEXT *cx = &cxstack[cxstack_ix];
        DEBUG_CX("UNWIND");                                             \
        /* Note: we don't need to restore the base context info till the end. */
@@ -1514,13 +1515,14 @@ Perl_dounwind(pTHX_ I32 cxix)
            POPSUBST(cx);
            continue;  /* not break */
        case CXt_SUB:
-           POPSUB(cx,sv);
-           LEAVESUB(sv);
+           POPSUB(cx);
            break;
        case CXt_EVAL:
            POPEVAL(cx);
-            LEAVE_SCOPE(cx->blk_eval.old_savestack_ix);
-            PL_tmps_floor = cx->blk_eval.old_tmpsfloor;
+            PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
+           break;
+       case CXt_BLOCK:
+            POPBASICBLK(cx);
            break;
        case CXt_LOOP_LAZYIV:
        case CXt_LOOP_LAZYSV:
@@ -1528,6 +1530,12 @@ Perl_dounwind(pTHX_ I32 cxix)
        case CXt_LOOP_PLAIN:
            POPLOOP(cx);
            break;
+       case CXt_WHEN:
+           POPWHEN(cx);
+           break;
+       case CXt_GIVEN:
+           POPGIVEN(cx);
+           break;
        case CXt_NULL:
            break;
        case CXt_FORMAT:
@@ -1569,7 +1577,6 @@ Perl_die_unwind(pTHX_ SV *msv)
 
     if (in_eval) {
        I32 cxix;
-       I32 gimme;
 
        /*
         * Historically, perl used to set ERRSV ($@) early in the die
@@ -1622,6 +1629,7 @@ Perl_die_unwind(pTHX_ SV *msv)
            SV *namesv;
            PERL_CONTEXT *cx;
            SV **newsp;
+            I32 gimme;
 #ifdef DEBUGGING
            COP *oldcop;
 #endif
@@ -1631,7 +1639,16 @@ Perl_die_unwind(pTHX_ SV *msv)
            if (cxix < cxstack_ix)
                dounwind(cxix);
 
-           POPBLOCK(cx,PL_curpm);
+            cx = &cxstack[cxstack_ix];
+            assert(CxTYPE(cx) == CXt_EVAL);
+            newsp = PL_stack_base + cx->blk_oldsp;
+            gimme = cx->blk_gimme;
+
+           if (gimme == G_SCALAR)
+               *++newsp = &PL_sv_undef;
+           PL_stack_sp = newsp;
+
+
            if (CxTYPE(cx) != CXt_EVAL) {
                STRLEN msglen;
                const char* message = SvPVx_const(exceptsv, msglen);
@@ -1639,6 +1656,8 @@ Perl_die_unwind(pTHX_ SV *msv)
                PerlIO_write(Perl_error_log, message, msglen);
                my_exit(1);
            }
+
+           POPBLOCK(cx,PL_curpm);
            POPEVAL(cx);
            namesv = cx->blk_eval.old_namesv;
 #ifdef DEBUGGING
@@ -1647,12 +1666,7 @@ Perl_die_unwind(pTHX_ SV *msv)
            restartjmpenv = cx->blk_eval.cur_top_env;
            restartop = cx->blk_eval.retop;
 
-           if (gimme == G_SCALAR)
-               *++newsp = &PL_sv_undef;
-           PL_stack_sp = newsp;
-
-            LEAVE_SCOPE(cx->blk_eval.old_savestack_ix);
-            PL_tmps_floor = cx->blk_eval.old_tmpsfloor;
+            PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
 
            if (optype == OP_REQUIRE) {
                 assert (PL_curcop == oldcop);
@@ -1974,7 +1988,7 @@ PP(pp_dbstate)
            PUSHBLOCK(cx, CXt_SUB, SP);
            PUSHSUB_DB(cx);
            cx->blk_sub.retop = PL_op->op_next;
-            cx->blk_sub.old_savestack_ix = PL_savestack_ix;
+            cx->cx_u.cx_blk.blku_old_savestack_ix = PL_savestack_ix;
 
             SAVEI32(PL_debug);
             PL_debug = 0;
@@ -2054,10 +2068,8 @@ PP(pp_enter)
     PERL_CONTEXT *cx;
     I32 gimme = GIMME_V;
 
-    ENTER_with_name("block");
-
-    SAVETMPS;
     PUSHBLOCK(cx, CXt_BLOCK, SP);
+    PUSHBASICBLK(cx);
 
     RETURN;
 }
@@ -2075,17 +2087,20 @@ PP(pp_leave)
        cx->blk_oldpm = PL_curpm;       /* fake block should preserve $1 et al */
     }
 
-    POPBLOCK(cx,newpm);
-
-    gimme = OP_GIMME(PL_op, (cxstack_ix >= 0) ? gimme : G_SCALAR);
+    cx = &cxstack[cxstack_ix];
+    assert(CxTYPE(cx) == CXt_BLOCK);
+    newsp = PL_stack_base + cx->blk_oldsp;
+    gimme = cx->blk_gimme;
 
     SP = (gimme == G_VOID)
         ? newsp
         : 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_with_name("block");
+    POPBLOCK(cx,newpm);
+    POPBASICBLK(cx);
+
+    PL_curpm = newpm;  /* Don't pop $1 et al till now */
 
     RETURN;
 }
@@ -2117,45 +2132,49 @@ PP(pp_enteriter)
     dSP; dMARK;
     PERL_CONTEXT *cx;
     const I32 gimme = GIMME_V;
-    void *itervar; /* location of the iteration variable */
+    void *itervarp; /* GV or pad slot 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 */
+       itervarp = &PAD_SVl(PL_op->op_targ);
+        itersave = *(SV**)itervarp;
+        assert(itersave);
        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(itersave);
        }
-       SAVEPADSVANDMORTALIZE(PL_op->op_targ);
-       itervar = &PAD_SVl(PL_op->op_targ);
-    }
-    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);
-       *svp = newSV(0);
-       itervar = (void *)gv;
+        SvREFCNT_inc_simple_void_NN(itersave);
+       cxtype |= CXp_FOR_PAD;
     }
     else {
        SV * const sv = POPs;
-       assert(SvTYPE(sv) == SVt_PVMG);
-       assert(SvMAGIC(sv));
-       assert(SvMAGIC(sv)->mg_type == PERL_MAGIC_lvref);
-       itervar = (void *)sv;
-       cxtype |= CXp_FOR_LVREF;
+       itervarp = (void *)sv;
+        if (LIKELY(isGV(sv))) {                /* symbol table variable */
+            SV** svp = &GvSV(sv);
+            itersave = *svp;
+            if (LIKELY(itersave))
+                SvREFCNT_inc_simple_void_NN(itersave);
+            else
+                *svp = newSV(0);
+            cxtype |= CXp_FOR_GV;
+        }
+        else {                          /* LV ref: for \$foo (...) */
+            assert(SvTYPE(sv) == SVt_PVMG);
+            assert(SvMAGIC(sv));
+            assert(SvMAGIC(sv)->mg_type == PERL_MAGIC_lvref);
+            itersave = NULL;
+            cxtype |= CXp_FOR_LVREF;
+        }
     }
 
     if (PL_op->op_private & OPpITER_DEF)
        cxtype |= CXp_FOR_DEF;
 
-    ENTER_with_name("loop2");
-
     PUSHBLOCK(cx, cxtype, SP);
-    PUSHLOOP_FOR(cx, itervar, MARK);
+    PUSHLOOP_FOR(cx, itervarp, itersave, MARK);
     if (PL_op->op_flags & OPf_STACKED) {
        SV *maybe_ary = POPs;
        if (SvTYPE(maybe_ary) != SVt_PVAV) {
@@ -2230,10 +2249,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);
 
@@ -2249,10 +2264,11 @@ PP(pp_leaveloop)
     PMOP *newpm;
     SV **mark;
 
-    POPBLOCK(cx,newpm);
+    cx = &cxstack[cxstack_ix];
     assert(CxTYPE_is_LOOP(cx));
-    mark = newsp;
+    mark = PL_stack_base + cx->blk_oldsp;
     newsp = PL_stack_base + cx->blk_loop.resetsp;
+    gimme = cx->blk_gimme;
 
     SP = (gimme == G_VOID)
         ? newsp
@@ -2260,12 +2276,10 @@ PP(pp_leaveloop)
                               PL_op->op_private & OPpLVALUE);
     PUTBACK;
 
+    POPBLOCK(cx,newpm);
     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;
 }
 
@@ -2286,19 +2300,21 @@ PP(pp_leavesublv)
     PMOP *newpm;
     I32 gimme;
     PERL_CONTEXT *cx;
-    SV *sv;
     bool ref;
     const char *what = NULL;
 
-    if (CxMULTICALL(&cxstack[cxstack_ix])) {
+    cx = &cxstack[cxstack_ix];
+    assert(CxTYPE(cx) == CXt_SUB);
+
+    if (CxMULTICALL(cx)) {
         /* entry zero of a stack is always PL_sv_undef, which
          * simplifies converting a '()' return into undef in scalar context */
         assert(PL_stack_sp > PL_stack_base || *PL_stack_base == &PL_sv_undef);
        return 0;
     }
 
-    POPBLOCK(cx,newpm);
-    cxstack_ix++; /* preserve cx entry on stack for use by POPSUB */
+    newsp = PL_stack_base + cx->blk_oldsp;
+    gimme = cx->blk_gimme;
     TAINT_NOT;
 
     mark = newsp + 1;
@@ -2306,7 +2322,6 @@ PP(pp_leavesublv)
     ref = !!(CxLVAL(cx) & OPpENTERSUB_INARGS);
     if (gimme == G_SCALAR) {
        if (CxLVAL(cx) && !ref) {     /* Leave it as it is if we can. */
-           SV *sv;
            if (MARK <= SP) {
                if ((SvPADTMP(TOPs) || SvREADONLY(TOPs)) &&
                    !SvSMAGICAL(TOPs)) {
@@ -2321,10 +2336,9 @@ PP(pp_leavesublv)
                what = "undef";
            }
           croak:
-           POPSUB(cx,sv);
+           POPSUB(cx);
            cxstack_ix--;
-           PL_curpm = newpm;
-           LEAVESUB(sv);
+           PL_curpm = cx->blk_oldpm;
            Perl_croak(aTHX_
                      "Can't return %s from lvalue subroutine", what
            );
@@ -2391,10 +2405,11 @@ PP(pp_leavesublv)
     }
     PUTBACK;
 
-    POPSUB(cx,sv);     /* Stack values are safe: release CV and @_ ... */
+    POPBLOCK(cx,newpm);
+    cxstack_ix++; /* preserve cx entry on stack for use by POPSUB */
+    POPSUB(cx);        /* Stack values are safe: release CV and @_ ... */
     cxstack_ix--;
     PL_curpm = newpm;  /* ... and pop $1 et al */
-    LEAVESUB(sv);
 
     return cx->blk_sub.retop;
 }
@@ -2464,21 +2479,21 @@ PP(pp_return)
          * we need to set sp = oldsp so that pp_leavesub knows to push
          * &PL_sv_undef onto the stack.
          */
-    SV **oldsp;
-    cx = &cxstack[cxix];
-    oldsp = PL_stack_base + cx->blk_oldsp;
-    if (oldsp != MARK) {
-        SSize_t nargs = SP - MARK;
-        if (nargs) {
-            if (cx->blk_gimme == G_ARRAY) {
-                /* shift return args to base of call stack frame */
-                Move(MARK + 1, oldsp + 1, nargs, SV*);
-                PL_stack_sp  = oldsp + nargs;
+        SV **oldsp;
+        cx = &cxstack[cxix];
+        oldsp = PL_stack_base + cx->blk_oldsp;
+        if (oldsp != MARK) {
+            SSize_t nargs = SP - MARK;
+            if (nargs) {
+                if (cx->blk_gimme == G_ARRAY) {
+                    /* shift return args to base of call stack frame */
+                    Move(MARK + 1, oldsp + 1, nargs, SV*);
+                    PL_stack_sp  = oldsp + nargs;
+                }
             }
+            else
+                PL_stack_sp  = oldsp;
         }
-        else
-            PL_stack_sp  = oldsp;
-    }
     }
 
     /* fall through to a normal exit */
@@ -2541,9 +2556,7 @@ S_unwind_loop(pTHX_ const char * const opname)
 PP(pp_last)
 {
     PERL_CONTEXT *cx;
-    I32 gimme;
     OP *nextop = NULL;
-    SV **newsp;
     PMOP *newpm;
 
     S_unwind_loop(aTHX_ "last");
@@ -2556,35 +2569,26 @@ PP(pp_last)
         || CxTYPE(cx) == CXt_LOOP_FOR
         || CxTYPE(cx) == CXt_LOOP_PLAIN
     );
-    newsp = PL_stack_base + cx->blk_loop.resetsp;
+    PL_stack_sp = PL_stack_base + cx->blk_loop.resetsp;
     nextop = cx->blk_loop.my_op->op_lastop->op_next;
 
     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);
     return nextop;
 }
 
 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;
@@ -2594,7 +2598,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) {
@@ -2605,8 +2608,7 @@ PP(pp_redo)
     }
 
     TOPBLOCK(cx);
-    oldsave = PL_scopestack[PL_scopestack_ix - 1];
-    LEAVE_SCOPE(oldsave);
+    CX_LEAVE_SCOPE(cx);
     FREETMPS;
     PL_curcop = cx->blk_oldcop;
     PERL_ASYNC_CHECK();
@@ -2761,7 +2763,7 @@ PP(pp_goto)
                 SvREFCNT_inc_NN(sv_2mortal(MUTABLE_SV(arg)));
 
            assert(PL_scopestack_ix == cx->blk_oldscopesp);
-            LEAVE_SCOPE(cx->blk_sub.old_savestack_ix);
+            CX_LEAVE_SCOPE(cx);
 
            if (CxTYPE(cx) == CXt_SUB && CxHASARGS(cx)) {
                AV* av = MUTABLE_AV(PAD_SVl(0));
@@ -2806,15 +2808,10 @@ PP(pp_goto)
 
            /* Now do some callish stuff. */
            if (CvISXSUB(cv)) {
-               SV **newsp;
-               I32 gimme;
                const SSize_t items = arg ? AvFILL(arg) + 1 : 0;
                const bool m = arg ? cBOOL(SvRMAGICAL(arg)) : 0;
                SV** mark;
 
-                PERL_UNUSED_VAR(newsp);
-                PERL_UNUSED_VAR(gimme);
-
                 ENTER;
                 SAVETMPS;
                 SAVEFREESV(cv); /* later, undo the 'avoid premature free' hack */
@@ -3035,14 +3032,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 */
@@ -3425,7 +3418,6 @@ S_doeval(pTHX_ int gimme, CV* outside, U32 seq, HV *hh)
     yystatus = (!in_require && CATCH_GET) ? S_try_yyparse(aTHX_ GRAMPROG) : yyparse(GRAMPROG);
 
     if (yystatus || PL_parser->error_count || !PL_eval_root) {
-       SV **newsp;                     /* Used by POPBLOCK. */
        PERL_CONTEXT *cx;
        I32 optype;                     /* Used by POPEVAL. */
        SV *namesv;
@@ -3433,7 +3425,6 @@ S_doeval(pTHX_ int gimme, CV* outside, U32 seq, HV *hh)
 
        cx = NULL;
        namesv = NULL;
-       PERL_UNUSED_VAR(newsp);
        PERL_UNUSED_VAR(optype);
 
        /* note that if yystatus == 3, then the EVAL CX block has already
@@ -3449,8 +3440,7 @@ S_doeval(pTHX_ int gimme, CV* outside, U32 seq, HV *hh)
            POPEVAL(cx);
            namesv = cx->blk_eval.old_namesv;
            /* POPBLOCK has rendered LEAVE_with_name("evalcomp") unnecessary */
-            LEAVE_SCOPE(cx->blk_eval.old_savestack_ix);
-            PL_tmps_floor = cx->blk_eval.old_tmpsfloor;
+            PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
        }
 
        errsv = ERRSV;
@@ -4101,7 +4091,7 @@ PP(pp_require)
     /* switch to eval mode */
     PUSHBLOCK(cx, CXt_EVAL, SP);
     PUSHEVAL(cx, name);
-    cx->blk_eval.old_savestack_ix = old_savestack_ix;
+    cx->cx_u.cx_blk.blku_old_savestack_ix = old_savestack_ix;
     cx->blk_eval.retop = PL_op->op_next;
 
     SAVECOPLINE(&PL_compiling);
@@ -4217,7 +4207,7 @@ PP(pp_entereval)
 
     PUSHBLOCK(cx, (CXt_EVAL|CXp_REAL), SP);
     PUSHEVAL(cx, 0);
-    cx->blk_eval.old_savestack_ix = old_savestack_ix;
+    cx->cx_u.cx_blk.blku_old_savestack_ix = old_savestack_ix;
     cx->blk_eval.retop = PL_op->op_next;
 
     /* prepare to compile string */
@@ -4276,14 +4266,20 @@ PP(pp_leaveeval)
     bool keep = cBOOL(PL_in_eval & EVAL_KEEPERR);
 
     PERL_ASYNC_CHECK();
+
+    cx = &cxstack[cxstack_ix];
+    assert(CxTYPE(cx) == CXt_EVAL);
+    newsp = PL_stack_base + cx->blk_oldsp;
+    gimme = cx->blk_gimme;
+
+    if (gimme != G_VOID)
+        SP = leave_common(newsp, SP, newsp, gimme, SVs_TEMP, FALSE);
     POPBLOCK(cx,newpm);
     POPEVAL(cx);
     namesv = cx->blk_eval.old_namesv;
     retop = cx->blk_eval.retop;
     evalcv = cx->blk_eval.cv;
 
-    if (gimme != G_VOID)
-        SP = leave_common(newsp, SP, newsp, gimme, SVs_TEMP, FALSE);
     PL_curpm = newpm;  /* Don't pop $1 et al till now */
 
 #ifdef DEBUGGING
@@ -4299,15 +4295,13 @@ PP(pp_leaveeval)
                        SvPVX_const(namesv),
                         SvUTF8(namesv) ? -(I32)SvCUR(namesv) : (I32)SvCUR(namesv),
                        G_DISCARD);
-        LEAVE_SCOPE(cx->blk_eval.old_savestack_ix);
-        PL_tmps_floor = cx->blk_eval.old_tmpsfloor;
+        PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
        Perl_die(aTHX_ "%"SVf" did not return a true value", SVfARG(namesv));
         NOT_REACHED; /* NOTREACHED */
        /* die_unwind() did LEAVE, or we won't be here */
     }
     else {
-        LEAVE_SCOPE(cx->blk_eval.old_savestack_ix);
-        PL_tmps_floor = cx->blk_eval.old_tmpsfloor;
+        PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
         if (!keep)
            CLEAR_ERRSV();
     }
@@ -4320,19 +4314,14 @@ PP(pp_leaveeval)
 void
 Perl_delete_eval_scope(pTHX)
 {
-    SV **newsp;
     PMOP *newpm;
-    I32 gimme;
     PERL_CONTEXT *cx;
     I32 optype;
        
     POPBLOCK(cx,newpm);
     POPEVAL(cx);
     PL_curpm = newpm;
-    LEAVE_SCOPE(cx->blk_eval.old_savestack_ix);
-    PL_tmps_floor = cx->blk_eval.old_tmpsfloor;
-    PERL_UNUSED_VAR(newsp);
-    PERL_UNUSED_VAR(gimme);
+    PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
     PERL_UNUSED_VAR(optype);
 }
 
@@ -4346,7 +4335,7 @@ Perl_create_eval_scope(pTHX_ U32 flags)
        
     PUSHBLOCK(cx, (CXt_EVAL|CXp_TRYBLOCK), PL_stack_sp);
     PUSHEVAL(cx, 0);
-    cx->blk_eval.old_savestack_ix = PL_savestack_ix;
+    cx->cx_u.cx_blk.blku_old_savestack_ix = PL_savestack_ix;
 
     PL_in_eval = EVAL_INEVAL;
     if (flags & G_KEEPERR)
@@ -4377,19 +4366,24 @@ PP(pp_leavetry)
     OP *retop;
 
     PERL_ASYNC_CHECK();
-    POPBLOCK(cx,newpm);
-    retop = cx->blk_eval.retop;
-    POPEVAL(cx);
-    PERL_UNUSED_VAR(optype);
+
+    cx = &cxstack[cxstack_ix];
+    assert(CxTYPE(cx) == CXt_EVAL);
+    newsp = PL_stack_base + cx->blk_oldsp;
+    gimme = cx->blk_gimme;
 
     SP = (gimme == G_VOID)
         ? newsp
         : leave_common(newsp, SP, newsp, gimme,
                               SVs_PADTMP|SVs_TEMP, FALSE);
+    POPBLOCK(cx,newpm);
+    retop = cx->blk_eval.retop;
+    POPEVAL(cx);
+    PERL_UNUSED_VAR(optype);
+
     PL_curpm = newpm;  /* Don't pop $1 et al till now */
 
-    LEAVE_SCOPE(cx->blk_eval.old_savestack_ix);
-    PL_tmps_floor = cx->blk_eval.old_tmpsfloor;
+    PL_tmps_floor = cx->cx_u.cx_blk.blku_old_tmpsfloor;
 
     CLEAR_ERRSV();
     RETURNOP(retop);
@@ -4400,16 +4394,14 @@ PP(pp_entergiven)
     dSP;
     PERL_CONTEXT *cx;
     const I32 gimme = GIMME_V;
+    SV *origsv = DEFSV;
+    SV *newsv = POPs;
     
-    ENTER_with_name("given");
-    SAVETMPS;
-
     assert(!PL_op->op_targ); /* used to be set for lexical $_ */
-    SAVE_DEFSV;
-    DEFSV_set(POPs);
+    GvSV(PL_defgv) = SvREFCNT_inc(newsv);
 
     PUSHBLOCK(cx, CXt_GIVEN, SP);
-    PUSHGIVEN(cx);
+    PUSHGIVEN(cx, origsv);
 
     RETURN;
 }
@@ -4423,16 +4415,21 @@ PP(pp_leavegiven)
     PMOP *newpm;
     PERL_UNUSED_CONTEXT;
 
-    POPBLOCK(cx,newpm);
+    cx = &cxstack[cxstack_ix];
     assert(CxTYPE(cx) == CXt_GIVEN);
+    newsp = PL_stack_base + cx->blk_oldsp;
+    gimme = cx->blk_gimme;
 
     SP = (gimme == G_VOID)
         ? newsp
         : leave_common(newsp, SP, newsp, gimme,
                               SVs_PADTMP|SVs_TEMP, FALSE);
+    POPBLOCK(cx,newpm);
+    POPGIVEN(cx);
+    assert(CxTYPE(cx) == CXt_GIVEN);
+
     PL_curpm = newpm;  /* Don't pop $1 et al till now */
 
-    LEAVE_with_name("given");
     RETURN;
 }
 
@@ -4985,9 +4982,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);
 
@@ -5001,44 +4995,38 @@ PP(pp_leavewhen)
     PERL_CONTEXT *cx;
     I32 gimme;
     SV **newsp;
-    PMOP *newpm;
 
-    cxix = dopoptogiven(cxstack_ix);
+    cx = &cxstack[cxstack_ix];
+    assert(CxTYPE(cx) == CXt_WHEN);
+    gimme = cx->blk_gimme;
+
+    cxix = dopoptogivenfor(cxstack_ix);
     if (cxix < 0)
        /* diag_listed_as: Can't "when" outside a topicalizer */
        DIE(aTHX_ "Can't \"%s\" outside a topicalizer",
                   PL_op->op_flags & OPf_SPECIAL ? "default" : "when");
 
-    POPBLOCK(cx,newpm);
-    assert(CxTYPE(cx) == CXt_WHEN);
-
+    newsp = PL_stack_base + cx->blk_oldsp;
     SP = (gimme == G_VOID)
         ? newsp
         : leave_common(newsp, SP, newsp, gimme,
                               SVs_PADTMP|SVs_TEMP, FALSE);
-    PL_curpm = newpm;   /* pop $1 et al */
-
-    LEAVE_with_name("when");
-
-    if (cxix < cxstack_ix)
-        dounwind(cxix);
+    /* pop the WHEN, BLOCK and anything else before the GIVEN/FOR */
+    assert(cxix < cxstack_ix);
+    dounwind(cxix);
 
     cx = &cxstack[cxix];
 
     if (CxFOREACH(cx)) {
-       /* clear off anything above the scope we're re-entering */
-       I32 inner = PL_scopestack_ix;
-
+        /* emulate pp_next. Note that any stack(s) cleanup will be
+         * done by the pp_unstack which op_nextop should point to */
        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;
     }
     else {
        PERL_ASYNC_CHECK();
+        assert(cx->blk_givwhen.leave_op->op_type == OP_LEAVEGIVEN);
        RETURNOP(cx->blk_givwhen.leave_op);
     }
 }
@@ -5048,11 +5036,8 @@ PP(pp_continue)
     dSP;
     I32 cxix;
     PERL_CONTEXT *cx;
-    I32 gimme;
-    SV **newsp;
     PMOP *newpm;
 
-    PERL_UNUSED_VAR(gimme);
     
     cxix = dopoptowhen(cxstack_ix); 
     if (cxix < 0)   
@@ -5063,11 +5048,11 @@ PP(pp_continue)
     
     POPBLOCK(cx,newpm);
     assert(CxTYPE(cx) == CXt_WHEN);
+    POPWHEN(cx);
 
-    SP = newsp;
+    SP = PL_stack_base + cx->blk_oldsp;
     PL_curpm = newpm;   /* pop $1 et al */
 
-    LEAVE_with_name("when");
     RETURNOP(cx->blk_givwhen.leave_op->op_next);
 }
 
@@ -5076,7 +5061,7 @@ PP(pp_break)
     I32 cxix;
     PERL_CONTEXT *cx;
 
-    cxix = dopoptogiven(cxstack_ix); 
+    cxix = dopoptogivenfor(cxstack_ix);
     if (cxix < 0)
        DIE(aTHX_ "Can't \"break\" outside a given block");