This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Don't advertise PERL_HASH_SEED_EXPLICIT and NO_HASH_SEED
[perl5.git] / pp_hot.c
index 546d93c..9c5f325 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1,7 +1,7 @@
 /*    pp_hot.c
  *
- *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
+ *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ *    2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
  * Then he heard Merry change the note, and up went the Horn-cry of Buckland,
  * shaking the air.
  *
- *            Awake!  Awake!  Fear, Fire, Foes!  Awake!
- *                     Fire, Foes!  Awake!
+ *                  Awake!  Awake!  Fear, Fire, Foes!  Awake!
+ *                               Fire, Foes!  Awake!
+ *
+ *     [p.1007 of _The Lord of the Rings_, VI/viii: "The Scouring of the Shire"]
  */
 
 /* This file contains 'hot' pp ("push/pop") functions that
@@ -50,6 +52,7 @@ PP(pp_nextstate)
     TAINT_NOT;         /* Each statement is presumed innocent */
     PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
     FREETMPS;
+    PERL_ASYNC_CHECK();
     return NORMAL;
 }
 
@@ -71,13 +74,6 @@ PP(pp_null)
     return NORMAL;
 }
 
-PP(pp_setstate)
-{
-    dVAR;
-    PL_curcop = (COP*)PL_op;
-    return NORMAL;
-}
-
 PP(pp_pushmark)
 {
     dVAR;
@@ -96,13 +92,14 @@ PP(pp_stringify)
 PP(pp_gv)
 {
     dVAR; dSP;
-    XPUSHs((SV*)cGVOP_gv);
+    XPUSHs(MUTABLE_SV(cGVOP_gv));
     RETURN;
 }
 
 PP(pp_and)
 {
     dVAR; dSP;
+    PERL_ASYNC_CHECK();
     if (!SvTRUE(TOPs))
        RETURN;
     else {
@@ -120,28 +117,22 @@ PP(pp_sassign)
        SV * const temp = left;
        left = right; right = temp;
     }
-    else if (PL_op->op_private & OPpASSIGN_STATE) {
-       if (SvPADSTALE(right))
-           SvPADSTALE_off(right);
-       else
-           RETURN; /* ignore assignment */
-    }
     if (PL_tainting && PL_tainted && !SvTAINTED(left))
        TAINT_NOT;
     if (PL_op->op_private & OPpASSIGN_CV_TO_GV) {
        SV * const cv = SvRV(left);
        const U32 cv_type = SvTYPE(cv);
-       const U32 gv_type = SvTYPE(right);
+       const bool is_gv = isGV_with_GP(right);
        const bool got_coderef = cv_type == SVt_PVCV || cv_type == SVt_PVFM;
 
        if (!got_coderef) {
            assert(SvROK(cv));
        }
 
-       /* Can do the optimisation if right (LVAUE) is not a typeglob,
+       /* Can do the optimisation if right (LVALUE) is not a typeglob,
           left (RVALUE) is a reference to something, and we're in void
           context. */
-       if (!got_coderef && gv_type != SVt_PVGV && GIMME_V == G_VOID) {
+       if (!got_coderef && !is_gv && GIMME_V == G_VOID) {
            /* Is the target symbol table currently empty?  */
            GV * const gv = gv_fetchsv(right, GV_NOINIT, SVt_PVGV);
            if (SvTYPE(gv) != SVt_PVGV && !SvOK(gv)) {
@@ -149,8 +140,8 @@ PP(pp_sassign)
                   The gv becomes a(nother) reference to the constant.  */
                SV *const value = SvRV(cv);
 
-               SvUPGRADE((SV *)gv, SVt_RV);
-               SvROK_on(gv);
+               SvUPGRADE(MUTABLE_SV(gv), SVt_IV);
+               SvPCS_IMPORTED_on(gv);
                SvRV_set(gv, value);
                SvREFCNT_inc_simple_void(value);
                SETs(right);
@@ -159,25 +150,50 @@ PP(pp_sassign)
        }
 
        /* Need to fix things up.  */
-       if (gv_type != SVt_PVGV) {
+       if (!is_gv) {
            /* Need to fix GV.  */
-           right = (SV*)gv_fetchsv(right, GV_ADD, SVt_PVGV);
+           right = MUTABLE_SV(gv_fetchsv(right, GV_ADD, SVt_PVGV));
        }
 
        if (!got_coderef) {
            /* We've been returned a constant rather than a full subroutine,
               but they expect a subroutine reference to apply.  */
-           ENTER;
-           SvREFCNT_inc_void(SvRV(cv));
-           /* newCONSTSUB takes a reference count on the passed in SV
-              from us.  We set the name to NULL, otherwise we get into
-              all sorts of fun as the reference to our new sub is
-              donated to the GV that we're about to assign to.
-           */
-           SvRV_set(left, (SV *)newCONSTSUB(GvSTASH(right), NULL,
-                                                SvRV(cv)));
-           SvREFCNT_dec(cv);
-           LEAVE;
+           if (SvROK(cv)) {
+               ENTER_with_name("sassign_coderef");
+               SvREFCNT_inc_void(SvRV(cv));
+               /* newCONSTSUB takes a reference count on the passed in SV
+                  from us.  We set the name to NULL, otherwise we get into
+                  all sorts of fun as the reference to our new sub is
+                  donated to the GV that we're about to assign to.
+               */
+               SvRV_set(left, MUTABLE_SV(newCONSTSUB(GvSTASH(right), NULL,
+                                                     SvRV(cv))));
+               SvREFCNT_dec(cv);
+               LEAVE_with_name("sassign_coderef");
+           } else {
+               /* What can happen for the corner case *{"BONK"} = \&{"BONK"};
+                  is that
+                  First:   ops for \&{"BONK"}; return us the constant in the
+                           symbol table
+                  Second:  ops for *{"BONK"} cause that symbol table entry
+                           (and our reference to it) to be upgraded from RV
+                           to typeblob)
+                  Thirdly: We get here. cv is actually PVGV now, and its
+                           GvCV() is actually the subroutine we're looking for
+
+                  So change the reference so that it points to the subroutine
+                  of that typeglob, as that's what they were after all along.
+               */
+               GV *const upgraded = MUTABLE_GV(cv);
+               CV *const source = GvCV(upgraded);
+
+               assert(source);
+               assert(CvFLAGS(source) & CVf_CONST);
+
+               SvREFCNT_inc_void(source);
+               SvREFCNT_dec(upgraded);
+               SvRV_set(left, MUTABLE_SV(source));
+           }
        }
 
     }
@@ -189,6 +205,7 @@ PP(pp_sassign)
 PP(pp_cond_expr)
 {
     dVAR; dSP;
+    PERL_ASYNC_CHECK();
     if (SvTRUEx(POPs))
        RETURNOP(cLOGOP->op_other);
     else
@@ -198,18 +215,20 @@ PP(pp_cond_expr)
 PP(pp_unstack)
 {
     dVAR;
-    I32 oldsave;
+    PERL_ASYNC_CHECK();
     TAINT_NOT;         /* Each statement is presumed innocent */
     PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
     FREETMPS;
-    oldsave = PL_scopestack[PL_scopestack_ix - 1];
-    LEAVE_SCOPE(oldsave);
+    if (!(PL_op->op_flags & OPf_SPECIAL)) {
+       I32 oldsave = PL_scopestack[PL_scopestack_ix - 1];
+       LEAVE_SCOPE(oldsave);
+    }
     return NORMAL;
 }
 
 PP(pp_concat)
 {
-  dVAR; dSP; dATARGET; tryAMAGICbin(concat,opASSIGN);
+  dVAR; dSP; dATARGET; tryAMAGICbin_MG(concat_amg, AMGf_assign);
   {
     dPOPTOPssrl;
     bool lbyte;
@@ -218,18 +237,17 @@ PP(pp_concat)
     bool rbyte = FALSE;
     bool rcopied = FALSE;
 
-    if (TARG == right && right != left) {
-       /* mg_get(right) may happen here ... */
-       rpv = SvPV_const(right, rlen);
+    if (TARG == right && right != left) { /* $r = $l.$r */
+       rpv = SvPV_nomg_const(right, rlen);
        rbyte = !DO_UTF8(right);
-       right = sv_2mortal(newSVpvn(rpv, rlen));
+       right = newSVpvn_flags(rpv, rlen, SVs_TEMP);
        rpv = SvPV_const(right, rlen);  /* no point setting UTF-8 here */
        rcopied = TRUE;
     }
 
-    if (TARG != left) {
+    if (TARG != left) { /* not $l .= $r */
         STRLEN llen;
-        const char* const lpv = SvPV_const(left, llen);        /* mg_get(left) may happen here */
+        const char* const lpv = SvPV_nomg_const(left, llen);
        lbyte = !DO_UTF8(left);
        sv_setpvn(TARG, lpv, llen);
        if (!lbyte)
@@ -237,34 +255,37 @@ PP(pp_concat)
        else
            SvUTF8_off(TARG);
     }
-    else { /* TARG == left */
-        STRLEN llen;
-       SvGETMAGIC(left);               /* or mg_get(left) may happen here */
+    else { /* $l .= $r */
        if (!SvOK(TARG)) {
-           if (left == right && ckWARN(WARN_UNINITIALIZED))
+           if (left == right && ckWARN(WARN_UNINITIALIZED)) /* $l .= $l */
                report_uninit(right);
-           sv_setpvn(left, "", 0);
+           sv_setpvs(left, "");
        }
-       (void)SvPV_nomg_const(left, llen);    /* Needed to set UTF8 flag */
-       lbyte = !DO_UTF8(left);
+       lbyte = (SvROK(left) && SvTYPE(SvRV(left)) == SVt_REGEXP)
+                   ?  !DO_UTF8(SvRV(left)) : !DO_UTF8(left);
        if (IN_BYTES)
            SvUTF8_off(TARG);
     }
 
-    /* or mg_get(right) may happen here */
     if (!rcopied) {
-       rpv = SvPV_const(right, rlen);
+       if (left == right)
+           /* $r.$r: do magic twice: tied might return different 2nd time */
+           SvGETMAGIC(right);
+       rpv = SvPV_nomg_const(right, rlen);
        rbyte = !DO_UTF8(right);
     }
     if (lbyte != rbyte) {
+       /* sv_utf8_upgrade_nomg() may reallocate the stack */
+       PUTBACK;
        if (lbyte)
            sv_utf8_upgrade_nomg(TARG);
        else {
            if (!rcopied)
-               right = sv_2mortal(newSVpvn(rpv, rlen));
+               right = newSVpvn_flags(rpv, rlen, SVs_TEMP);
            sv_utf8_upgrade_nomg(right);
-           rpv = SvPV_const(right, rlen);
+           rpv = SvPV_nomg_const(right, rlen);
        }
+       SPAGAIN;
     }
     sv_catpvn_nomg(TARG, rpv, rlen);
 
@@ -293,17 +314,18 @@ PP(pp_padsv)
 PP(pp_readline)
 {
     dVAR;
+    dSP; SvGETMAGIC(TOPs);
     tryAMAGICunTARGET(iter, 0);
-    PL_last_in_gv = (GV*)(*PL_stack_sp--);
-    if (SvTYPE(PL_last_in_gv) != SVt_PVGV) {
-       if (SvROK(PL_last_in_gv) && SvTYPE(SvRV(PL_last_in_gv)) == SVt_PVGV)
-           PL_last_in_gv = (GV*)SvRV(PL_last_in_gv);
+    PL_last_in_gv = MUTABLE_GV(*PL_stack_sp--);
+    if (!isGV_with_GP(PL_last_in_gv)) {
+       if (SvROK(PL_last_in_gv) && isGV_with_GP(SvRV(PL_last_in_gv)))
+           PL_last_in_gv = MUTABLE_GV(SvRV(PL_last_in_gv));
        else {
            dSP;
-           XPUSHs((SV*)PL_last_in_gv);
+           XPUSHs(MUTABLE_SV(PL_last_in_gv));
            PUTBACK;
            pp_rv2gv();
-           PL_last_in_gv = (GV*)(*PL_stack_sp--);
+           PL_last_in_gv = MUTABLE_GV(*PL_stack_sp--);
        }
     }
     return do_readline();
@@ -311,7 +333,8 @@ PP(pp_readline)
 
 PP(pp_eq)
 {
-    dVAR; dSP; tryAMAGICbinSET(eq,0);
+    dVAR; dSP;
+    tryAMAGICbin_MG(eq_amg, AMGf_set);
 #ifndef NV_PRESERVES_UV
     if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
         SP--;
@@ -320,12 +343,12 @@ PP(pp_eq)
     }
 #endif
 #ifdef PERL_PRESERVE_IVUV
-    SvIV_please(TOPs);
+    SvIV_please_nomg(TOPs);
     if (SvIOK(TOPs)) {
        /* Unless the left argument is integer in range we are going
           to have to use NV maths. Hence only attempt to coerce the
           right argument if we know the left is integer.  */
-      SvIV_please(TOPm1s);
+      SvIV_please_nomg(TOPm1s);
        if (SvIOK(TOPm1s)) {
            const bool auvok = SvUOK(TOPm1s);
            const bool buvok = SvUOK(TOPs);
@@ -370,13 +393,13 @@ PP(pp_eq)
 #endif
     {
 #if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
-      dPOPTOPnnrl;
+      dPOPTOPnnrl_nomg;
       if (Perl_isnan(left) || Perl_isnan(right))
          RETSETNO;
       SETs(boolSV(left == right));
 #else
-      dPOPnv;
-      SETs(boolSV(TOPn == value));
+      dPOPnv_nomg;
+      SETs(boolSV(SvNV_nomg(TOPs) == value));
 #endif
       RETURN;
     }
@@ -385,8 +408,8 @@ PP(pp_eq)
 PP(pp_preinc)
 {
     dVAR; dSP;
-    if (SvTYPE(TOPs) >= SVt_PVGV && SvTYPE(TOPs) != SVt_PVLV)
-       DIE(aTHX_ PL_no_modify);
+    if (SvTYPE(TOPs) >= SVt_PVAV || isGV_with_GP(TOPs))
+       Perl_croak_no_modify(aTHX);
     if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
         && SvIVX(TOPs) != IV_MAX)
     {
@@ -402,6 +425,7 @@ PP(pp_preinc)
 PP(pp_or)
 {
     dVAR; dSP;
+    PERL_ASYNC_CHECK();
     if (SvTRUE(TOPs))
        RETURN;
     else {
@@ -417,21 +441,23 @@ PP(pp_defined)
     register SV* sv;
     bool defined;
     const int op_type = PL_op->op_type;
-    const int is_dor = (op_type == OP_DOR || op_type == OP_DORASSIGN);
+    const bool is_dor = (op_type == OP_DOR || op_type == OP_DORASSIGN);
 
     if (is_dor) {
+       PERL_ASYNC_CHECK();
         sv = TOPs;
         if (!sv || !SvANY(sv)) {
            if (op_type == OP_DOR)
                --SP;
             RETURNOP(cLOGOP->op_other);
         }
-    } else if (op_type == OP_DEFINED) {
+    }
+    else {
+       /* OP_DEFINED */
         sv = POPs;
         if (!sv || !SvANY(sv))
             RETPUSHNO;
-    } else
-        DIE(aTHX_ "panic:  Invalid op (%s) in pp_defined()", OP_NAME(PL_op));
+    }
 
     defined = FALSE;
     switch (SvTYPE(sv)) {
@@ -469,8 +495,12 @@ PP(pp_defined)
 
 PP(pp_add)
 {
-    dVAR; dSP; dATARGET; bool useleft; tryAMAGICbin(add,opASSIGN);
-    useleft = USE_LEFT(TOPm1s);
+    dVAR; dSP; dATARGET; bool useleft; SV *svl, *svr;
+    tryAMAGICbin_MG(add_amg, AMGf_assign|AMGf_numeric);
+    svr = TOPs;
+    svl = TOPm1s;
+
+    useleft = USE_LEFT(svl);
 #ifdef PERL_PRESERVE_IVUV
     /* We must see if we can perform the addition with integers if possible,
        as the integer code detects overflow while the NV code doesn't.
@@ -518,8 +548,9 @@ PP(pp_add)
        unsigned code below is actually shorter than the old code. :-)
     */
 
-    SvIV_please(TOPs);
-    if (SvIOK(TOPs)) {
+    SvIV_please_nomg(svr);
+
+    if (SvIOK(svr)) {
        /* Unless the left argument is integer in range we are going to have to
           use NV maths. Hence only attempt to coerce the right argument if
           we know the left is integer.  */
@@ -535,12 +566,12 @@ PP(pp_add)
               lots of code to speed up what is probably a rarish case.  */
        } else {
            /* Left operand is defined, so is it IV? */
-           SvIV_please(TOPm1s);
-           if (SvIOK(TOPm1s)) {
-               if ((auvok = SvUOK(TOPm1s)))
-                   auv = SvUVX(TOPm1s);
+           SvIV_please_nomg(svl);
+           if (SvIOK(svl)) {
+               if ((auvok = SvUOK(svl)))
+                   auv = SvUVX(svl);
                else {
-                   register const IV aiv = SvIVX(TOPm1s);
+                   register const IV aiv = SvIVX(svl);
                    if (aiv >= 0) {
                        auv = aiv;
                        auvok = 1;      /* Now acting as a sign flag.  */
@@ -555,12 +586,12 @@ PP(pp_add)
            bool result_good = 0;
            UV result;
            register UV buv;
-           bool buvok = SvUOK(TOPs);
+           bool buvok = SvUOK(svr);
        
            if (buvok)
-               buv = SvUVX(TOPs);
+               buv = SvUVX(svr);
            else {
-               register const IV biv = SvIVX(TOPs);
+               register const IV biv = SvIVX(svr);
                if (biv >= 0) {
                    buv = biv;
                    buvok = 1;
@@ -618,13 +649,14 @@ PP(pp_add)
     }
 #endif
     {
-       dPOPnv;
+       NV value = SvNV_nomg(svr);
+       (void)POPs;
        if (!useleft) {
            /* left operand is undef, treat as zero. + 0.0 is identity. */
            SETn(value);
            RETURN;
        }
-       SETn( value + TOPn );
+       SETn( value + SvNV_nomg(svl) );
        RETURN;
     }
 }
@@ -632,14 +664,14 @@ PP(pp_add)
 PP(pp_aelemfast)
 {
     dVAR; dSP;
-    AV * const av = PL_op->op_flags & OPf_SPECIAL ?
-               (AV*)PAD_SV(PL_op->op_targ) : GvAV(cGVOP_gv);
+    AV * const av = PL_op->op_flags & OPf_SPECIAL
+       ? MUTABLE_AV(PAD_SV(PL_op->op_targ)) : GvAV(cGVOP_gv);
     const U32 lval = PL_op->op_flags & OPf_MOD;
     SV** const svp = av_fetch(av, PL_op->op_private, lval);
     SV *sv = (svp ? *svp : &PL_sv_undef);
     EXTEND(SP, 1);
-    if (!lval && SvGMAGICAL(sv))       /* see note in pp_helem() */
-       sv = sv_mortalcopy(sv);
+    if (!lval && SvRMAGICAL(av) && SvGMAGICAL(sv)) /* see note in pp_helem() */
+       mg_get(sv);
     PUSHs(sv);
     RETURN;
 }
@@ -668,7 +700,7 @@ PP(pp_pushre)
     Copy(&PL_op, &LvTARGOFF(sv), 1, OP*);
     XPUSHs(sv);
 #else
-    XPUSHs((SV*)PL_op);
+    XPUSHs(MUTABLE_SV(PL_op));
 #endif
     RETURN;
 }
@@ -681,10 +713,11 @@ PP(pp_print)
     IO *io;
     register PerlIO *fp;
     MAGIC *mg;
-    GV * const gv = (PL_op->op_flags & OPf_STACKED) ? (GV*)*++MARK : PL_defoutgv;
+    GV * const gv
+       = (PL_op->op_flags & OPf_STACKED) ? MUTABLE_GV(*++MARK) : PL_defoutgv;
 
     if (gv && (io = GvIO(gv))
-       && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar)))
+       && (mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar)))
     {
       had_magic:
        if (MARK == ORIGMARK) {
@@ -697,11 +730,16 @@ PP(pp_print)
            ++SP;
        }
        PUSHMARK(MARK - 1);
-       *MARK = SvTIED_obj((SV*)io, mg);
+       *MARK = SvTIED_obj(MUTABLE_SV(io), mg);
        PUTBACK;
-       ENTER;
+       ENTER_with_name("call_PRINT");
+       if( PL_op->op_type == OP_SAY ) {
+               /* local $\ = "\n" */
+               SAVEGENERICSV(PL_ors_sv);
+               PL_ors_sv = newSVpvs("\n");
+       }
        call_method("PRINT", G_SCALAR);
-       LEAVE;
+       LEAVE_with_name("call_PRINT");
        SPAGAIN;
        MARK = ORIGMARK + 1;
        *MARK = *SP;
@@ -709,8 +747,8 @@ PP(pp_print)
        RETURN;
     }
     if (!(io = GvIO(gv))) {
-        if ((GvEGV(gv)) && (io = GvIO(GvEGV(gv)))
-           && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar)))
+        if ( gv && GvEGVx(gv) && (io = GvIO(GvEGV(gv)))
+           && (mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar)))
             goto had_magic;
        if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
            report_evil_fh(gv, io, PL_op->op_type);
@@ -728,14 +766,16 @@ PP(pp_print)
        goto just_say_no;
     }
     else {
+       SV * const ofs = GvSV(PL_ofsgv); /* $, */
        MARK++;
-       if (PL_ofs_sv && SvOK(PL_ofs_sv)) {
+       if (ofs && (SvGMAGICAL(ofs) || SvOK(ofs))) {
            while (MARK <= SP) {
                if (!do_print(*MARK, fp))
                    break;
                MARK++;
                if (MARK <= SP) {
-                   if (!do_print(PL_ofs_sv, fp)) { /* $, */
+                   /* don't use 'ofs' here - it may be invalidated by magic callbacks */
+                   if (!do_print(GvSV(PL_ofsgv), fp)) {
                        MARK--;
                        break;
                    }
@@ -752,7 +792,11 @@ PP(pp_print)
        if (MARK <= SP)
            goto just_say_no;
        else {
-           if (PL_ors_sv && SvOK(PL_ors_sv))
+           if (PL_op->op_type == OP_SAY) {
+               if (PerlIO_write(fp, "\n", 1) == 0 || PerlIO_error(fp))
+                   goto just_say_no;
+           }
+            else if (PL_ors_sv && SvOK(PL_ors_sv))
                if (!do_print(PL_ors_sv, fp)) /* $\ */
                    goto just_say_no;
 
@@ -774,103 +818,82 @@ PP(pp_print)
 PP(pp_rv2av)
 {
     dVAR; dSP; dTOPss;
-    AV *av;
+    const I32 gimme = GIMME_V;
+    static const char an_array[] = "an ARRAY";
+    static const char a_hash[] = "a HASH";
+    const bool is_pp_rv2av = PL_op->op_type == OP_RV2AV;
+    const svtype type = is_pp_rv2av ? SVt_PVAV : SVt_PVHV;
 
+    if (!(PL_op->op_private & OPpDEREFed))
+       SvGETMAGIC(sv);
     if (SvROK(sv)) {
-      wasref:
-       tryAMAGICunDEREF(to_av);
+       sv = amagic_deref_call(sv, is_pp_rv2av ? to_av_amg : to_hv_amg);
+       SPAGAIN;
 
-       av = (AV*)SvRV(sv);
-       if (SvTYPE(av) != SVt_PVAV)
-           DIE(aTHX_ "Not an ARRAY reference");
+       sv = SvRV(sv);
+       if (SvTYPE(sv) != type)
+           DIE(aTHX_ "Not %s reference", is_pp_rv2av ? an_array : a_hash);
        if (PL_op->op_flags & OPf_REF) {
-           SETs((SV*)av);
+           SETs(sv);
            RETURN;
        }
        else if (LVRET) {
-           if (GIMME == G_SCALAR)
-               Perl_croak(aTHX_ "Can't return array to lvalue scalar context");
-           SETs((SV*)av);
+           if (gimme != G_ARRAY)
+               goto croak_cant_return;
+           SETs(sv);
            RETURN;
        }
        else if (PL_op->op_flags & OPf_MOD
                && PL_op->op_private & OPpLVAL_INTRO)
-           Perl_croak(aTHX_ PL_no_localize_ref);
+           Perl_croak(aTHX_ "%s", PL_no_localize_ref);
     }
     else {
-       if (SvTYPE(sv) == SVt_PVAV) {
-           av = (AV*)sv;
+       if (SvTYPE(sv) == type) {
            if (PL_op->op_flags & OPf_REF) {
-               SETs((SV*)av);
+               SETs(sv);
                RETURN;
            }
            else if (LVRET) {
-               if (GIMME == G_SCALAR)
-                   Perl_croak(aTHX_ "Can't return array to lvalue"
-                              " scalar context");
-               SETs((SV*)av);
+               if (gimme != G_ARRAY)
+                   goto croak_cant_return;
+               SETs(sv);
                RETURN;
            }
        }
        else {
            GV *gv;
        
-           if (SvTYPE(sv) != SVt_PVGV) {
-               if (SvGMAGICAL(sv)) {
-                   mg_get(sv);
-                   if (SvROK(sv))
-                       goto wasref;
-               }
-               if (!SvOK(sv)) {
-                   if (PL_op->op_flags & OPf_REF ||
-                     PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(aTHX_ PL_no_usym, "an ARRAY");
-                   if (ckWARN(WARN_UNINITIALIZED))
-                       report_uninit(sv);
-                   if (GIMME == G_ARRAY) {
-                       (void)POPs;
-                       RETURN;
-                   }
-                   RETSETUNDEF;
-               }
-               if ((PL_op->op_flags & OPf_SPECIAL) &&
-                   !(PL_op->op_flags & OPf_MOD))
-               {
-                   gv = (GV*)gv_fetchsv(sv, 0, SVt_PVAV);
-                   if (!gv
-                       && (!is_gv_magical_sv(sv,0)
-                           || !(gv = (GV*)gv_fetchsv(sv, GV_ADD, SVt_PVAV))))
-                   {
-                       RETSETUNDEF;
-                   }
-               }
-               else {
-                   if (PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(aTHX_ PL_no_symref_sv, sv, "an ARRAY");
-                   gv = (GV*)gv_fetchsv(sv, GV_ADD, SVt_PVAV);
-               }
+           if (!isGV_with_GP(sv)) {
+               gv = Perl_softref2xv(aTHX_ sv, is_pp_rv2av ? an_array : a_hash,
+                                    type, &sp);
+               if (!gv)
+                   RETURN;
            }
            else {
-               gv = (GV*)sv;
+               gv = MUTABLE_GV(sv);
            }
-           av = GvAVn(gv);
+           sv = is_pp_rv2av ? MUTABLE_SV(GvAVn(gv)) : MUTABLE_SV(GvHVn(gv));
            if (PL_op->op_private & OPpLVAL_INTRO)
-               av = save_ary(gv);
+               sv = is_pp_rv2av ? MUTABLE_SV(save_ary(gv)) : MUTABLE_SV(save_hash(gv));
            if (PL_op->op_flags & OPf_REF) {
-               SETs((SV*)av);
+               SETs(sv);
                RETURN;
            }
            else if (LVRET) {
-               if (GIMME == G_SCALAR)
-                   Perl_croak(aTHX_ "Can't return array to lvalue"
-                              " scalar context");
-               SETs((SV*)av);
+               if (gimme != G_ARRAY)
+                   goto croak_cant_return;
+               SETs(sv);
                RETURN;
            }
        }
     }
 
-    if (GIMME == G_ARRAY) {
+    if (is_pp_rv2av) {
+       AV *const av = MUTABLE_AV(sv);
+       /* The guts of pp_rv2av, with no intenting change to preserve history
+          (until such time as we get tools that can do blame annotation across
+          whitespace changes.  */
+    if (gimme == G_ARRAY) {
        const I32 maxarg = AvFILL(av) + 1;
        (void)POPs;                     /* XXXX May be optimized away? */
        EXTEND(SP, maxarg);
@@ -880,7 +903,7 @@ PP(pp_rv2av)
                SV ** const svp = av_fetch(av, i, FALSE);
                /* See note in pp_helem, and bug id #27839 */
                SP[i+1] = svp
-                   ? SvGMAGICAL(*svp) ? sv_mortalcopy(*svp) : *svp
+                   ? SvGMAGICAL(*svp) ? (mg_get(*svp), *svp) : *svp
                    : &PL_sv_undef;
            }
        }
@@ -889,122 +912,29 @@ PP(pp_rv2av)
        }
        SP += maxarg;
     }
-    else if (GIMME_V == G_SCALAR) {
+    else if (gimme == G_SCALAR) {
        dTARGET;
        const I32 maxarg = AvFILL(av) + 1;
        SETi(maxarg);
     }
-    RETURN;
-}
-
-PP(pp_rv2hv)
-{
-    dVAR; dSP; dTOPss;
-    HV *hv;
-    const I32 gimme = GIMME_V;
-    static const char return_hash_to_lvalue_scalar[] = "Can't return hash to lvalue scalar context";
-
-    if (SvROK(sv)) {
-      wasref:
-       tryAMAGICunDEREF(to_hv);
-
-       hv = (HV*)SvRV(sv);
-       if (SvTYPE(hv) != SVt_PVHV)
-           DIE(aTHX_ "Not a HASH reference");
-       if (PL_op->op_flags & OPf_REF) {
-           SETs((SV*)hv);
-           RETURN;
-       }
-       else if (LVRET) {
-           if (gimme != G_ARRAY)
-               Perl_croak(aTHX_ return_hash_to_lvalue_scalar );
-           SETs((SV*)hv);
-           RETURN;
-       }
-       else if (PL_op->op_flags & OPf_MOD
-               && PL_op->op_private & OPpLVAL_INTRO)
-           Perl_croak(aTHX_ PL_no_localize_ref);
-    }
-    else {
-       if (SvTYPE(sv) == SVt_PVHV) {
-           hv = (HV*)sv;
-           if (PL_op->op_flags & OPf_REF) {
-               SETs((SV*)hv);
-               RETURN;
-           }
-           else if (LVRET) {
-               if (gimme != G_ARRAY)
-                   Perl_croak(aTHX_ return_hash_to_lvalue_scalar );
-               SETs((SV*)hv);
-               RETURN;
-           }
-       }
-       else {
-           GV *gv;
-       
-           if (SvTYPE(sv) != SVt_PVGV) {
-               if (SvGMAGICAL(sv)) {
-                   mg_get(sv);
-                   if (SvROK(sv))
-                       goto wasref;
-               }
-               if (!SvOK(sv)) {
-                   if (PL_op->op_flags & OPf_REF ||
-                     PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(aTHX_ PL_no_usym, "a HASH");
-                   if (ckWARN(WARN_UNINITIALIZED))
-                       report_uninit(sv);
-                   if (gimme == G_ARRAY) {
-                       SP--;
-                       RETURN;
-                   }
-                   RETSETUNDEF;
-               }
-               if ((PL_op->op_flags & OPf_SPECIAL) &&
-                   !(PL_op->op_flags & OPf_MOD))
-               {
-                   gv = (GV*)gv_fetchsv(sv, 0, SVt_PVHV);
-                   if (!gv
-                       && (!is_gv_magical_sv(sv,0)
-                           || !(gv = (GV*)gv_fetchsv(sv, GV_ADD, SVt_PVHV))))
-                   {
-                       RETSETUNDEF;
-                   }
-               }
-               else {
-                   if (PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(aTHX_ PL_no_symref_sv, sv, "a HASH");
-                   gv = (GV*)gv_fetchsv(sv, GV_ADD, SVt_PVHV);
-               }
-           }
-           else {
-               gv = (GV*)sv;
-           }
-           hv = GvHVn(gv);
-           if (PL_op->op_private & OPpLVAL_INTRO)
-               hv = save_hash(gv);
-           if (PL_op->op_flags & OPf_REF) {
-               SETs((SV*)hv);
-               RETURN;
-           }
-           else if (LVRET) {
-               if (gimme != G_ARRAY)
-                   Perl_croak(aTHX_ return_hash_to_lvalue_scalar );
-               SETs((SV*)hv);
-               RETURN;
-           }
-       }
-    }
-
+    } else {
+       /* The guts of pp_rv2hv  */
     if (gimme == G_ARRAY) { /* array wanted */
-       *PL_stack_sp = (SV*)hv;
+       *PL_stack_sp = sv;
        return do_kv();
     }
     else if (gimme == G_SCALAR) {
        dTARGET;
-    TARG = Perl_hv_scalar(aTHX_ hv);
+    TARG = Perl_hv_scalar(aTHX_ MUTABLE_HV(sv));
+       SPAGAIN;
        SETTARG;
     }
+    }
+    RETURN;
+
+ croak_cant_return:
+    Perl_croak(aTHX_ "Can't return %s to lvalue scalar context",
+              is_pp_rv2av ? "array" : "hash");
     RETURN;
 }
 
@@ -1012,6 +942,9 @@ STATIC void
 S_do_oddball(pTHX_ HV *hash, SV **relem, SV **firstrelem)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_DO_ODDBALL;
+
     if (*relem) {
        SV *tmpstr;
         const HE *didstore;
@@ -1027,7 +960,7 @@ S_do_oddball(pTHX_ HV *hash, SV **relem, SV **firstrelem)
            }
            else
                err = "Odd number of elements in hash assignment";
-           Perl_warner(aTHX_ packWARN(WARN_MISC), err);
+           Perl_warner(aTHX_ packWARN(WARN_MISC), "%s", err);
        }
 
         tmpstr = newSV(0);
@@ -1063,7 +996,6 @@ PP(pp_aassign)
     int duplicates = 0;
     SV **firsthashrelem = NULL;        /* "= 0" keeps gcc 2.95 quiet  */
 
-
     PL_delaymagic = DM_DELAY;          /* catch simultaneous items */
     gimme = GIMME_V;
 
@@ -1076,16 +1008,20 @@ PP(pp_aassign)
        for (relem = firstrelem; relem <= lastrelem; relem++) {
            if ((sv = *relem)) {
                TAINT_NOT;      /* Each item is independent */
-               *relem = sv_mortalcopy(sv);
+
+               /* Dear TODO test in t/op/sort.t, I love you.
+                  (It's relying on a panic, not a "semi-panic" from newSVsv()
+                  and then an assertion failure below.)  */
+               if (SvIS_FREED(sv)) {
+                   Perl_croak(aTHX_ "panic: attempt to copy freed scalar %p",
+                              (void*)sv);
+               }
+               /* Specifically *not* sv_mortalcopy(), as that will steal TEMPs,
+                  and we need a second copy of a temp here.  */
+               *relem = sv_2mortal(newSVsv(sv));
            }
        }
     }
-    if (PL_op->op_private & OPpASSIGN_STATE) {
-       if (SvPADSTALE(*firstlelem))
-           SvPADSTALE_off(*firstlelem);
-       else
-           RETURN; /* ignore assignment */
-    }
 
     relem = firstrelem;
     lelem = firstlelem;
@@ -1097,7 +1033,7 @@ PP(pp_aassign)
        sv = *lelem++;
        switch (SvTYPE(sv)) {
        case SVt_PVAV:
-           ary = (AV*)sv;
+           ary = MUTABLE_AV(sv);
            magic = SvMAGICAL(ary) != 0;
            av_clear(ary);
            av_extend(ary, lastrelem - relem);
@@ -1105,7 +1041,8 @@ PP(pp_aassign)
            while (relem <= lastrelem) {        /* gobble up all the rest */
                SV **didstore;
                assert(*relem);
-               sv = newSVsv(*relem);
+               sv = newSV(0);
+               sv_setsv(sv, *relem);
                *(relem++) = sv;
                didstore = av_store(ary,i++,sv);
                if (magic) {
@@ -1116,11 +1053,14 @@ PP(pp_aassign)
                }
                TAINT_NOT;
            }
+           if (PL_delaymagic & DM_ARRAY_ISA)
+               SvSETMAGIC(MUTABLE_SV(ary));
            break;
        case SVt_PVHV: {                                /* normal hash */
                SV *tmpstr;
+               SV** topelem = relem;
 
-               hash = (HV*)sv;
+               hash = MUTABLE_HV(sv);
                magic = SvMAGICAL(hash) != 0;
                hv_clear(hash);
                firsthashrelem = relem;
@@ -1132,10 +1072,19 @@ PP(pp_aassign)
                    tmpstr = newSV(0);
                    if (*relem)
                        sv_setsv(tmpstr,*relem);        /* value */
-                   *(relem++) = tmpstr;
-                   if (gimme != G_VOID && hv_exists_ent(hash, sv, 0))
-                       /* key overwrites an existing entry */
-                       duplicates += 2;
+                   relem++;
+                   if (gimme != G_VOID) {
+                       if (hv_exists_ent(hash, sv, 0))
+                           /* key overwrites an existing entry */
+                           duplicates += 2;
+                       else
+                       if (gimme == G_ARRAY) {
+                           /* copy element back: possibly to an earlier
+                            * stack location if we encountered dups earlier */
+                           *topelem++ = sv;
+                           *topelem++ = tmpstr;
+                       }
+                   }
                    didstore = hv_store_ent(hash,sv,tmpstr,0);
                    if (magic) {
                        if (SvSMAGICAL(tmpstr))
@@ -1248,11 +1197,20 @@ PP(pp_aassign)
            SP = lastrelem;
        else if (hash) {
            if (duplicates) {
-               /* Removes from the stack the entries which ended up as
-                * duplicated keys in the hash (fix for [perl #24380]) */
-               Move(firsthashrelem + duplicates,
-                       firsthashrelem, duplicates, SV**);
+               /* at this point we have removed the duplicate key/value
+                * pairs from the stack, but the remaining values may be
+                * wrong; i.e. with (a 1 a 2 b 3) on the stack we've removed
+                * the (a 2), but the stack now probably contains
+                * (a <freed> b 3), because { hv_save(a,1); hv_save(a,2) }
+                * obliterates the earlier key. So refresh all values. */
                lastrelem -= duplicates;
+               relem = firsthashrelem;
+               while (relem < lastrelem) {
+                   HE *he;
+                   sv = *relem++;
+                   he = hv_fetch_ent(hash, sv, 0, 0);
+                   *relem++ = (he ? HeVAL(he) : &PL_sv_undef);
+               }
            }
            SP = lastrelem;
        }
@@ -1262,6 +1220,7 @@ PP(pp_aassign)
        while (relem <= SP)
            *relem++ = (lelem <= lastlelem) ? *lelem++ : &PL_sv_undef;
     }
+
     RETURN;
 }
 
@@ -1269,12 +1228,30 @@ PP(pp_qr)
 {
     dVAR; dSP;
     register PMOP * const pm = cPMOP;
+    REGEXP * rx = PM_GETRE(pm);
+    SV * const pkg = rx ? CALLREG_PACKAGE(rx) : NULL;
     SV * const rv = sv_newmortal();
-    SV * const sv = newSVrv(rv, "Regexp");
-    if (pm->op_pmdynflags & PMdf_TAINTED)
+
+    SvUPGRADE(rv, SVt_IV);
+    /* For a subroutine describing itself as "This is a hacky workaround" I'm
+       loathe to use it here, but it seems to be the right fix. Or close.
+       The key part appears to be that it's essential for pp_qr to return a new
+       object (SV), which implies that there needs to be an effective way to
+       generate a new SV from the existing SV that is pre-compiled in the
+       optree.  */
+    SvRV_set(rv, MUTABLE_SV(reg_temp_copy(NULL, rx)));
+    SvROK_on(rv);
+
+    if (pkg) {
+       HV *const stash = gv_stashsv(pkg, GV_ADD);
+       SvREFCNT_dec(pkg);
+       (void)sv_bless(rv, stash);
+    }
+
+    if (RX_EXTFLAGS(rx) & RXf_TAINTED)
         SvTAINTED_on(rv);
-    sv_magic(sv,(SV*)ReREFCNT_inc(PM_GETRE(pm)), PERL_MAGIC_qr,0,0);
-    RETURNX(PUSHs(rv));
+    XPUSHs(rv);
+    RETURN;
 }
 
 PP(pp_match)
@@ -1286,7 +1263,7 @@ PP(pp_match)
     register const char *s;
     const char *strend;
     I32 global;
-    I32 r_flags = REXEC_CHECKED;
+    U8 r_flags = REXEC_CHECKED;
     const char *truebase;                      /* Start of string  */
     register REGEXP *rx = PM_GETRE(pm);
     bool rxtainted;
@@ -1296,6 +1273,7 @@ PP(pp_match)
     const I32 oldsave = PL_savestack_ix;
     I32 update_minmatch = 1;
     I32 had_zerolen = 0;
+    U32 gpos = 0;
 
     if (PL_op->op_flags & OPf_STACKED)
        TARG = POPs;
@@ -1307,87 +1285,115 @@ PP(pp_match)
     }
 
     PUTBACK;                           /* EVAL blocks need stack_sp. */
-    s = SvPV_const(TARG, len);
+    /* Skip get-magic if this is a qr// clone, because regcomp has
+       already done it. */
+    s = ((struct regexp *)SvANY(rx))->mother_re
+        ? SvPV_nomg_const(TARG, len)
+        : SvPV_const(TARG, len);
     if (!s)
        DIE(aTHX_ "panic: pp_match");
     strend = s + len;
-    rxtainted = ((pm->op_pmdynflags & PMdf_TAINTED) ||
+    rxtainted = ((RX_EXTFLAGS(rx) & RXf_TAINTED) ||
                 (PL_tainted && (pm->op_pmflags & PMf_RETAINT)));
     TAINT_NOT;
 
     RX_MATCH_UTF8_set(rx, DO_UTF8(TARG));
 
     /* PMdf_USED is set after a ?? matches once */
-    if (pm->op_pmdynflags & PMdf_USED) {
+    if (
+#ifdef USE_ITHREADS
+        SvREADONLY(PL_regex_pad[pm->op_pmoffset])
+#else
+        pm->op_pmflags & PMf_USED
+#endif
+    ) {
       failure:
        if (gimme == G_ARRAY)
            RETURN;
        RETPUSHNO;
     }
 
+
+
     /* empty pattern special-cased to use last successful pattern if possible */
-    if (!rx->prelen && PL_curpm) {
+    if (!RX_PRELEN(rx) && PL_curpm) {
        pm = PL_curpm;
        rx = PM_GETRE(pm);
     }
 
-    if (rx->minlen > (I32)len)
+    if (RX_MINLEN(rx) > (I32)len)
        goto failure;
 
     truebase = t = s;
 
     /* XXXX What part of this is needed with true \G-support? */
     if ((global = dynpm->op_pmflags & PMf_GLOBAL)) {
-       rx->startp[0] = -1;
+       RX_OFFS(rx)[0].start = -1;
        if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG)) {
            MAGIC* const mg = mg_find(TARG, PERL_MAGIC_regex_global);
            if (mg && mg->mg_len >= 0) {
-               if (!(rx->reganch & ROPT_GPOS_SEEN))
-                   rx->endp[0] = rx->startp[0] = mg->mg_len;
-               else if (rx->reganch & ROPT_ANCH_GPOS) {
+               if (!(RX_EXTFLAGS(rx) & RXf_GPOS_SEEN))
+                   RX_OFFS(rx)[0].end = RX_OFFS(rx)[0].start = mg->mg_len;
+               else if (RX_EXTFLAGS(rx) & RXf_ANCH_GPOS) {
                    r_flags |= REXEC_IGNOREPOS;
-                   rx->endp[0] = rx->startp[0] = mg->mg_len;
-               }
-               minmatch = (mg->mg_flags & MGf_MINMATCH);
+                   RX_OFFS(rx)[0].end = RX_OFFS(rx)[0].start = mg->mg_len;
+               } else if (RX_EXTFLAGS(rx) & RXf_GPOS_FLOAT) 
+                   gpos = mg->mg_len;
+               else 
+                   RX_OFFS(rx)[0].end = RX_OFFS(rx)[0].start = mg->mg_len;
+               minmatch = (mg->mg_flags & MGf_MINMATCH) ? RX_GOFS(rx) + 1 : 0;
                update_minmatch = 0;
            }
        }
     }
-    if ((!global && rx->nparens)
-           || SvTEMP(TARG) || PL_sawampersand || (pm->op_pmflags & PMf_EVAL))
+    /* XXX: comment out !global get safe $1 vars after a
+       match, BUT be aware that this leads to dramatic slowdowns on
+       /g matches against large strings.  So far a solution to this problem
+       appears to be quite tricky.
+       Test for the unsafe vars are TODO for now. */
+    if (       (!global && RX_NPARENS(rx))
+           || SvTEMP(TARG) || SvAMAGIC(TARG) || PL_sawampersand
+           || (RX_EXTFLAGS(rx) & (RXf_EVAL_SEEN|RXf_PMf_KEEPCOPY)))
        r_flags |= REXEC_COPY_STR;
     if (SvSCREAM(TARG))
        r_flags |= REXEC_SCREAM;
 
 play_it_again:
-    if (global && rx->startp[0] != -1) {
-       t = s = rx->endp[0] + truebase;
-       if ((s + rx->minlen) > strend)
+    if (global && RX_OFFS(rx)[0].start != -1) {
+       t = s = RX_OFFS(rx)[0].end + truebase - RX_GOFS(rx);
+       if ((s + RX_MINLEN(rx)) > strend || s < truebase)
            goto nope;
        if (update_minmatch++)
            minmatch = had_zerolen;
     }
-    if (rx->reganch & RE_USE_INTUIT &&
-       DO_UTF8(TARG) == ((rx->reganch & ROPT_UTF8) != 0)) {
+    if (RX_EXTFLAGS(rx) & RXf_USE_INTUIT &&
+       DO_UTF8(TARG) == (RX_UTF8(rx) != 0)) {
        /* FIXME - can PL_bostr be made const char *?  */
        PL_bostr = (char *)truebase;
-       s = CALLREG_INTUIT_START(aTHX_ rx, TARG, (char *)s, (char *)strend, r_flags, NULL);
+       s = CALLREG_INTUIT_START(rx, TARG, (char *)s, (char *)strend, r_flags, NULL);
 
        if (!s)
            goto nope;
-       if ( (rx->reganch & ROPT_CHECK_ALL)
+       if ( (RX_EXTFLAGS(rx) & RXf_CHECK_ALL)
             && !PL_sawampersand
-            && ((rx->reganch & ROPT_NOSCAN)
-                || !((rx->reganch & RE_INTUIT_TAIL)
+            && !(RX_EXTFLAGS(rx) & RXf_PMf_KEEPCOPY)
+            && ((RX_EXTFLAGS(rx) & RXf_NOSCAN)
+                || !((RX_EXTFLAGS(rx) & RXf_INTUIT_TAIL)
                      && (r_flags & REXEC_SCREAM)))
             && !SvROK(TARG))   /* Cannot trust since INTUIT cannot guess ^ */
            goto yup;
     }
-    if (CALLREGEXEC(aTHX_ rx, (char*)s, (char *)strend, (char*)truebase, minmatch, TARG, NULL, r_flags))
+    if (CALLREGEXEC(rx, (char*)s, (char *)strend, (char*)truebase,
+                    minmatch, TARG, NUM2PTR(void*, gpos), r_flags))
     {
        PL_curpm = pm;
-       if (dynpm->op_pmflags & PMf_ONCE)
-           dynpm->op_pmdynflags |= PMdf_USED;
+       if (dynpm->op_pmflags & PMf_ONCE) {
+#ifdef USE_ITHREADS
+            SvREADONLY_on(PL_regex_pad[dynpm->op_pmoffset]);
+#else
+           dynpm->op_pmflags |= PMf_USED;
+#endif
+        }
        goto gotcha;
     }
     else
@@ -1399,7 +1405,7 @@ play_it_again:
        RX_MATCH_TAINTED_on(rx);
     TAINT_IF(RX_MATCH_TAINTED(rx));
     if (gimme == G_ARRAY) {
-       const I32 nparens = rx->nparens;
+       const I32 nparens = RX_NPARENS(rx);
        I32 i = (global && !nparens) ? 1 : 0;
 
        SPAGAIN;                        /* EVAL blocks could move the stack. */
@@ -1407,10 +1413,10 @@ play_it_again:
        EXTEND_MORTAL(nparens + i);
        for (i = !i; i <= nparens; i++) {
            PUSHs(sv_newmortal());
-           if ((rx->startp[i] != -1) && rx->endp[i] != -1 ) {
-               const I32 len = rx->endp[i] - rx->startp[i];
-               s = rx->startp[i] + truebase;
-               if (rx->endp[i] < 0 || rx->startp[i] < 0 ||
+           if ((RX_OFFS(rx)[i].start != -1) && RX_OFFS(rx)[i].end != -1 ) {
+               const I32 len = RX_OFFS(rx)[i].end - RX_OFFS(rx)[i].start;
+               s = RX_OFFS(rx)[i].start + truebase;
+               if (RX_OFFS(rx)[i].end < 0 || RX_OFFS(rx)[i].start < 0 ||
                    len < 0 || len > strend - s)
                    DIE(aTHX_ "panic: pp_match start/end pointers");
                sv_setpvn(*SP, s, len);
@@ -1431,16 +1437,17 @@ play_it_again:
                    mg = sv_magicext(TARG, NULL, PERL_MAGIC_regex_global,
                                     &PL_vtbl_mglob, NULL, 0);
                }
-               if (rx->startp[0] != -1) {
-                   mg->mg_len = rx->endp[0];
-                   if (rx->startp[0] == rx->endp[0])
+               if (RX_OFFS(rx)[0].start != -1) {
+                   mg->mg_len = RX_OFFS(rx)[0].end;
+                   if (RX_OFFS(rx)[0].start + RX_GOFS(rx) == (UV)RX_OFFS(rx)[0].end)
                        mg->mg_flags |= MGf_MINMATCH;
                    else
                        mg->mg_flags &= ~MGf_MINMATCH;
                }
            }
-           had_zerolen = (rx->startp[0] != -1
-                          && rx->startp[0] == rx->endp[0]);
+           had_zerolen = (RX_OFFS(rx)[0].start != -1
+                          && (RX_OFFS(rx)[0].start + RX_GOFS(rx)
+                              == (UV)RX_OFFS(rx)[0].end));
            PUTBACK;                    /* EVAL blocks may use stack */
            r_flags |= REXEC_IGNOREPOS | REXEC_NOT_FIRST;
            goto play_it_again;
@@ -1465,9 +1472,9 @@ play_it_again:
                mg = sv_magicext(TARG, NULL, PERL_MAGIC_regex_global,
                                 &PL_vtbl_mglob, NULL, 0);
            }
-           if (rx->startp[0] != -1) {
-               mg->mg_len = rx->endp[0];
-               if (rx->startp[0] == rx->endp[0])
+           if (RX_OFFS(rx)[0].start != -1) {
+               mg->mg_len = RX_OFFS(rx)[0].end;
+               if (RX_OFFS(rx)[0].start + RX_GOFS(rx) == (UV)RX_OFFS(rx)[0].end)
                    mg->mg_flags |= MGf_MINMATCH;
                else
                    mg->mg_flags &= ~MGf_MINMATCH;
@@ -1482,58 +1489,66 @@ yup:                                    /* Confirmed by INTUIT */
        RX_MATCH_TAINTED_on(rx);
     TAINT_IF(RX_MATCH_TAINTED(rx));
     PL_curpm = pm;
-    if (dynpm->op_pmflags & PMf_ONCE)
-       dynpm->op_pmdynflags |= PMdf_USED;
+    if (dynpm->op_pmflags & PMf_ONCE) {
+#ifdef USE_ITHREADS
+        SvREADONLY_on(PL_regex_pad[dynpm->op_pmoffset]);
+#else
+        dynpm->op_pmflags |= PMf_USED;
+#endif
+    }
     if (RX_MATCH_COPIED(rx))
-       Safefree(rx->subbeg);
+       Safefree(RX_SUBBEG(rx));
     RX_MATCH_COPIED_off(rx);
-    rx->subbeg = NULL;
+    RX_SUBBEG(rx) = NULL;
     if (global) {
        /* FIXME - should rx->subbeg be const char *?  */
-       rx->subbeg = (char *) truebase;
-       rx->startp[0] = s - truebase;
+       RX_SUBBEG(rx) = (char *) truebase;
+       RX_OFFS(rx)[0].start = s - truebase;
        if (RX_MATCH_UTF8(rx)) {
-           char * const t = (char*)utf8_hop((U8*)s, rx->minlen);
-           rx->endp[0] = t - truebase;
+           char * const t = (char*)utf8_hop((U8*)s, RX_MINLENRET(rx));
+           RX_OFFS(rx)[0].end = t - truebase;
        }
        else {
-           rx->endp[0] = s - truebase + rx->minlen;
+           RX_OFFS(rx)[0].end = s - truebase + RX_MINLENRET(rx);
        }
-       rx->sublen = strend - truebase;
+       RX_SUBLEN(rx) = strend - truebase;
        goto gotcha;
     }
-    if (PL_sawampersand) {
+    if (PL_sawampersand || RX_EXTFLAGS(rx) & RXf_PMf_KEEPCOPY) {
        I32 off;
 #ifdef PERL_OLD_COPY_ON_WRITE
        if (SvIsCOW(TARG) || (SvFLAGS(TARG) & CAN_COW_MASK) == CAN_COW_FLAGS) {
            if (DEBUG_C_TEST) {
                PerlIO_printf(Perl_debug_log,
                              "Copy on write: pp_match $& capture, type %d, truebase=%p, t=%p, difference %d\n",
-                             (int) SvTYPE(TARG), truebase, t,
+                             (int) SvTYPE(TARG), (void*)truebase, (void*)t,
                              (int)(t-truebase));
            }
-           rx->saved_copy = sv_setsv_cow(rx->saved_copy, TARG);
-           rx->subbeg = (char *) SvPVX_const(rx->saved_copy) + (t - truebase);
-           assert (SvPOKp(rx->saved_copy));
+           RX_SAVED_COPY(rx) = sv_setsv_cow(RX_SAVED_COPY(rx), TARG);
+           RX_SUBBEG(rx)
+               = (char *) SvPVX_const(RX_SAVED_COPY(rx)) + (t - truebase);
+           assert (SvPOKp(RX_SAVED_COPY(rx)));
        } else
 #endif
        {
 
-           rx->subbeg = savepvn(t, strend - t);
+           RX_SUBBEG(rx) = savepvn(t, strend - t);
 #ifdef PERL_OLD_COPY_ON_WRITE
-           rx->saved_copy = NULL;
+           RX_SAVED_COPY(rx) = NULL;
 #endif
        }
-       rx->sublen = strend - t;
+       RX_SUBLEN(rx) = strend - t;
        RX_MATCH_COPIED_on(rx);
-       off = rx->startp[0] = s - t;
-       rx->endp[0] = off + rx->minlen;
+       off = RX_OFFS(rx)[0].start = s - t;
+       RX_OFFS(rx)[0].end = off + RX_MINLENRET(rx);
     }
     else {                     /* startp/endp are used by @- @+. */
-       rx->startp[0] = s - truebase;
-       rx->endp[0] = s - truebase + rx->minlen;
+       RX_OFFS(rx)[0].start = s - truebase;
+       RX_OFFS(rx)[0].end = s - truebase + RX_MINLENRET(rx);
     }
-    rx->nparens = rx->lastparen = rx->lastcloseparen = 0;      /* used by @-, @+, and $^N */
+    /* including RX_NPARENS(rx) in the below code seems highly suspicious.
+       -dmq */
+    RX_NPARENS(rx) = RX_LASTPAREN(rx) = RX_LASTCLOSEPAREN(rx) = 0;     /* used by @-, @+, and $^N */
     LEAVE_SCOPE(oldsave);
     RETPUSHYES;
 
@@ -1565,14 +1580,14 @@ Perl_do_readline(pTHX)
     const I32 gimme = GIMME_V;
 
     if (io) {
-       MAGIC * const mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar);
+       MAGIC * const mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar);
        if (mg) {
            PUSHMARK(SP);
-           XPUSHs(SvTIED_obj((SV*)io, mg));
+           XPUSHs(SvTIED_obj(MUTABLE_SV(io), mg));
            PUTBACK;
-           ENTER;
+           ENTER_with_name("call_READLINE");
            call_method("READLINE", gimme);
-           LEAVE;
+           LEAVE_with_name("call_READLINE");
            SPAGAIN;
            if (gimme == G_SCALAR) {
                SV* const result = POPs;
@@ -1592,7 +1607,7 @@ Perl_do_readline(pTHX)
                    if (av_len(GvAVn(PL_last_in_gv)) < 0) {
                        IoFLAGS(io) &= ~IOf_START;
                        do_open(PL_last_in_gv,"-",1,FALSE,O_RDONLY,0,NULL);
-                       sv_setpvn(GvSVn(PL_last_in_gv), "-", 1);
+                       sv_setpvs(GvSVn(PL_last_in_gv), "-");
                        SvSETMAGIC(GvSV(PL_last_in_gv));
                        fp = IoIFP(io);
                        goto have_fp;
@@ -1636,15 +1651,25 @@ Perl_do_readline(pTHX)
   have_fp:
     if (gimme == G_SCALAR) {
        sv = TARG;
-       if (SvROK(sv))
-           sv_unref(sv);
+       if (type == OP_RCATLINE && SvGMAGICAL(sv))
+           mg_get(sv);
+       if (SvROK(sv)) {
+           if (type == OP_RCATLINE)
+               SvPV_force_nolen(sv);
+           else
+               sv_unref(sv);
+       }
        else if (isGV_with_GP(sv)) {
            SvPV_force_nolen(sv);
        }
        SvUPGRADE(sv, SVt_PV);
        tmplen = SvLEN(sv);     /* remember if already alloced */
-       if (!tmplen && !SvREADONLY(sv))
-           Sv_Grow(sv, 80);    /* try short-buffering it */
+       if (!tmplen && !SvREADONLY(sv)) {
+            /* try short-buffering it. Please update t/op/readline.t
+            * if you change the growth length.
+            */
+           Sv_Grow(sv, 80);
+        }
        offset = 0;
        if (type == OP_RCATLINE && SvOK(sv)) {
            if (!SvPOK(sv)) {
@@ -1685,11 +1710,11 @@ Perl_do_readline(pTHX)
                (void)do_close(PL_last_in_gv, FALSE);
            }
            else if (type == OP_GLOB) {
-               if (!do_close(PL_last_in_gv, FALSE) && ckWARN(WARN_GLOB)) {
-                   Perl_warner(aTHX_ packWARN(WARN_GLOB),
-                          "glob failed (child exited with status %d%s)",
-                          (int)(STATUS_CURRENT >> 8),
-                          (STATUS_CURRENT & 0x80) ? ", core dumped" : "");
+               if (!do_close(PL_last_in_gv, FALSE)) {
+                   Perl_ck_warner(aTHX_ packWARN(WARN_GLOB),
+                                  "glob failed (child exited with status %d%s)",
+                                  (int)(STATUS_CURRENT >> 8),
+                                  (STATUS_CURRENT & 0x80) ? ", core dumped" : "");
                }
            }
            if (gimme == G_SCALAR) {
@@ -1764,13 +1789,17 @@ PP(pp_enter)
     I32 gimme = OP_GIMME(PL_op, -1);
 
     if (gimme == -1) {
-       if (cxstack_ix >= 0)
-           gimme = cxstack[cxstack_ix].blk_gimme;
-       else
+       if (cxstack_ix >= 0) {
+           /* If this flag is set, we're just inside a return, so we should
+            * store the caller's context */
+           gimme = (PL_op->op_flags & OPf_SPECIAL)
+               ? block_gimme()
+               : cxstack[cxstack_ix].blk_gimme;
+       } else
            gimme = G_SCALAR;
     }
 
-    ENTER;
+    ENTER_with_name("block");
 
     SAVETMPS;
     PUSHBLOCK(cx, CXt_BLOCK, SP);
@@ -1784,33 +1813,29 @@ PP(pp_helem)
     HE* he;
     SV **svp;
     SV * const keysv = POPs;
-    HV * const hv = (HV*)POPs;
+    HV * const hv = MUTABLE_HV(POPs);
     const U32 lval = PL_op->op_flags & OPf_MOD || LVRET;
     const U32 defer = PL_op->op_private & OPpLVAL_DEFER;
     SV *sv;
     const U32 hash = (SvIsCOW_shared_hash(keysv)) ? SvSHARED_HASH(keysv) : 0;
-    I32 preeminent = 0;
+    const bool localizing = PL_op->op_private & OPpLVAL_INTRO;
+    bool preeminent = TRUE;
 
     if (SvTYPE(hv) != SVt_PVHV)
        RETPUSHUNDEF;
 
-    if (PL_op->op_private & OPpLVAL_INTRO) {
+    if (localizing) {
        MAGIC *mg;
        HV *stash;
-       /* does the element we're localizing already exist? */
-       preeminent = /* can we determine whether it exists? */
-           (    !SvRMAGICAL(hv)
-               || mg_find((SV*)hv, PERL_MAGIC_env)
-               || (     (mg = mg_find((SV*)hv, PERL_MAGIC_tied))
-                       /* Try to preserve the existenceness of a tied hash
-                       * element by using EXISTS and DELETE if possible.
-                       * Fallback to FETCH and STORE otherwise */
-                   && (stash = SvSTASH(SvRV(SvTIED_obj((SV*)hv, mg))))
-                   && gv_fetchmethod_autoload(stash, "EXISTS", TRUE)
-                   && gv_fetchmethod_autoload(stash, "DELETE", TRUE)
-               )
-           ) ? hv_exists_ent(hv, keysv, 0) : 1;
+
+       /* If we can determine whether the element exist,
+        * Try to preserve the existenceness of a tied hash
+        * element by using EXISTS and DELETE if possible.
+        * Fallback to FETCH and STORE otherwise. */
+       if (SvCANEXISTDELETE(hv) || mg_find((const SV *)hv, PERL_MAGIC_env))
+           preeminent = hv_exists_ent(hv, keysv, 0);
     }
+
     he = hv_fetch_ent(hv, keysv, lval && !defer, hash);
     svp = he ? &HeVAL(he) : NULL;
     if (lval) {
@@ -1818,7 +1843,7 @@ PP(pp_helem)
            SV* lv;
            SV* key2;
            if (!defer) {
-               DIE(aTHX_ PL_no_helem_sv, keysv);
+               DIE(aTHX_ PL_no_helem_sv, SVfARG(keysv));
            }
            lv = sv_newmortal();
            sv_upgrade(lv, SVt_PVLV);
@@ -1830,31 +1855,33 @@ PP(pp_helem)
            PUSHs(lv);
            RETURN;
        }
-       if (PL_op->op_private & OPpLVAL_INTRO) {
+       if (localizing) {
            if (HvNAME_get(hv) && isGV(*svp))
-               save_gp((GV*)*svp, !(PL_op->op_flags & OPf_SPECIAL));
-           else {
-               if (!preeminent) {
-                   STRLEN keylen;
-                   const char * const key = SvPV_const(keysv, keylen);
-                   SAVEDELETE(hv, savepvn(key,keylen),
-                              SvUTF8(keysv) ? -(I32)keylen : (I32)keylen);
-               } else
-                   save_helem(hv, keysv, svp);
-            }
+               save_gp(MUTABLE_GV(*svp), !(PL_op->op_flags & OPf_SPECIAL));
+           else if (preeminent)
+               save_helem_flags(hv, keysv, svp,
+                    (PL_op->op_flags & OPf_SPECIAL) ? 0 : SAVEf_SETMAGIC);
+           else
+               SAVEHDELETE(hv, keysv);
        }
        else if (PL_op->op_private & OPpDEREF)
            vivify_ref(*svp, PL_op->op_private & OPpDEREF);
     }
     sv = (svp ? *svp : &PL_sv_undef);
-    /* This makes C<local $tied{foo} = $tied{foo}> possible.
-     * Pushing the magical RHS on to the stack is useless, since
-     * that magic is soon destined to be misled by the local(),
-     * and thus the later pp_sassign() will fail to mg_get() the
-     * old value.  This should also cure problems with delayed
-     * mg_get()s.  GSAR 98-07-03 */
-    if (!lval && SvGMAGICAL(sv))
-       sv = sv_mortalcopy(sv);
+    /* Originally this did a conditional C<sv = sv_mortalcopy(sv)>; this
+     * was to make C<local $tied{foo} = $tied{foo}> possible.
+     * However, it seems no longer to be needed for that purpose, and
+     * introduced a new bug: stuff like C<while ($hash{taintedval} =~ /.../g>
+     * would loop endlessly since the pos magic is getting set on the
+     * mortal copy and lost. However, the copy has the effect of
+     * triggering the get magic, and losing it altogether made things like
+     * c<$tied{foo};> in void context no longer do get magic, which some
+     * code relied on. Also, delayed triggering of magic on @+ and friends
+     * meant the original regex may be out of scope by now. So as a
+     * compromise, do the get magic here. (The MGf_GSKIP flag will stop it
+     * being called too many times). */
+    if (!lval && SvRMAGICAL(hv) && SvGMAGICAL(sv))
+       mg_get(sv);
     PUSHs(sv);
     RETURN;
 }
@@ -1874,13 +1901,7 @@ PP(pp_leave)
 
     POPBLOCK(cx,newpm);
 
-    gimme = OP_GIMME(PL_op, -1);
-    if (gimme == -1) {
-       if (cxstack_ix >= 0)
-           gimme = cxstack[cxstack_ix].blk_gimme;
-       else
-           gimme = G_SCALAR;
-    }
+    gimme = OP_GIMME(PL_op, (cxstack_ix >= 0) ? gimme : G_SCALAR);
 
     TAINT_NOT;
     if (gimme == G_VOID)
@@ -1911,7 +1932,7 @@ PP(pp_leave)
     }
     PL_curpm = newpm;  /* Don't pop $1 et al till now */
 
-    LEAVE;
+    LEAVE_with_name("block");
 
     RETURN;
 }
@@ -1921,23 +1942,24 @@ PP(pp_iter)
     dVAR; dSP;
     register PERL_CONTEXT *cx;
     SV *sv, *oldsv;
-    AV* av;
     SV **itersvp;
+    AV *av = NULL; /* used for LOOP_FOR on arrays and the stack */
+    bool av_is_stack = FALSE;
 
     EXTEND(SP, 1);
     cx = &cxstack[cxstack_ix];
-    if (CxTYPE(cx) != CXt_LOOP)
+    if (!CxTYPE_is_LOOP(cx))
        DIE(aTHX_ "panic: pp_iter");
 
     itersvp = CxITERVAR(cx);
-    av = cx->blk_loop.iterary;
-    if (SvTYPE(av) != SVt_PVAV) {
-       /* iterate ($min .. $max) */
-       if (cx->blk_loop.iterlval) {
+    if (CxTYPE(cx) == CXt_LOOP_LAZYSV) {
            /* string increment */
-           register SV* cur = cx->blk_loop.iterlval;
+           SV* cur = cx->blk_loop.state_u.lazysv.cur;
+           SV *end = cx->blk_loop.state_u.lazysv.end;
+           /* If the maximum is !SvOK(), pp_enteriter substitutes PL_sv_no.
+              It has SvPVX of "" and SvCUR of 0, which is what we want.  */
            STRLEN maxlen = 0;
-           const char *max = SvOK((SV*)av) ? SvPV_const((SV*)av, maxlen) : "";
+           const char *max = SvPV_const(end, maxlen);
            if (!SvNIOK(cur) && SvCUR(cur) <= maxlen) {
                if (SvREFCNT(*itersvp) == 1 && !SvMAGICAL(*itersvp)) {
                    /* safe to reuse old SV */
@@ -1959,15 +1981,16 @@ PP(pp_iter)
                RETPUSHYES;
            }
            RETPUSHNO;
-       }
+    }
+    else if (CxTYPE(cx) == CXt_LOOP_LAZYIV) {
        /* integer increment */
-       if (cx->blk_loop.iterix > cx->blk_loop.itermax)
+       if (cx->blk_loop.state_u.lazyiv.cur > cx->blk_loop.state_u.lazyiv.end)
            RETPUSHNO;
 
        /* don't risk potential race */
        if (SvREFCNT(*itersvp) == 1 && !SvMAGICAL(*itersvp)) {
            /* safe to reuse old SV */
-           sv_setiv(*itersvp, cx->blk_loop.iterix++);
+           sv_setiv(*itersvp, cx->blk_loop.state_u.lazyiv.cur++);
        }
        else
        {
@@ -1975,37 +1998,52 @@ PP(pp_iter)
             * completely new SV for closures/references to work as they
             * used to */
            oldsv = *itersvp;
-           *itersvp = newSViv(cx->blk_loop.iterix++);
+           *itersvp = newSViv(cx->blk_loop.state_u.lazyiv.cur++);
            SvREFCNT_dec(oldsv);
        }
+
+       /* Handle end of range at IV_MAX */
+       if ((cx->blk_loop.state_u.lazyiv.cur == IV_MIN) &&
+           (cx->blk_loop.state_u.lazyiv.end == IV_MAX))
+       {
+           cx->blk_loop.state_u.lazyiv.cur++;
+           cx->blk_loop.state_u.lazyiv.end++;
+       }
+
        RETPUSHYES;
     }
 
     /* iterate array */
+    assert(CxTYPE(cx) == CXt_LOOP_FOR);
+    av = cx->blk_loop.state_u.ary.ary;
+    if (!av) {
+       av_is_stack = TRUE;
+       av = PL_curstack;
+    }
     if (PL_op->op_private & OPpITER_REVERSED) {
-       /* In reverse, use itermax as the min :-)  */
-       if (cx->blk_loop.iterix <= cx->blk_loop.itermax)
+       if (cx->blk_loop.state_u.ary.ix <= (av_is_stack
+                                   ? cx->blk_loop.resetsp + 1 : 0))
            RETPUSHNO;
 
        if (SvMAGICAL(av) || AvREIFY(av)) {
-           SV * const * const svp = av_fetch(av, --cx->blk_loop.iterix, FALSE);
+           SV * const * const svp = av_fetch(av, --cx->blk_loop.state_u.ary.ix, FALSE);
            sv = svp ? *svp : NULL;
        }
        else {
-           sv = AvARRAY(av)[--cx->blk_loop.iterix];
+           sv = AvARRAY(av)[--cx->blk_loop.state_u.ary.ix];
        }
     }
     else {
-       if (cx->blk_loop.iterix >= (av == PL_curstack ? cx->blk_oldsp :
+       if (cx->blk_loop.state_u.ary.ix >= (av_is_stack ? cx->blk_oldsp :
                                    AvFILL(av)))
            RETPUSHNO;
 
        if (SvMAGICAL(av) || AvREIFY(av)) {
-           SV * const * const svp = av_fetch(av, ++cx->blk_loop.iterix, FALSE);
+           SV * const * const svp = av_fetch(av, ++cx->blk_loop.state_u.ary.ix, FALSE);
            sv = svp ? *svp : NULL;
        }
        else {
-           sv = AvARRAY(av)[++cx->blk_loop.iterix];
+           sv = AvARRAY(av)[++cx->blk_loop.state_u.ary.ix];
        }
     }
 
@@ -2014,32 +2052,24 @@ PP(pp_iter)
        Perl_croak(aTHX_ "Use of freed value in iteration");
     }
 
-    if (sv)
+    if (sv) {
        SvTEMP_off(sv);
+       SvREFCNT_inc_simple_void_NN(sv);
+    }
     else
        sv = &PL_sv_undef;
-    if (av != PL_curstack && sv == &PL_sv_undef) {
-       SV *lv = cx->blk_loop.iterlval;
-       if (lv && SvREFCNT(lv) > 1) {
-           SvREFCNT_dec(lv);
-           lv = NULL;
-       }
-       if (lv)
-           SvREFCNT_dec(LvTARG(lv));
-       else {
-           lv = cx->blk_loop.iterlval = newSV(0);
-           sv_upgrade(lv, SVt_PVLV);
-           LvTYPE(lv) = 'y';
-           sv_magic(lv, NULL, PERL_MAGIC_defelem, NULL, 0);
-       }
+    if (!av_is_stack && sv == &PL_sv_undef) {
+       SV *lv = newSV_type(SVt_PVLV);
+       LvTYPE(lv) = 'y';
+       sv_magic(lv, NULL, PERL_MAGIC_defelem, NULL, 0);
        LvTARG(lv) = SvREFCNT_inc_simple(av);
-       LvTARGOFF(lv) = cx->blk_loop.iterix;
+       LvTARGOFF(lv) = cx->blk_loop.state_u.ary.ix;
        LvTARGLEN(lv) = (STRLEN)UV_MAX;
-       sv = (SV*)lv;
+       sv = lv;
     }
 
     oldsv = *itersvp;
-    *itersvp = SvREFCNT_inc_simple_NN(sv);
+    *itersvp = sv;
     SvREFCNT_dec(oldsv);
 
     RETPUSHYES;
@@ -2060,22 +2090,25 @@ PP(pp_subst)
     I32 maxiters;
     register I32 i;
     bool once;
-    bool rxtainted;
+    U8 rxtainted;
     char *orig;
-    I32 r_flags;
+    U8 r_flags;
     register REGEXP *rx = PM_GETRE(pm);
     STRLEN len;
     int force_on_match = 0;
     const I32 oldsave = PL_savestack_ix;
     STRLEN slen;
     bool doutf8 = FALSE;
+    I32 matched;
 #ifdef PERL_OLD_COPY_ON_WRITE
     bool is_cow;
 #endif
     SV *nsv = NULL;
-
     /* known replacement string? */
     register SV *dstr = (pm->op_pmflags & PMf_CONST) ? POPs : NULL;
+
+    PERL_ASYNC_CHECK();
+
     if (PL_op->op_flags & OPf_STACKED)
        TARG = POPs;
     else if (PL_op->op_private & OPpTARGET_MY)
@@ -2085,6 +2118,11 @@ PP(pp_subst)
        EXTEND(SP,1);
     }
 
+    /* In non-destructive replacement mode, duplicate target scalar so it
+     * remains unchanged. */
+    if (rpm->op_pmflags & PMf_NONDESTRUCT)
+       TARG = sv_2mortal(newSVsv(TARG));
+
 #ifdef PERL_OLD_COPY_ON_WRITE
     /* Awooga. Awooga. "bool" types that are actually char are dangerous,
        because they make integers such as 256 "false".  */
@@ -2098,15 +2136,17 @@ PP(pp_subst)
        !is_cow &&
 #endif
        (SvREADONLY(TARG)
-       || ( (SvTYPE(TARG) == SVt_PVGV || SvTYPE(TARG) > SVt_PVLV)
+        || ( ((SvTYPE(TARG) == SVt_PVGV && isGV_with_GP(TARG))
+              || SvTYPE(TARG) > SVt_PVLV)
             && !(SvTYPE(TARG) == SVt_PVGV && SvFAKE(TARG)))))
-       DIE(aTHX_ PL_no_modify);
+       Perl_croak_no_modify(aTHX);
     PUTBACK;
 
+  setup_match:
     s = SvPV_mutable(TARG, len);
     if (!SvPOKp(TARG) || SvTYPE(TARG) == SVt_PVGV)
        force_on_match = 1;
-    rxtainted = ((pm->op_pmdynflags & PMdf_TAINTED) ||
+    rxtainted = ((RX_EXTFLAGS(rx) & RXf_TAINTED) ||
                 (PL_tainted && (pm->op_pmflags & PMf_RETAINT)));
     if (PL_tainted)
        rxtainted |= 2;
@@ -2124,28 +2164,29 @@ PP(pp_subst)
                                   position, once with zero-length,
                                   second time with non-zero. */
 
-    if (!rx->prelen && PL_curpm) {
+    if (!RX_PRELEN(rx) && PL_curpm) {
        pm = PL_curpm;
        rx = PM_GETRE(pm);
     }
-    r_flags = (rx->nparens || SvTEMP(TARG) || PL_sawampersand
-           || (pm->op_pmflags & PMf_EVAL))
+    r_flags = (RX_NPARENS(rx) || SvTEMP(TARG) || PL_sawampersand
+           || (RX_EXTFLAGS(rx) & (RXf_EVAL_SEEN|RXf_PMf_KEEPCOPY)) )
               ? REXEC_COPY_STR : 0;
     if (SvSCREAM(TARG))
        r_flags |= REXEC_SCREAM;
 
     orig = m = s;
-    if (rx->reganch & RE_USE_INTUIT) {
+    if (RX_EXTFLAGS(rx) & RXf_USE_INTUIT) {
        PL_bostr = orig;
-       s = CALLREG_INTUIT_START(aTHX_ rx, TARG, s, strend, r_flags, NULL);
+       s = CALLREG_INTUIT_START(rx, TARG, s, strend, r_flags, NULL);
 
        if (!s)
            goto nope;
        /* How to do it in subst? */
-/*     if ( (rx->reganch & ROPT_CHECK_ALL)
+/*     if ( (RX_EXTFLAGS(rx) & RXf_CHECK_ALL)
             && !PL_sawampersand
-            && ((rx->reganch & ROPT_NOSCAN)
-                || !((rx->reganch & RE_INTUIT_TAIL)
+            && !(RX_EXTFLAGS(rx) & RXf_KEEPCOPY)
+            && ((RX_EXTFLAGS(rx) & RXf_NOSCAN)
+                || !((RX_EXTFLAGS(rx) & RXf_INTUIT_TAIL)
                      && (r_flags & REXEC_SCREAM))))
            goto yup;
 */
@@ -2153,9 +2194,26 @@ PP(pp_subst)
 
     /* only replace once? */
     once = !(rpm->op_pmflags & PMf_GLOBAL);
-
+    matched = CALLREGEXEC(rx, s, strend, orig, 0, TARG, NULL,
+                        r_flags | REXEC_CHECKED);
     /* known replacement string? */
     if (dstr) {
+
+       /* Upgrade the source if the replacement is utf8 but the source is not,
+        * but only if it matched; see
+        * http://www.nntp.perl.org/group/perl.perl5.porters/2010/04/msg158809.html
+        */
+       if (matched && DO_UTF8(dstr) && ! DO_UTF8(TARG)) {
+           const STRLEN new_len = sv_utf8_upgrade(TARG);
+
+           /* If the lengths are the same, the pattern contains only
+            * invariants, can keep going; otherwise, various internal markers
+            * could be off, so redo */
+           if (new_len != len) {
+               goto setup_match;
+           }
+       }
+
        /* replacement needing upgrading? */
        if (DO_UTF8(TARG) && !doutf8) {
             nsv = sv_newmortal();
@@ -2182,14 +2240,16 @@ PP(pp_subst)
 #ifdef PERL_OLD_COPY_ON_WRITE
        && !is_cow
 #endif
-       && (I32)clen <= rx->minlen && (once || !(r_flags & REXEC_COPY_STR))
-       && !(rx->reganch & ROPT_LOOKBEHIND_SEEN)
+       && (I32)clen <= RX_MINLENRET(rx) && (once || !(r_flags & REXEC_COPY_STR))
+       && !(RX_EXTFLAGS(rx) & RXf_LOOKBEHIND_SEEN)
        && (!doutf8 || SvUTF8(TARG))) {
-       if (!CALLREGEXEC(aTHX_ rx, s, strend, orig, 0, TARG, NULL,
-                        r_flags | REXEC_CHECKED))
+       if (!matched)
        {
            SPAGAIN;
-           PUSHs(&PL_sv_no);
+           if (rpm->op_pmflags & PMf_NONDESTRUCT)
+               PUSHs(TARG);
+           else
+               PUSHs(&PL_sv_no);
            LEAVE_SCOPE(oldsave);
            RETURN;
        }
@@ -2209,8 +2269,8 @@ PP(pp_subst)
        SvSCREAM_off(TARG);     /* disable possible screamer */
        if (once) {
            rxtainted |= RX_MATCH_TAINTED(rx);
-           m = orig + rx->startp[0];
-           d = orig + rx->endp[0];
+           m = orig + RX_OFFS(rx)[0].start;
+           d = orig + RX_OFFS(rx)[0].end;
            s = orig;
            if (m - s > strend - d) {  /* faster to shorten from end */
                if (clen) {
@@ -2228,10 +2288,8 @@ PP(pp_subst)
            else if ((i = m - s)) {     /* faster from front */
                d -= clen;
                m = d;
+               Move(s, d - i, i, char);
                sv_chop(TARG, d-i);
-               s += i;
-               while (i--)
-                   *--d = *--s;
                if (clen)
                    Copy(c, m, clen, char);
            }
@@ -2245,14 +2303,17 @@ PP(pp_subst)
            }
            TAINT_IF(rxtainted & 1);
            SPAGAIN;
-           PUSHs(&PL_sv_yes);
+           if (rpm->op_pmflags & PMf_NONDESTRUCT)
+               PUSHs(TARG);
+           else
+               PUSHs(&PL_sv_yes);
        }
        else {
            do {
                if (iters++ > maxiters)
                    DIE(aTHX_ "Substitution loop");
                rxtainted |= RX_MATCH_TAINTED(rx);
-               m = rx->startp[0] + orig;
+               m = RX_OFFS(rx)[0].start + orig;
                if ((i = m - s)) {
                    if (s != d)
                        Move(s, d, i, char);
@@ -2262,8 +2323,8 @@ PP(pp_subst)
                    Copy(c, d, clen, char);
                    d += clen;
                }
-               s = rx->endp[0] + orig;
-           } while (CALLREGEXEC(aTHX_ rx, s, strend, orig, s == m,
+               s = RX_OFFS(rx)[0].end + orig;
+           } while (CALLREGEXEC(rx, s, strend, orig, s == m,
                                 TARG, NULL,
                                 /* don't match same null twice */
                                 REXEC_NOT_FIRST|REXEC_IGNOREPOS));
@@ -2274,7 +2335,10 @@ PP(pp_subst)
            }
            TAINT_IF(rxtainted & 1);
            SPAGAIN;
-           PUSHs(sv_2mortal(newSViv((I32)iters)));
+           if (rpm->op_pmflags & PMf_NONDESTRUCT)
+               PUSHs(TARG);
+           else
+               mPUSHi((I32)iters);
        }
        (void)SvPOK_only_UTF8(TARG);
        TAINT_IF(rxtainted);
@@ -2290,8 +2354,7 @@ PP(pp_subst)
        RETURN;
     }
 
-    if (CALLREGEXEC(aTHX_ rx, s, strend, orig, 0, TARG, NULL,
-                   r_flags | REXEC_CHECKED))
+    if (matched)
     {
        if (force_on_match) {
            force_on_match = 0;
@@ -2302,40 +2365,38 @@ PP(pp_subst)
       have_a_cow:
 #endif
        rxtainted |= RX_MATCH_TAINTED(rx);
-       dstr = newSVpvn(m, s-m);
+       dstr = newSVpvn_utf8(m, s-m, DO_UTF8(TARG));
        SAVEFREESV(dstr);
-       if (DO_UTF8(TARG))
-           SvUTF8_on(dstr);
        PL_curpm = pm;
        if (!c) {
            register PERL_CONTEXT *cx;
            SPAGAIN;
            PUSHSUBST(cx);
-           RETURNOP(cPMOP->op_pmreplroot);
+           RETURNOP(cPMOP->op_pmreplrootu.op_pmreplroot);
        }
        r_flags |= REXEC_IGNOREPOS | REXEC_NOT_FIRST;
        do {
            if (iters++ > maxiters)
                DIE(aTHX_ "Substitution loop");
            rxtainted |= RX_MATCH_TAINTED(rx);
-           if (RX_MATCH_COPIED(rx) && rx->subbeg != orig) {
+           if (RX_MATCH_COPIED(rx) && RX_SUBBEG(rx) != orig) {
                m = s;
                s = orig;
-               orig = rx->subbeg;
+               orig = RX_SUBBEG(rx);
                s = orig + (m - s);
                strend = s + (strend - m);
            }
-           m = rx->startp[0] + orig;
+           m = RX_OFFS(rx)[0].start + orig;
            if (doutf8 && !SvUTF8(dstr))
                sv_catpvn_utf8_upgrade(dstr, s, m - s, nsv);
             else
                sv_catpvn(dstr, s, m-s);
-           s = rx->endp[0] + orig;
+           s = RX_OFFS(rx)[0].end + orig;
            if (clen)
                sv_catpvn(dstr, c, clen);
            if (once)
                break;
-       } while (CALLREGEXEC(aTHX_ rx, s, strend, orig, s == m,
+       } while (CALLREGEXEC(rx, s, strend, orig, s == m,
                             TARG, NULL, r_flags));
        if (doutf8 && !DO_UTF8(TARG))
            sv_catpvn_utf8_upgrade(dstr, s, strend - s, nsv);
@@ -2363,7 +2424,10 @@ PP(pp_subst)
 
        TAINT_IF(rxtainted & 1);
        SPAGAIN;
-       PUSHs(sv_2mortal(newSViv((I32)iters)));
+       if (rpm->op_pmflags & PMf_NONDESTRUCT)
+           PUSHs(TARG);
+       else
+           mPUSHi((I32)iters);
 
        (void)SvPOK_only(TARG);
        if (doutf8)
@@ -2379,7 +2443,10 @@ PP(pp_subst)
 nope:
 ret_no:
     SPAGAIN;
-    PUSHs(&PL_sv_no);
+    if (rpm->op_pmflags & PMf_NONDESTRUCT)
+       PUSHs(TARG);
+    else
+       PUSHs(&PL_sv_no);
     LEAVE_SCOPE(oldsave);
     RETURN;
 }
@@ -2391,14 +2458,15 @@ PP(pp_grepwhile)
     if (SvTRUEx(POPs))
        PL_stack_base[PL_markstack_ptr[-1]++] = PL_stack_base[*PL_markstack_ptr];
     ++*PL_markstack_ptr;
-    LEAVE;                                     /* exit inner scope */
+    FREETMPS;
+    LEAVE_with_name("grep_item");                                      /* exit inner scope */
 
     /* All done yet? */
     if (PL_stack_base + *PL_markstack_ptr > SP) {
        I32 items;
        const I32 gimme = GIMME_V;
 
-       LEAVE;                                  /* exit outer scope */
+       LEAVE_with_name("grep");                                        /* exit outer scope */
        (void)POPMARK;                          /* pop src */
        items = --*PL_markstack_ptr - PL_markstack_ptr[-1];
        (void)POPMARK;                          /* pop dst */
@@ -2421,7 +2489,7 @@ PP(pp_grepwhile)
     else {
        SV *src;
 
-       ENTER;                                  /* enter inner scope */
+       ENTER_with_name("grep_item");                                   /* enter inner scope */
        SAVEVPTR(PL_curpm);
 
        src = PL_stack_base[*PL_markstack_ptr];
@@ -2429,7 +2497,7 @@ PP(pp_grepwhile)
        if (PL_op->op_private & OPpGREP_LEX)
            PAD_SVl(PL_op->op_targ) = src;
        else
-           DEFSV = src;
+           DEFSV_set(src);
 
        RETURNOP(cLOGOP->op_other);
     }
@@ -2516,7 +2584,7 @@ PP(pp_leavesublv)
 
     TAINT_NOT;
 
-    if (cx->blk_sub.lval & OPpENTERSUB_INARGS) {
+    if (CxLVAL(cx) & OPpENTERSUB_INARGS) {
        /* We are an argument to a function or grep().
         * This kind of lvalueness was legal before lvalue
         * subroutines too, so be backward compatible:
@@ -2527,6 +2595,29 @@ PP(pp_leavesublv)
        if (gimme == G_SCALAR)
            goto temporise;
        if (gimme == G_ARRAY) {
+           mark = newsp + 1;
+           /* We want an array here, but padav will have left us an arrayref for an lvalue,
+            * so we need to expand it */
+           if(SvTYPE(*mark) == SVt_PVAV) {
+               AV *const av = MUTABLE_AV(*mark);
+               const I32 maxarg = AvFILL(av) + 1;
+               (void)POPs; /* get rid of the array ref */
+               EXTEND(SP, maxarg);
+               if (SvRMAGICAL(av)) {
+                   U32 i;
+                   for (i=0; i < (U32)maxarg; i++) {
+                       SV ** const svp = av_fetch(av, i, FALSE);
+                       SP[i+1] = svp
+                           ? SvGMAGICAL(*svp) ? (mg_get(*svp), *svp) : *svp
+                           : &PL_sv_undef;
+                   }
+               }
+               else {
+                   Copy(AvARRAY(av), SP+1, maxarg, SV*);
+               }
+               SP += maxarg;
+               PUTBACK;
+           }
            if (!CvLVALUE(cx->blk_sub.cv))
                goto temporise_array;
            EXTEND_MORTAL(SP - newsp);
@@ -2543,7 +2634,7 @@ PP(pp_leavesublv)
            }
        }
     }
-    else if (cx->blk_sub.lval) {     /* Leave it as it is if we can. */
+    else if (CxLVAL(cx)) {     /* Leave it as it is if we can. */
        /* Here we go for robustness, not for speed, so we change all
         * the refcounts so the caller gets a live guy. Cannot set
         * TEMP, so sv_2mortal is out of question. */
@@ -2559,10 +2650,13 @@ PP(pp_leavesublv)
            MARK = newsp + 1;
            EXTEND_MORTAL(1);
            if (MARK == SP) {
-               /* Temporaries are bad unless they happen to be elements
-                * of a tied hash or array */
-               if (SvFLAGS(TOPs) & (SVs_TEMP | SVs_PADTMP | SVf_READONLY) &&
-                   !(SvRMAGICAL(TOPs) && mg_find(TOPs, PERL_MAGIC_tiedelem))) {
+               /* Temporaries are bad unless they happen to have set magic
+                * attached, such as the elements of a tied hash or array */
+               if ((SvFLAGS(TOPs) & (SVs_TEMP | SVs_PADTMP) ||
+                    (SvFLAGS(TOPs) & (SVf_READONLY | SVf_FAKE))
+                      == SVf_READONLY
+                   ) &&
+                   !SvSMAGICAL(TOPs)) {
                    LEAVE;
                    cxstack_ix--;
                    POPSUB(cx,sv);
@@ -2660,45 +2754,6 @@ PP(pp_leavesublv)
     return cx->blk_sub.retop;
 }
 
-
-STATIC CV *
-S_get_db_sub(pTHX_ SV **svp, CV *cv)
-{
-    dVAR;
-    SV * const dbsv = GvSVn(PL_DBsub);
-
-    save_item(dbsv);
-    if (!PERLDB_SUB_NN) {
-       GV * const gv = CvGV(cv);
-
-       if ( (CvFLAGS(cv) & (CVf_ANON | CVf_CLONED))
-            || strEQ(GvNAME(gv), "END")
-            || ((GvCV(gv) != cv) && /* Could be imported, and old sub redefined. */
-                !( (SvTYPE(*svp) == SVt_PVGV) && (GvCV((GV*)*svp) == cv) ))) {
-           /* Use GV from the stack as a fallback. */
-           /* GV is potentially non-unique, or contain different CV. */
-           SV * const tmp = newRV((SV*)cv);
-           sv_setsv(dbsv, tmp);
-           SvREFCNT_dec(tmp);
-       }
-       else {
-           gv_efullname3(dbsv, gv, NULL);
-       }
-    }
-    else {
-       const int type = SvTYPE(dbsv);
-       if (type < SVt_PVIV && type != SVt_IV)
-           sv_upgrade(dbsv, SVt_PVIV);
-       (void)SvIOK_on(dbsv);
-       SvIV_set(dbsv, PTR2IV(cv));     /* Do it the quickest way  */
-    }
-
-    if (CvISXSUB(cv))
-       PL_curcopdb = PL_curcop;
-    cv = GvCV(PL_DBsub);
-    return cv;
-}
-
 PP(pp_entersub)
 {
     dVAR; dSP; dPOPss;
@@ -2713,7 +2768,10 @@ PP(pp_entersub)
     switch (SvTYPE(sv)) {
        /* This is overwhelming the most common case:  */
     case SVt_PVGV:
-       if (!(cv = GvCVu((GV*)sv))) {
+       if (!isGV_with_GP(sv))
+           DIE(aTHX_ "Not a CODE reference");
+      we_have_a_glob:
+       if (!(cv = GvCVu((const GV *)sv))) {
            HV *stash;
            cv = sv_2cv(sv, &stash, &gv, 0);
        }
@@ -2723,36 +2781,34 @@ PP(pp_entersub)
            goto try_autoload;
        }
        break;
+    case SVt_PVLV:
+       if(isGV_with_GP(sv)) goto we_have_a_glob;
+       /*FALLTHROUGH*/
     default:
-       if (!SvROK(sv)) {
+       if (sv == &PL_sv_yes) {         /* unfound import, ignore */
+           if (hasargs)
+               SP = PL_stack_base + POPMARK;
+           else
+               (void)POPMARK;
+           RETURN;
+       }
+       SvGETMAGIC(sv);
+       if (SvROK(sv)) {
+           sv = amagic_deref_call(sv, to_cv_amg);
+           /* Don't SPAGAIN here.  */
+       }
+       else {
            const char *sym;
-           if (sv == &PL_sv_yes) {             /* unfound import, ignore */
-               if (hasargs)
-                   SP = PL_stack_base + POPMARK;
-               RETURN;
-           }
-           if (SvGMAGICAL(sv)) {
-               mg_get(sv);
-               if (SvROK(sv))
-                   goto got_rv;
-               sym = SvPOKp(sv) ? SvPVX_const(sv) : NULL;
-           }
-           else {
-               sym = SvPV_nolen_const(sv);
-            }
+           STRLEN len;
+           sym = SvPV_nomg_const(sv, len);
            if (!sym)
                DIE(aTHX_ PL_no_usym, "a subroutine");
            if (PL_op->op_private & HINT_STRICT_REFS)
-               DIE(aTHX_ PL_no_symref, sym, "a subroutine");
-           cv = get_cv(sym, TRUE);
+               DIE(aTHX_ "Can't use string (\"%.32s\"%s) as a subroutine ref while \"strict refs\" in use", sym, len>32 ? "..." : "");
+           cv = get_cvn_flags(sym, len, GV_ADD|SvUTF8(sv));
            break;
        }
-  got_rv:
-       {
-           SV * const * sp = &sv;              /* Used in tryAMAGICunDEREF macro. */
-           tryAMAGICunDEREF(to_cv);
-       }       
-       cv = (CV*)SvRV(sv);
+       cv = MUTABLE_CV(SvRV(sv));
        if (SvTYPE(cv) == SVt_PVCV)
            break;
        /* FALL THROUGH */
@@ -2761,7 +2817,7 @@ PP(pp_entersub)
        DIE(aTHX_ "Not a CODE reference");
        /* This is the second most common case:  */
     case SVt_PVCV:
-       cv = (CV*)sv;
+       cv = MUTABLE_CV(sv);
        break;
     }
 
@@ -2769,6 +2825,8 @@ PP(pp_entersub)
     SAVETMPS;
 
   retry:
+    if (CvCLONE(cv) && ! CvCLONED(cv))
+       DIE(aTHX_ "Closure prototype called");
     if (!CvROOT(cv) && !CvXSUB(cv)) {
        GV* autogv;
        SV* sub_name;
@@ -2793,7 +2851,7 @@ try_autoload:
            else {
                sub_name = sv_newmortal();
                gv_efullname3(sub_name, gv, NULL);
-               DIE(aTHX_ "Undefined subroutine &%"SVf" called", (void*)sub_name);
+               DIE(aTHX_ "Undefined subroutine &%"SVf" called", SVfARG(sub_name));
            }
        }
        if (!cv)
@@ -2803,10 +2861,18 @@ try_autoload:
 
     gimme = GIMME_V;
     if ((PL_op->op_private & OPpENTERSUB_DB) && GvCV(PL_DBsub) && !CvNODEBUG(cv)) {
-        if (CvASSERTION(cv) && PL_DBassertion)
-           sv_setiv(PL_DBassertion, 1);
-       
-       cv = get_db_sub(&sv, cv);
+        Perl_get_db_sub(aTHX_ &sv, cv);
+        if (CvISXSUB(cv))
+            PL_curcopdb = PL_curcop;
+         if (CvLVALUE(cv)) {
+             /* check for lsub that handles lvalue subroutines */
+            cv = GvCV(gv_HVadd(gv_fetchpvs("DB::lsub", GV_ADDMULTI, SVt_PVHV)));
+             /* if lsub not found then fall back to DB::sub */
+            if (!cv) cv = GvCV(PL_DBsub);
+         } else {
+             cv = GvCV(PL_DBsub);
+         }
+
        if (!cv || (!CvXSUB(cv) && !CvSTART(cv)))
            DIE(aTHX_ "No DB::sub routine defined");
     }
@@ -2831,9 +2897,8 @@ try_autoload:
        }
        SAVECOMPPAD();
        PAD_SET_CUR_NOSAVE(padlist, CvDEPTH(cv));
-       if (hasargs)
-       {
-           AV* const av = (AV*)PAD_SVl(0);
+       if (hasargs) {
+           AV *const av = MUTABLE_AV(PAD_SVl(0));
            if (AvREAL(av)) {
                /* @_ is normally not REAL--this should only ever
                 * happen when DB::sub() calls things that modify @_ */
@@ -2842,7 +2907,7 @@ try_autoload:
                AvREIFY_on(av);
            }
            cx->blk_sub.savearray = GvAV(PL_defgv);
-           GvAV(PL_defgv) = (AV*)SvREFCNT_inc_simple(av);
+           GvAV(PL_defgv) = MUTABLE_AV(SvREFCNT_inc_simple(av));
            CX_CURPAD_SAVE(cx->blk_sub);
            cx->blk_sub.argarray = av;
            ++MARK;
@@ -2851,13 +2916,13 @@ try_autoload:
                SV **ary = AvALLOC(av);
                if (AvARRAY(av) != ary) {
                    AvMAX(av) += AvARRAY(av) - AvALLOC(av);
-                   SvPV_set(av, (char*)ary);
+                   AvARRAY(av) = ary;
                }
                if (items > AvMAX(av) + 1) {
                    AvMAX(av) = items - 1;
                    Renew(ary,items,SV*);
                    AvALLOC(av) = ary;
-                   SvPV_set(av, (char*)ary);
+                   AvARRAY(av) = ary;
                }
            }
            Copy(MARK,AvARRAY(av),items,SV*);
@@ -2873,53 +2938,51 @@ try_autoload:
         * stuff so that __WARN__ handlers can safely dounwind()
         * if they want to
         */
-       if (CvDEPTH(cv) == 100 && ckWARN(WARN_RECURSION)
+       if (CvDEPTH(cv) == PERL_SUB_DEPTH_WARN && ckWARN(WARN_RECURSION)
            && !(PERLDB_SUB && cv == GvCV(PL_DBsub)))
            sub_crush_depth(cv);
-#if 0
-       DEBUG_S(PerlIO_printf(Perl_debug_log,
-                             "%p entersub returning %p\n", thr, CvSTART(cv)));
-#endif
        RETURNOP(CvSTART(cv));
     }
     else {
-           I32 markix = TOPMARK;
-
-           PUTBACK;
+       I32 markix = TOPMARK;
 
-           if (!hasargs) {
-               /* Need to copy @_ to stack. Alternative may be to
-                * switch stack to @_, and copy return values
-                * back. This would allow popping @_ in XSUB, e.g.. XXXX */
-               AV * const av = GvAV(PL_defgv);
-               const I32 items = AvFILLp(av) + 1;   /* @_ is not tieable */
-
-               if (items) {
-                   /* Mark is at the end of the stack. */
-                   EXTEND(SP, items);
-                   Copy(AvARRAY(av), SP + 1, items, SV*);
-                   SP += items;
-                   PUTBACK ;           
-               }
-           }
-           /* We assume first XSUB in &DB::sub is the called one. */
-           if (PL_curcopdb) {
-               SAVEVPTR(PL_curcop);
-               PL_curcop = PL_curcopdb;
-               PL_curcopdb = NULL;
-           }
-           /* Do we need to open block here? XXXX */
-           if (CvXSUB(cv)) /* XXX this is supposed to be true */
-               (void)(*CvXSUB(cv))(aTHX_ cv);
+       PUTBACK;
 
-           /* Enforce some sanity in scalar context. */
-           if (gimme == G_SCALAR && ++markix != PL_stack_sp - PL_stack_base ) {
-               if (markix > PL_stack_sp - PL_stack_base)
-                   *(PL_stack_base + markix) = &PL_sv_undef;
-               else
-                   *(PL_stack_base + markix) = *PL_stack_sp;
-               PL_stack_sp = PL_stack_base + markix;
-           }
+       if (!hasargs) {
+           /* Need to copy @_ to stack. Alternative may be to
+            * switch stack to @_, and copy return values
+            * back. This would allow popping @_ in XSUB, e.g.. XXXX */
+           AV * const av = GvAV(PL_defgv);
+           const I32 items = AvFILLp(av) + 1;   /* @_ is not tieable */
+
+           if (items) {
+               /* Mark is at the end of the stack. */
+               EXTEND(SP, items);
+               Copy(AvARRAY(av), SP + 1, items, SV*);
+               SP += items;
+               PUTBACK ;               
+           }
+       }
+       /* We assume first XSUB in &DB::sub is the called one. */
+       if (PL_curcopdb) {
+           SAVEVPTR(PL_curcop);
+           PL_curcop = PL_curcopdb;
+           PL_curcopdb = NULL;
+       }
+       /* Do we need to open block here? XXXX */
+
+       /* CvXSUB(cv) must not be NULL because newXS() refuses NULL xsub address */
+       assert(CvXSUB(cv));
+       CvXSUB(cv)(aTHX_ cv);
+
+       /* Enforce some sanity in scalar context. */
+       if (gimme == G_SCALAR && ++markix != PL_stack_sp - PL_stack_base ) {
+           if (markix > PL_stack_sp - PL_stack_base)
+               *(PL_stack_base + markix) = &PL_sv_undef;
+           else
+               *(PL_stack_base + markix) = *PL_stack_sp;
+           PL_stack_sp = PL_stack_base + markix;
+       }
        LEAVE;
        return NORMAL;
     }
@@ -2928,13 +2991,15 @@ try_autoload:
 void
 Perl_sub_crush_depth(pTHX_ CV *cv)
 {
+    PERL_ARGS_ASSERT_SUB_CRUSH_DEPTH;
+
     if (CvANON(cv))
        Perl_warner(aTHX_ packWARN(WARN_RECURSION), "Deep recursion on anonymous subroutine");
     else {
        SV* const tmpstr = sv_newmortal();
        gv_efullname3(tmpstr, CvGV(cv), NULL);
        Perl_warner(aTHX_ packWARN(WARN_RECURSION), "Deep recursion on subroutine \"%"SVf"\"",
-                   (void*)tmpstr);
+                   SVfARG(tmpstr));
     }
 }
 
@@ -2944,19 +3009,34 @@ PP(pp_aelem)
     SV** svp;
     SV* const elemsv = POPs;
     IV elem = SvIV(elemsv);
-    AV* const av = (AV*)POPs;
+    AV *const av = MUTABLE_AV(POPs);
     const U32 lval = PL_op->op_flags & OPf_MOD || LVRET;
     const U32 defer = (PL_op->op_private & OPpLVAL_DEFER) && (elem > av_len(av));
+    const bool localizing = PL_op->op_private & OPpLVAL_INTRO;
+    bool preeminent = TRUE;
     SV *sv;
 
     if (SvROK(elemsv) && !SvGAMAGIC(elemsv) && ckWARN(WARN_MISC))
        Perl_warner(aTHX_ packWARN(WARN_MISC),
                    "Use of reference \"%"SVf"\" as array index",
-                   (void*)elemsv);
+                   SVfARG(elemsv));
     if (elem > 0)
        elem -= CopARYBASE_get(PL_curcop);
     if (SvTYPE(av) != SVt_PVAV)
        RETPUSHUNDEF;
+
+    if (localizing) {
+       MAGIC *mg;
+       HV *stash;
+
+       /* If we can determine whether the element exist,
+        * Try to preserve the existenceness of a tied array
+        * element by using EXISTS and DELETE if possible.
+        * Fallback to FETCH and STORE otherwise. */
+       if (SvCANEXISTDELETE(av))
+           preeminent = av_exists(av, elem);
+    }
+
     svp = av_fetch(av, elem, lval && !defer);
     if (lval) {
 #ifdef PERL_MALLOC_WRAP
@@ -2986,14 +3066,18 @@ PP(pp_aelem)
            PUSHs(lv);
            RETURN;
        }
-       if (PL_op->op_private & OPpLVAL_INTRO)
-           save_aelem(av, elem, svp);
+       if (localizing) {
+           if (preeminent)
+               save_aelem(av, elem, svp);
+           else
+               SAVEADELETE(av, elem);
+       }
        else if (PL_op->op_private & OPpDEREF)
            vivify_ref(*svp, PL_op->op_private & OPpDEREF);
     }
     sv = (svp ? *svp : &PL_sv_undef);
-    if (!lval && SvGMAGICAL(sv))       /* see note in pp_helem() */
-       sv = sv_mortalcopy(sv);
+    if (!lval && SvRMAGICAL(av) && SvGMAGICAL(sv)) /* see note in pp_helem() */
+       mg_get(sv);
     PUSHs(sv);
     RETURN;
 }
@@ -3001,26 +3085,22 @@ PP(pp_aelem)
 void
 Perl_vivify_ref(pTHX_ SV *sv, U32 to_what)
 {
+    PERL_ARGS_ASSERT_VIVIFY_REF;
+
     SvGETMAGIC(sv);
     if (!SvOK(sv)) {
        if (SvREADONLY(sv))
-           Perl_croak(aTHX_ PL_no_modify);
-       if (SvTYPE(sv) < SVt_RV)
-           sv_upgrade(sv, SVt_RV);
-       else if (SvTYPE(sv) >= SVt_PV) {
-           SvPV_free(sv);
-            SvLEN_set(sv, 0);
-           SvCUR_set(sv, 0);
-       }
+           Perl_croak_no_modify(aTHX);
+       prepare_SV_for_RV(sv);
        switch (to_what) {
        case OPpDEREF_SV:
            SvRV_set(sv, newSV(0));
            break;
        case OPpDEREF_AV:
-           SvRV_set(sv, (SV*)newAV());
+           SvRV_set(sv, MUTABLE_SV(newAV()));
            break;
        case OPpDEREF_HV:
-           SvRV_set(sv, (SV*)newHV());
+           SvRV_set(sv, MUTABLE_SV(newHV()));
            break;
        }
        SvROK_on(sv);
@@ -3062,19 +3142,20 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
     SV* ob;
     GV* gv;
     HV* stash;
-    STRLEN namelen;
     const char* packname = NULL;
     SV *packsv = NULL;
     STRLEN packlen;
-    const char * const name = SvPV_const(meth, namelen);
     SV * const sv = *(PL_stack_base + TOPMARK + 1);
 
+    PERL_ARGS_ASSERT_METHOD_COMMON;
+
     if (!sv)
-       Perl_croak(aTHX_ "Can't call method \"%s\" on an undefined value", name);
+       Perl_croak(aTHX_ "Can't call method \"%"SVf"\" on an undefined value",
+                  SVfARG(meth));
 
     SvGETMAGIC(sv);
     if (SvROK(sv))
-       ob = (SV*)SvRV(sv);
+       ob = MUTABLE_SV(SvRV(sv));
     else {
        GV* iogv;
 
@@ -3090,7 +3171,7 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
        if (!SvOK(sv) ||
            !(packname) ||
            !(iogv = gv_fetchsv(sv, 0, SVt_PVIO)) ||
-           !(ob=(SV*)GvIO(iogv)))
+           !(ob=MUTABLE_SV(GvIO(iogv))))
        {
            /* this isn't the name of a filehandle either */
            if (!packname ||
@@ -3099,30 +3180,35 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
                    : !isIDFIRST(*packname)
                ))
            {
-               Perl_croak(aTHX_ "Can't call method \"%s\" %s", name,
+               Perl_croak(aTHX_ "Can't call method \"%"SVf"\" %s",
+                          SVfARG(meth),
                           SvOK(sv) ? "without a package or object reference"
                                    : "on an undefined value");
            }
            /* assume it's a package name */
-           stash = gv_stashpvn(packname, packlen, FALSE);
+           stash = gv_stashpvn(packname, packlen, 0);
            if (!stash)
                packsv = sv;
             else {
                SV* const ref = newSViv(PTR2IV(stash));
-               hv_store(PL_stashcache, packname, packlen, ref, 0);
+               (void)hv_store(PL_stashcache, packname, packlen, ref, 0);
            }
            goto fetch;
        }
        /* it _is_ a filehandle name -- replace with a reference */
-       *(PL_stack_base + TOPMARK + 1) = sv_2mortal(newRV((SV*)iogv));
+       *(PL_stack_base + TOPMARK + 1) = sv_2mortal(newRV(MUTABLE_SV(iogv)));
     }
 
     /* if we got here, ob should be a reference or a glob */
     if (!ob || !(SvOBJECT(ob)
-                || (SvTYPE(ob) == SVt_PVGV && (ob = (SV*)GvIO((GV*)ob))
+                || (SvTYPE(ob) == SVt_PVGV 
+                    && isGV_with_GP(ob)
+                    && (ob = MUTABLE_SV(GvIO((const GV *)ob)))
                     && SvOBJECT(ob))))
     {
+       const char * const name = SvPV_nolen_const(meth);
        Perl_croak(aTHX_ "Can't call method \"%s\" on unblessed reference",
+                  (SvSCREAM(meth) && strEQ(name,"isa")) ? "DOES" :
                   name);
     }
 
@@ -3136,79 +3222,21 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
     if (hashp) {
        const HE* const he = hv_fetch_ent(stash, meth, 0, *hashp);
        if (he) {
-           gv = (GV*)HeVAL(he);
+           gv = MUTABLE_GV(HeVAL(he));
            if (isGV(gv) && GvCV(gv) &&
-               (!GvCVGEN(gv) || GvCVGEN(gv) == PL_sub_generation))
-               return (SV*)GvCV(gv);
-       }
-    }
-
-    gv = gv_fetchmethod(stash ? stash : (HV*)packsv, name);
-
-    if (!gv) {
-       /* This code tries to figure out just what went wrong with
-          gv_fetchmethod.  It therefore needs to duplicate a lot of
-          the internals of that function.  We can't move it inside
-          Perl_gv_fetchmethod_autoload(), however, since that would
-          cause UNIVERSAL->can("NoSuchPackage::foo") to croak, and we
-          don't want that.
-       */
-       const char* leaf = name;
-       const char* sep = NULL;
-       const char* p;
-
-       for (p = name; *p; p++) {
-           if (*p == '\'')
-               sep = p, leaf = p + 1;
-           else if (*p == ':' && *(p + 1) == ':')
-               sep = p, leaf = p + 2;
-       }
-       if (!sep || ((sep - name) == 5 && strnEQ(name, "SUPER", 5))) {
-           /* the method name is unqualified or starts with SUPER:: */
-           bool need_strlen = 1;
-           if (sep) {
-               packname = CopSTASHPV(PL_curcop);
-           }
-           else if (stash) {
-               HEK * const packhek = HvNAME_HEK(stash);
-               if (packhek) {
-                   packname = HEK_KEY(packhek);
-                   packlen = HEK_LEN(packhek);
-                   need_strlen = 0;
-               } else {
-                   goto croak;
-               }
-           }
-
-           if (!packname) {
-           croak:
-               Perl_croak(aTHX_
-                          "Can't use anonymous symbol table for method lookup");
-           }
-           else if (need_strlen)
-               packlen = strlen(packname);
-
-       }
-       else {
-           /* the method name is qualified */
-           packname = name;
-           packlen = sep - name;
-       }
-       
-       /* we're relying on gv_fetchmethod not autovivifying the stash */
-       if (gv_stashpvn(packname, packlen, FALSE)) {
-           Perl_croak(aTHX_
-                      "Can't locate object method \"%s\" via package \"%.*s\"",
-                      leaf, (int)packlen, packname);
-       }
-       else {
-           Perl_croak(aTHX_
-                      "Can't locate object method \"%s\" via package \"%.*s\""
-                      " (perhaps you forgot to load \"%.*s\"?)",
-                      leaf, (int)packlen, packname, (int)packlen, packname);
+               (!GvCVGEN(gv) || GvCVGEN(gv)
+                  == (PL_sub_generation + HvMROMETA(stash)->cache_gen)))
+               return MUTABLE_SV(GvCV(gv));
        }
     }
-    return isGV(gv) ? (SV*)GvCV(gv) : (SV*)gv;
+
+    gv = gv_fetchmethod_flags(stash ? stash : MUTABLE_HV(packsv),
+                             SvPV_nolen_const(meth),
+                             GV_AUTOLOAD | GV_CROAK);
+
+    assert(gv);
+
+    return isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv);
 }
 
 /*