This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Allow passing of the full enum name into the tryAMAGICbin family of
[perl5.git] / pp.c
diff --git a/pp.c b/pp.c
index eccf7eb..c3d9d2b 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -1,7 +1,7 @@
 /*    pp.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, 2005, 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.
  * and no knowing what you'll find around a corner.  And Elves, sir!" --Samwise
  */
 
+/* This file contains general pp ("push/pop") functions that execute the
+ * opcodes that make up a perl program. A typical pp function expects to
+ * find its arguments on the stack, and usually pushes its results onto
+ * the stack, hence the 'pp' terminology. Each OP structure contains
+ * a pointer to the relevant pp_foo() function.
+ */
+
 #include "EXTERN.h"
 #define PERL_IN_PP_C
 #include "perl.h"
 extern Pid_t getpid (void);
 #endif
 
+/*
+ * Some BSDs and Cygwin default to POSIX math instead of IEEE.
+ * This switches them over to IEEE.
+ */
+#if defined(LIBM_LIB_VERSION)
+    _LIB_VERSION_TYPE _LIB_VERSION = _IEEE_;
+#endif
+
 /* variations on pp_null */
 
 PP(pp_stub)
@@ -38,11 +53,6 @@ PP(pp_stub)
     RETURN;
 }
 
-PP(pp_scalar)
-{
-    return NORMAL;
-}
-
 /* Pushy stuff. */
 
 PP(pp_padav)
@@ -63,12 +73,12 @@ PP(pp_padav)
     }
     gimme = GIMME_V;
     if (gimme == G_ARRAY) {
-       I32 maxarg = AvFILL((AV*)TARG) + 1;
+       const I32 maxarg = AvFILL((AV*)TARG) + 1;
        EXTEND(SP, maxarg);
        if (SvMAGICAL(TARG)) {
            U32 i;
            for (i=0; i < (U32)maxarg; i++) {
-               SV **svp = av_fetch((AV*)TARG, i, FALSE);
+               SV ** const svp = av_fetch((AV*)TARG, i, FALSE);
                SP[i+1] = (svp) ? *svp : &PL_sv_undef;
            }
        }
@@ -78,8 +88,8 @@ PP(pp_padav)
        SP += maxarg;
     }
     else if (gimme == G_SCALAR) {
-       SV* sv = sv_newmortal();
-       I32 maxarg = AvFILL((AV*)TARG) + 1;
+       SV* const sv = sv_newmortal();
+       const I32 maxarg = AvFILL((AV*)TARG) + 1;
        sv_setiv(sv, maxarg);
        PUSHs(sv);
     }
@@ -106,25 +116,12 @@ PP(pp_padhv)
        RETURNOP(do_kv());
     }
     else if (gimme == G_SCALAR) {
-       SV* sv = sv_newmortal();
-        if (SvRMAGICAL(TARG) && mg_find(TARG, PERL_MAGIC_tied))
-            Perl_croak(aTHX_ "Can't provide tied hash usage; "
-                       "use keys(%%hash) to test if empty");
-       if (HvFILL((HV*)TARG))
-           Perl_sv_setpvf(aTHX_ sv, "%ld/%ld",
-                     (long)HvFILL((HV*)TARG), (long)HvMAX((HV*)TARG) + 1);
-       else
-           sv_setiv(sv, 0);
+       SV* const sv = Perl_hv_scalar(aTHX_ (HV*)TARG);
        SETs(sv);
     }
     RETURN;
 }
 
-PP(pp_padany)
-{
-    DIE(aTHX_ "NOT IMPL LINE %d",__LINE__);
-}
-
 /* Translations. */
 
 PP(pp_rv2gv)
@@ -137,7 +134,7 @@ PP(pp_rv2gv)
 
        sv = SvRV(sv);
        if (SvTYPE(sv) == SVt_PVIO) {
-           GV *gv = (GV*) sv_newmortal();
+           GV * const gv = (GV*) sv_newmortal();
            gv_init(gv, 0, "", 0, 0);
            GvIOp(gv) = (IO *)sv;
            (void)SvREFCNT_inc(sv);
@@ -148,9 +145,6 @@ PP(pp_rv2gv)
     }
     else {
        if (SvTYPE(sv) != SVt_PVGV) {
-           char *sym;
-           STRLEN len;
-
            if (SvGMAGICAL(sv)) {
                mg_get(sv);
                if (SvROK(sv))
@@ -160,23 +154,29 @@ PP(pp_rv2gv)
                /* If this is a 'my' scalar and flag is set then vivify
                 * NI-S 1999/05/07
                 */
+               if (SvREADONLY(sv))
+                   Perl_croak(aTHX_ PL_no_modify);
                if (PL_op->op_private & OPpDEREF) {
-                   char *name;
                    GV *gv;
                    if (cUNOP->op_targ) {
                        STRLEN len;
                        SV *namesv = PAD_SV(cUNOP->op_targ);
-                       name = SvPV(namesv, len);
+                       const char *name = SvPV(namesv, len);
                        gv = (GV*)NEWSV(0,0);
                        gv_init(gv, CopSTASH(PL_curcop), name, len, 0);
                    }
                    else {
-                       name = CopSTASHPV(PL_curcop);
+                       const char *name = CopSTASHPV(PL_curcop);
                        gv = newGVgen(name);
                    }
                    if (SvTYPE(sv) < SVt_RV)
                        sv_upgrade(sv, SVt_RV);
-                   SvRV(sv) = (SV*)gv;
+                   if (SvPVX_const(sv)) {
+                       SvPV_free(sv);
+                       SvLEN_set(sv, 0);
+                        SvCUR_set(sv, 0);
+                   }
+                   SvRV_set(sv, (SV*)gv);
                    SvROK_on(sv);
                    SvSETMAGIC(sv);
                    goto wasref;
@@ -185,25 +185,24 @@ PP(pp_rv2gv)
                    PL_op->op_private & HINT_STRICT_REFS)
                    DIE(aTHX_ PL_no_usym, "a symbol");
                if (ckWARN(WARN_UNINITIALIZED))
-                   report_uninit();
+                   report_uninit(sv);
                RETSETUNDEF;
            }
-           sym = SvPV(sv,len);
            if ((PL_op->op_flags & OPf_SPECIAL) &&
                !(PL_op->op_flags & OPf_MOD))
            {
-               sv = (SV*)gv_fetchpv(sym, FALSE, SVt_PVGV);
-               if (!sv
-                   && (!is_gv_magical(sym,len,0)
-                       || !(sv = (SV*)gv_fetchpv(sym, TRUE, SVt_PVGV))))
-               {
+               SV * const temp = (SV*)gv_fetchsv(sv, FALSE, SVt_PVGV);
+               if (!temp
+                   && (!is_gv_magical_sv(sv,0)
+                       || !(sv = (SV*)gv_fetchsv(sv, TRUE, SVt_PVGV)))) {
                    RETSETUNDEF;
                }
+               sv = temp;
            }
            else {
                if (PL_op->op_private & HINT_STRICT_REFS)
-                   DIE(aTHX_ PL_no_symref, sym, "a symbol");
-               sv = (SV*)gv_fetchpv(sym, TRUE, SVt_PVGV);
+                   DIE(aTHX_ PL_no_symref_sv, sv, "a symbol");
+               sv = (SV*)gv_fetchsv(sv, TRUE, SVt_PVGV);
            }
        }
     }
@@ -231,8 +230,6 @@ PP(pp_rv2sv)
        }
     }
     else {
-       char *sym;
-       STRLEN len;
        gv = (GV*)sv;
 
        if (SvTYPE(gv) != SVt_PVGV) {
@@ -246,28 +243,27 @@ PP(pp_rv2sv)
                    PL_op->op_private & HINT_STRICT_REFS)
                    DIE(aTHX_ PL_no_usym, "a SCALAR");
                if (ckWARN(WARN_UNINITIALIZED))
-                   report_uninit();
+                   report_uninit(sv);
                RETSETUNDEF;
            }
-           sym = SvPV(sv, len);
            if ((PL_op->op_flags & OPf_SPECIAL) &&
                !(PL_op->op_flags & OPf_MOD))
            {
-               gv = (GV*)gv_fetchpv(sym, FALSE, SVt_PV);
+               gv = (GV*)gv_fetchsv(sv, FALSE, SVt_PV);
                if (!gv
-                   && (!is_gv_magical(sym,len,0)
-                       || !(gv = (GV*)gv_fetchpv(sym, TRUE, SVt_PV))))
+                   && (!is_gv_magical_sv(sv, 0)
+                       || !(gv = (GV*)gv_fetchsv(sv, TRUE, SVt_PV))))
                {
                    RETSETUNDEF;
                }
            }
            else {
                if (PL_op->op_private & HINT_STRICT_REFS)
-                   DIE(aTHX_ PL_no_symref, sym, "a SCALAR");
-               gv = (GV*)gv_fetchpv(sym, TRUE, SVt_PV);
+                   DIE(aTHX_ PL_no_symref_sv, sv, "a SCALAR");
+               gv = (GV*)gv_fetchsv(sv, TRUE, SVt_PV);
            }
        }
-       sv = GvSV(gv);
+       sv = GvSVn(gv);
     }
     if (PL_op->op_flags & OPf_MOD) {
        if (PL_op->op_private & OPpLVAL_INTRO) {
@@ -288,14 +284,14 @@ PP(pp_rv2sv)
 PP(pp_av2arylen)
 {
     dSP;
-    AV *av = (AV*)TOPs;
-    SV *sv = AvARYLEN(av);
-    if (!sv) {
-       AvARYLEN(av) = sv = NEWSV(0,0);
-       sv_upgrade(sv, SVt_IV);
-       sv_magic(sv, (SV*)av, PERL_MAGIC_arylen, Nullch, 0);
-    }
-    SETs(sv);
+    AV * const av = (AV*)TOPs;
+    SV ** const sv = Perl_av_arylen_p(aTHX_ (AV*)av);
+    if (!*sv) {
+       *sv = NEWSV(0,0);
+       sv_upgrade(*sv, SVt_PVMG);
+       sv_magic(*sv, (SV*)av, PERL_MAGIC_arylen, Nullch, 0);
+    }
+    SETs(*sv);
     RETURN;
 }
 
@@ -319,10 +315,8 @@ PP(pp_pos)
        RETURN;
     }
     else {
-       MAGIC* mg;
-
        if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-           mg = mg_find(sv, PERL_MAGIC_regex_global);
+           const MAGIC * const mg = mg_find(sv, PERL_MAGIC_regex_global);
            if (mg && mg->mg_len >= 0) {
                I32 i = mg->mg_len;
                if (DO_UTF8(sv))
@@ -370,18 +364,17 @@ PP(pp_prototype)
 
     ret = &PL_sv_undef;
     if (SvPOK(TOPs) && SvCUR(TOPs) >= 7) {
-       char *s = SvPVX(TOPs);
+       const char *s = SvPVX_const(TOPs);
        if (strnEQ(s, "CORE::", 6)) {
-           int code;
-       
-           code = keyword(s + 6, SvCUR(TOPs) - 6);
+           const int code = keyword(s + 6, SvCUR(TOPs) - 6);
            if (code < 0) {     /* Overridable. */
 #define MAX_ARGS_OP ((sizeof(I32) - 1) * 2)
                int i = 0, n = 0, seen_question = 0;
                I32 oa;
                char str[ MAX_ARGS_OP * 2 + 2 ]; /* One ';', one '\0' */
 
-               if (code == -KEY_chop || code == -KEY_chomp)
+               if (code == -KEY_chop || code == -KEY_chomp
+                       || code == -KEY_exec || code == -KEY_system)
                    goto set;
                while (i < MAXO) {      /* The slow way. */
                    if (strEQ(s + 6, PL_op_name[i])
@@ -399,8 +392,6 @@ PP(pp_prototype)
                        seen_question = 1;
                        str[n++] = ';';
                    }
-                   else if (n && str[0] == ';' && seen_question)
-                       goto set;       /* XXXX system, exec */
                    if ((oa & (OA_OPTIONAL - 1)) >= OA_AVREF
                        && (oa & (OA_OPTIONAL - 1)) <= OA_SCALARREF
                        /* But globs are already references (kinda) */
@@ -424,7 +415,7 @@ PP(pp_prototype)
     }
     cv = sv_2cv(TOPs, &stash, &gv, FALSE);
     if (cv && SvPOK(cv))
-       ret = sv_2mortal(newSVpvn(SvPVX(cv), SvCUR(cv)));
+       ret = sv_2mortal(newSVpvn(SvPVX_const(cv), SvCUR(cv)));
   set:
     SETs(ret);
     RETURN;
@@ -493,7 +484,7 @@ S_refto(pTHX_ SV *sv)
     }
     rv = sv_newmortal();
     sv_upgrade(rv, SVt_RV);
-    SvRV(rv) = sv;
+    SvRV_set(rv, sv);
     SvROK_on(rv);
     return rv;
 }
@@ -501,19 +492,16 @@ S_refto(pTHX_ SV *sv)
 PP(pp_ref)
 {
     dSP; dTARGET;
-    SV *sv;
-    char *pv;
+    const char *pv;
+    SV * const sv = POPs;
 
-    sv = POPs;
-
-    if (sv && SvGMAGICAL(sv))
-       mg_get(sv);
+    if (sv)
+       SvGETMAGIC(sv);
 
     if (!sv || !SvROK(sv))
        RETPUSHNO;
 
-    sv = SvRV(sv);
-    pv = sv_reftype(sv,TRUE);
+    pv = sv_reftype(SvRV(sv),TRUE);
     PUSHp(pv, strlen(pv));
     RETURN;
 }
@@ -526,14 +514,14 @@ PP(pp_bless)
     if (MAXARG == 1)
        stash = CopSTASH(PL_curcop);
     else {
-       SV *ssv = POPs;
+       SV * const ssv = POPs;
        STRLEN len;
-       char *ptr;
+       const char *ptr;
 
        if (ssv && !SvGMAGICAL(ssv) && !SvAMAGIC(ssv) && SvROK(ssv))
            Perl_croak(aTHX_ "Attempt to bless into a reference");
-       ptr = SvPV(ssv,len);
-       if (ckWARN(WARN_MISC) && len == 0)
+       ptr = SvPV_const(ssv,len);
+       if (len == 0 && ckWARN(WARN_MISC))
            Perl_warner(aTHX_ packWARN(WARN_MISC),
                   "Explicit blessing to '' (assuming package main)");
        stash = gv_stashpvn(ptr, len, TRUE);
@@ -545,66 +533,63 @@ PP(pp_bless)
 
 PP(pp_gelem)
 {
-    GV *gv;
-    SV *sv;
-    SV *tmpRef;
-    char *elem;
     dSP;
-    STRLEN n_a;
 
-    sv = POPs;
-    elem = SvPV(sv, n_a);
-    gv = (GV*)POPs;
-    tmpRef = Nullsv;
+    SV *sv = POPs;
+    const char * const elem = SvPV_nolen_const(sv);
+    GV * const gv = (GV*)POPs;
+    SV * tmpRef = Nullsv;
+
     sv = Nullsv;
-    switch (elem ? *elem : '\0')
-    {
-    case 'A':
-       if (strEQ(elem, "ARRAY"))
-           tmpRef = (SV*)GvAV(gv);
-       break;
-    case 'C':
-       if (strEQ(elem, "CODE"))
-           tmpRef = (SV*)GvCVu(gv);
-       break;
-    case 'F':
-       if (strEQ(elem, "FILEHANDLE")) {
-           /* finally deprecated in 5.8.0 */
-           deprecate("*glob{FILEHANDLE}");
-           tmpRef = (SV*)GvIOp(gv);
+    if (elem) {
+       /* elem will always be NUL terminated.  */
+       const char * const second_letter = elem + 1;
+       switch (*elem) {
+       case 'A':
+           if (strEQ(second_letter, "RRAY"))
+               tmpRef = (SV*)GvAV(gv);
+           break;
+       case 'C':
+           if (strEQ(second_letter, "ODE"))
+               tmpRef = (SV*)GvCVu(gv);
+           break;
+       case 'F':
+           if (strEQ(second_letter, "ILEHANDLE")) {
+               /* finally deprecated in 5.8.0 */
+               deprecate("*glob{FILEHANDLE}");
+               tmpRef = (SV*)GvIOp(gv);
+           }
+           else
+               if (strEQ(second_letter, "ORMAT"))
+                   tmpRef = (SV*)GvFORM(gv);
+           break;
+       case 'G':
+           if (strEQ(second_letter, "LOB"))
+               tmpRef = (SV*)gv;
+           break;
+       case 'H':
+           if (strEQ(second_letter, "ASH"))
+               tmpRef = (SV*)GvHV(gv);
+           break;
+       case 'I':
+           if (*second_letter == 'O' && !elem[2])
+               tmpRef = (SV*)GvIOp(gv);
+           break;
+       case 'N':
+           if (strEQ(second_letter, "AME"))
+               sv = newSVpvn(GvNAME(gv), GvNAMELEN(gv));
+           break;
+       case 'P':
+           if (strEQ(second_letter, "ACKAGE")) {
+               const HEK *hek = HvNAME_HEK(GvSTASH(gv));
+               sv = hek ? newSVhek(hek) : newSVpvn("__ANON__", 8);
+           }
+           break;
+       case 'S':
+           if (strEQ(second_letter, "CALAR"))
+               tmpRef = GvSV(gv);
+           break;
        }
-       else
-       if (strEQ(elem, "FORMAT"))
-           tmpRef = (SV*)GvFORM(gv);
-       break;
-    case 'G':
-       if (strEQ(elem, "GLOB"))
-           tmpRef = (SV*)gv;
-       break;
-    case 'H':
-       if (strEQ(elem, "HASH"))
-           tmpRef = (SV*)GvHV(gv);
-       break;
-    case 'I':
-       if (strEQ(elem, "IO"))
-           tmpRef = (SV*)GvIOp(gv);
-       break;
-    case 'N':
-       if (strEQ(elem, "NAME"))
-           sv = newSVpvn(GvNAME(gv), GvNAMELEN(gv));
-       break;
-    case 'P':
-        if (strEQ(elem, "PACKAGE")) {
-            if (HvNAME(GvSTASH(gv)))
-                sv = newSVpv(HvNAME(GvSTASH(gv)), 0);
-            else
-                sv = newSVpv("__ANON__",0);
-        }
-       break;
-    case 'S':
-       if (strEQ(elem, "SCALAR"))
-           tmpRef = GvSV(gv);
-       break;
     }
     if (tmpRef)
        sv = newRV(tmpRef);
@@ -647,8 +632,8 @@ PP(pp_study)
     if (pos > PL_maxscream) {
        if (PL_maxscream < 0) {
            PL_maxscream = pos + 80;
-           New(301, PL_screamfirst, 256, I32);
-           New(302, PL_screamnext, PL_maxscream, I32);
+           Newx(PL_screamfirst, 256, I32);
+           Newx(PL_screamnext, PL_maxscream, I32);
        }
        else {
            PL_maxscream = pos + pos / 4;
@@ -667,7 +652,7 @@ PP(pp_study)
     sfirst -= 256;
 
     while (--pos >= 0) {
-       ch = s[pos];
+       register const I32 ch = s[pos];
        if (sfirst[ch] >= 0)
            snext[pos] = sfirst[ch] - pos;
        else
@@ -688,6 +673,8 @@ PP(pp_trans)
 
     if (PL_op->op_flags & OPf_STACKED)
        sv = POPs;
+    else if (PL_op->op_private & OPpTARGET_MY)
+       sv = GETTARGET;
     else {
        sv = DEFSV;
        EXTEND(SP,1);
@@ -713,7 +700,7 @@ PP(pp_chop)
     while (MARK < SP)
        do_chop(TARG, *++MARK);
     SP = ORIGMARK;
-    PUSHTARG;
+    XPUSHTARG;
     RETURN;
 }
 
@@ -731,42 +718,10 @@ PP(pp_chomp)
 
     while (SP > MARK)
        count += do_chomp(POPs);
-    PUSHi(count);
+    XPUSHi(count);
     RETURN;
 }
 
-PP(pp_defined)
-{
-    dSP;
-    register SV* sv;
-
-    sv = POPs;
-    if (!sv || !SvANY(sv))
-       RETPUSHNO;
-    switch (SvTYPE(sv)) {
-    case SVt_PVAV:
-       if (AvMAX(sv) >= 0 || SvGMAGICAL(sv)
-               || (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
-           RETPUSHYES;
-       break;
-    case SVt_PVHV:
-       if (HvARRAY(sv) || SvGMAGICAL(sv)
-               || (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
-           RETPUSHYES;
-       break;
-    case SVt_PVCV:
-       if (CvROOT(sv) || CvXSUB(sv))
-           RETPUSHYES;
-       break;
-    default:
-       if (SvGMAGICAL(sv))
-           mg_get(sv);
-       if (SvOK(sv))
-           RETPUSHYES;
-    }
-    RETPUSHNO;
-}
-
 PP(pp_undef)
 {
     dSP;
@@ -793,7 +748,7 @@ PP(pp_undef)
        hv_undef((HV*)sv);
        break;
     case SVt_PVCV:
-       if (ckWARN(WARN_MISC) && cv_const_sv((CV*)sv))
+       if (cv_const_sv((CV*)sv) && ckWARN(WARN_MISC))
            Perl_warner(aTHX_ packWARN(WARN_MISC), "Constant subroutine %s undefined",
                 CvANON((CV*)sv) ? "(anonymous)" : GvENAME(CvGV((CV*)sv)));
        /* FALL THROUGH */
@@ -811,7 +766,7 @@ PP(pp_undef)
        else {
            GP *gp;
            gp_free((GV*)sv);
-           Newz(602, gp, 1, GP);
+           Newxz(gp, 1, GP);
            GvGP(sv) = gp_ref(gp);
            GvSV(sv) = NEWSV(72,0);
            GvLINE(sv) = CopLINE(PL_curcop);
@@ -820,13 +775,12 @@ PP(pp_undef)
        }
        break;
     default:
-       if (SvTYPE(sv) >= SVt_PV && SvPVX(sv) && SvLEN(sv)) {
-           (void)SvOOK_off(sv);
-           Safefree(SvPVX(sv));
+       if (SvTYPE(sv) >= SVt_PV && SvPVX_const(sv) && SvLEN(sv)) {
+           SvPV_free(sv);
            SvPV_set(sv, Nullch);
            SvLEN_set(sv, 0);
        }
-       (void)SvOK_off(sv);
+       SvOK_off(sv);
        SvSETMAGIC(sv);
     }
 
@@ -836,12 +790,12 @@ PP(pp_undef)
 PP(pp_predec)
 {
     dSP;
-    if (SvTYPE(TOPs) > SVt_PVLV)
+    if (SvTYPE(TOPs) >= SVt_PVGV && SvTYPE(TOPs) != SVt_PVLV)
        DIE(aTHX_ PL_no_modify);
     if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
         && SvIVX(TOPs) != IV_MIN)
     {
-       --SvIVX(TOPs);
+       SvIV_set(TOPs, SvIVX(TOPs) - 1);
        SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
     }
     else
@@ -853,13 +807,13 @@ PP(pp_predec)
 PP(pp_postinc)
 {
     dSP; dTARGET;
-    if (SvTYPE(TOPs) > SVt_PVLV)
+    if (SvTYPE(TOPs) >= SVt_PVGV && SvTYPE(TOPs) != SVt_PVLV)
        DIE(aTHX_ PL_no_modify);
     sv_setsv(TARG, TOPs);
     if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
         && SvIVX(TOPs) != IV_MAX)
     {
-       ++SvIVX(TOPs);
+       SvIV_set(TOPs, SvIVX(TOPs) + 1);
        SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
     }
     else
@@ -875,13 +829,13 @@ PP(pp_postinc)
 PP(pp_postdec)
 {
     dSP; dTARGET;
-    if (SvTYPE(TOPs) > SVt_PVLV)
+    if (SvTYPE(TOPs) >= SVt_PVGV && SvTYPE(TOPs) != SVt_PVLV)
        DIE(aTHX_ PL_no_modify);
     sv_setsv(TARG, TOPs);
     if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
         && SvIVX(TOPs) != IV_MIN)
     {
-       --SvIVX(TOPs);
+       SvIV_set(TOPs, SvIVX(TOPs) - 1);
        SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
     }
     else
@@ -905,36 +859,37 @@ PP(pp_pow)
        we're sure it is safe; otherwise we call pow() and try to convert to
        integer afterwards. */
     {
-        SvIV_please(TOPm1s);
-        if (SvIOK(TOPm1s)) {
-            bool baseuok = SvUOK(TOPm1s);
-            UV baseuv;
+       SvIV_please(TOPs);
+       if (SvIOK(TOPs)) {
+           SvIV_please(TOPm1s);
+           if (SvIOK(TOPm1s)) {
+               UV power;
+               bool baseuok;
+               UV baseuv;
 
-            if (baseuok) {
-                baseuv = SvUVX(TOPm1s);
-            } else {
-                IV iv = SvIVX(TOPm1s);
-                if (iv >= 0) {
-                    baseuv = iv;
-                    baseuok = TRUE; /* effectively it's a UV now */
-                } else {
-                    baseuv = -iv; /* abs, baseuok == false records sign */
-                }
-            }
-            SvIV_please(TOPs);
-            if (SvIOK(TOPs)) {
-                UV power;
+               if (SvUOK(TOPs)) {
+                   power = SvUVX(TOPs);
+               } else {
+                   const IV iv = SvIVX(TOPs);
+                   if (iv >= 0) {
+                       power = iv;
+                   } else {
+                       goto float_it; /* Can't do negative powers this way.  */
+                   }
+               }
 
-                if (SvUOK(TOPs)) {
-                    power = SvUVX(TOPs);
-                } else {
-                    IV iv = SvIVX(TOPs);
-                    if (iv >= 0) {
-                        power = iv;
-                    } else {
-                        goto float_it; /* Can't do negative powers this way.  */
-                    }
-                }
+               baseuok = SvUOK(TOPm1s);
+               if (baseuok) {
+                   baseuv = SvUVX(TOPm1s);
+               } else {
+                   const IV iv = SvIVX(TOPm1s);
+                   if (iv >= 0) {
+                       baseuv = iv;
+                       baseuok = TRUE; /* effectively it's a UV now */
+                   } else {
+                       baseuv = -iv; /* abs, baseuok == false records sign */
+                   }
+               }
                 /* now we have integer ** positive integer. */
                 is_int = 1;
 
@@ -950,33 +905,28 @@ PP(pp_pow)
                        programmers to notice ** not doing what they mean. */
                     NV result = 1.0;
                     NV base = baseuok ? baseuv : -(NV)baseuv;
-                    int n = 0;
-
-                    for (; power; base *= base, n++) {
-                        /* Do I look like I trust gcc with long longs here?
-                           Do I hell.  */
-                        UV bit = (UV)1 << (UV)n;
-                        if (power & bit) {
-                            result *= base;
-                            /* Only bother to clear the bit if it is set.  */
-                            power -= bit;
-                           /* Avoid squaring base again if we're done. */
-                           if (power == 0) break;
-                        }
-                    }
+
+                   if (power & 1) {
+                       result *= base;
+                   }
+                   while (power >>= 1) {
+                       base *= base;
+                       if (power & 1) {
+                           result *= base;
+                       }
+                   }
                     SP--;
                     SETn( result );
                     SvIV_please(TOPs);
                     RETURN;
                } else {
                    register unsigned int highbit = 8 * sizeof(UV);
-                   register unsigned int lowbit = 0;
-                   register unsigned int diff;
-                   while ((diff = (highbit - lowbit) >> 1)) {
-                       if (baseuv & ~((1 << (lowbit + diff)) - 1))
-                           lowbit += diff;
-                       else 
-                           highbit -= diff;
+                   register unsigned int diff = 8 * sizeof(UV);
+                   while (diff >>= 1) {
+                       highbit -= diff;
+                       if (baseuv >> highbit) {
+                           highbit += diff;
+                       }
                    }
                    /* we now have baseuv < 2 ** highbit */
                    if (power * highbit <= 8 * sizeof(UV)) {
@@ -984,17 +934,18 @@ PP(pp_pow)
                           on same algorithm as above */
                        register UV result = 1;
                        register UV base = baseuv;
-                       register int n = 0;
-                       for (; power; base *= base, n++) {
-                           register UV bit = (UV)1 << (UV)n;
-                           if (power & bit) {
+                       const bool odd_power = (bool)(power & 1);
+                       if (odd_power) {
+                           result *= base;
+                       }
+                       while (power >>= 1) {
+                           base *= base;
+                           if (power & 1) {
                                result *= base;
-                               power -= bit;
-                               if (power == 0) break;
                            }
                        }
                        SP--;
-                       if (baseuok || !(power & 1))
+                       if (baseuok || !odd_power)
                            /* answer is positive */
                            SETu( result );
                        else if (result <= (UV)IV_MAX)
@@ -1049,7 +1000,7 @@ PP(pp_multiply)
            if (auvok) {
                alow = SvUVX(TOPm1s);
            } else {
-               IV aiv = SvIVX(TOPm1s);
+               const IV aiv = SvIVX(TOPm1s);
                if (aiv >= 0) {
                    alow = aiv;
                    auvok = TRUE; /* effectively it's a UV now */
@@ -1060,7 +1011,7 @@ PP(pp_multiply)
            if (buvok) {
                blow = SvUVX(TOPs);
            } else {
-               IV biv = SvIVX(TOPs);
+               const IV biv = SvIVX(TOPs);
                if (biv >= 0) {
                    blow = biv;
                    buvok = TRUE; /* effectively it's a UV now */
@@ -1181,7 +1132,7 @@ PP(pp_divide)
                 right = SvUVX(TOPs);
             }
            else {
-                IV biv = SvIVX(TOPs);
+               const IV biv = SvIVX(TOPs);
                 if (biv >= 0) {
                     right = biv;
                     right_non_neg = TRUE; /* effectively it's a UV now */
@@ -1202,7 +1153,7 @@ PP(pp_divide)
                 left = SvUVX(TOPm1s);
             }
            else {
-                IV aiv = SvIVX(TOPm1s);
+               const IV aiv = SvIVX(TOPm1s);
                 if (aiv >= 0) {
                     left = aiv;
                     left_non_neg = TRUE; /* effectively it's a UV now */
@@ -1228,7 +1179,7 @@ PP(pp_divide)
 #endif
                 ) {
                 /* Integer division can't overflow, but it can be imprecise.  */
-                UV result = left / right;
+               const UV result = left / right;
                 if (result * right == left) {
                     SP--; /* result is valid */
                     if (left_non_neg == right_non_neg) {
@@ -1277,7 +1228,7 @@ PP(pp_modulo)
             if (!right_neg) {
                 right = SvUVX(POPs);
             } else {
-                IV biv = SvIVX(POPs);
+               const IV biv = SvIVX(POPs);
                 if (biv >= 0) {
                     right = biv;
                     right_neg = FALSE; /* effectively it's a UV now */
@@ -1390,13 +1341,45 @@ PP(pp_repeat)
 {
   dSP; dATARGET; tryAMAGICbin(repeat,opASSIGN);
   {
-    register IV count = POPi;
+    register IV count;
+    dPOPss;
+    SvGETMAGIC(sv);
+    if (SvIOKp(sv)) {
+        if (SvUOK(sv)) {
+             const UV uv = SvUV(sv);
+             if (uv > IV_MAX)
+                  count = IV_MAX; /* The best we can do? */
+             else
+                  count = uv;
+        } else {
+             IV iv = SvIV(sv);
+             if (iv < 0)
+                  count = 0;
+             else
+                  count = iv;
+        }
+    }
+    else if (SvNOKp(sv)) {
+        const NV nv = SvNV(sv);
+        if (nv < 0.0)
+             count = 0;
+        else
+             count = (IV)nv;
+    }
+    else
+        count = SvIVx(sv);
     if (GIMME == G_ARRAY && PL_op->op_private & OPpREPEAT_DOLIST) {
        dMARK;
        I32 items = SP - MARK;
        I32 max;
+       static const char oom_list_extend[] =
+         "Out of memory during list extend";
 
        max = items * count;
+       MEM_WRAP_CHECK_1(max, SV*, oom_list_extend);
+       /* Did the max computation overflow? */
+       if (items > 0 && max > 0 && (max < items || max < count))
+          Perl_croak(aTHX_ oom_list_extend);
        MEXTEND(MARK, max);
        if (count > 1) {
            while (SP > MARK) {
@@ -1441,6 +1424,8 @@ PP(pp_repeat)
        SV *tmpstr = POPs;
        STRLEN len;
        bool isutf;
+       static const char oom_string_extend[] =
+         "Out of memory during string extend";
 
        SvSetSV(TARG, tmpstr);
        SvPV_force(TARG, len);
@@ -1449,9 +1434,13 @@ PP(pp_repeat)
            if (count < 1)
                SvCUR_set(TARG, 0);
            else {
-               SvGROW(TARG, (count * len) + 1);
+               STRLEN max = (UV)count * len;
+               if (len > ((MEM_SIZE)~0)/count)
+                    Perl_croak(aTHX_ oom_string_extend);
+               MEM_WRAP_CHECK_1(max, char, oom_string_extend);
+               SvGROW(TARG, max + 1);
                repeatcpy(SvPVX(TARG) + len, SvPVX(TARG), len, count - 1);
-               SvCUR(TARG) *= count;
+               SvCUR_set(TARG, SvCUR(TARG) * count);
            }
            *SvEND(TARG) = '\0';
        }
@@ -1502,7 +1491,7 @@ PP(pp_subtract)
                if ((auvok = SvUOK(TOPm1s)))
                    auv = SvUVX(TOPm1s);
                else {
-                   register IV aiv = SvIVX(TOPm1s);
+                   register const IV aiv = SvIVX(TOPm1s);
                    if (aiv >= 0) {
                        auv = aiv;
                        auvok = 1;      /* Now acting as a sign flag.  */
@@ -1522,7 +1511,7 @@ PP(pp_subtract)
            if (buvok)
                buv = SvUVX(TOPs);
            else {
-               register IV biv = SvIVX(TOPs);
+               register const IV biv = SvIVX(TOPs);
                if (biv >= 0) {
                    buv = biv;
                    buvok = 1;
@@ -1596,7 +1585,7 @@ PP(pp_left_shift)
 {
     dSP; dATARGET; tryAMAGICbin(lshift,opASSIGN);
     {
-      IV shift = POPi;
+      const IV shift = POPi;
       if (PL_op->op_private & HINT_INTEGER) {
        IV i = TOPi;
        SETi(i << shift);
@@ -1613,7 +1602,7 @@ PP(pp_right_shift)
 {
     dSP; dATARGET; tryAMAGICbin(rshift,opASSIGN);
     {
-      IV shift = POPi;
+      const IV shift = POPi;
       if (PL_op->op_private & HINT_INTEGER) {
        IV i = TOPi;
        SETi(i >> shift);
@@ -1638,16 +1627,16 @@ PP(pp_lt)
            bool buvok = SvUOK(TOPs);
        
            if (!auvok && !buvok) { /* ## IV < IV ## */
-               IV aiv = SvIVX(TOPm1s);
-               IV biv = SvIVX(TOPs);
+               const IV aiv = SvIVX(TOPm1s);
+               const IV biv = SvIVX(TOPs);
                
                SP--;
                SETs(boolSV(aiv < biv));
                RETURN;
            }
            if (auvok && buvok) { /* ## UV < UV ## */
-               UV auv = SvUVX(TOPm1s);
-               UV buv = SvUVX(TOPs);
+               const UV auv = SvUVX(TOPm1s);
+               const UV buv = SvUVX(TOPs);
                
                SP--;
                SETs(boolSV(auv < buv));
@@ -1655,9 +1644,7 @@ PP(pp_lt)
            }
            if (auvok) { /* ## UV < IV ## */
                UV auv;
-               IV biv;
-               
-               biv = SvIVX(TOPs);
+               const IV biv = SvIVX(TOPs);
                SP--;
                if (biv < 0) {
                    /* As (a) is a UV, it's >=0, so it cannot be < */
@@ -1669,10 +1656,9 @@ PP(pp_lt)
                RETURN;
            }
            { /* ## IV < UV ## */
-               IV aiv;
+               const IV aiv = SvIVX(TOPm1s);
                UV buv;
                
-               aiv = SvIVX(TOPm1s);
                if (aiv < 0) {
                    /* As (b) is a UV, it's >=0, so it must be < */
                    SP--;
@@ -1691,11 +1677,11 @@ PP(pp_lt)
 #ifdef PERL_PRESERVE_IVUV
     else
 #endif
-        if (SvROK(TOPs) && SvROK(TOPm1s)) {
-            SP--;
-            SETs(boolSV(SvRV(TOPs) < SvRV(TOPp1s)));
-            RETURN;
-        }
+    if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
+       SP--;
+       SETs(boolSV(SvRV(TOPs) < SvRV(TOPp1s)));
+       RETURN;
+    }
 #endif
     {
       dPOPnv;
@@ -1716,16 +1702,16 @@ PP(pp_gt)
            bool buvok = SvUOK(TOPs);
        
            if (!auvok && !buvok) { /* ## IV > IV ## */
-               IV aiv = SvIVX(TOPm1s);
-               IV biv = SvIVX(TOPs);
-               
+               const IV aiv = SvIVX(TOPm1s);
+               const IV biv = SvIVX(TOPs);
+
                SP--;
                SETs(boolSV(aiv > biv));
                RETURN;
            }
            if (auvok && buvok) { /* ## UV > UV ## */
-               UV auv = SvUVX(TOPm1s);
-               UV buv = SvUVX(TOPs);
+               const UV auv = SvUVX(TOPm1s);
+               const UV buv = SvUVX(TOPs);
                
                SP--;
                SETs(boolSV(auv > buv));
@@ -1733,9 +1719,8 @@ PP(pp_gt)
            }
            if (auvok) { /* ## UV > IV ## */
                UV auv;
-               IV biv;
-               
-               biv = SvIVX(TOPs);
+               const IV biv = SvIVX(TOPs);
+
                SP--;
                if (biv < 0) {
                    /* As (a) is a UV, it's >=0, so it must be > */
@@ -1747,10 +1732,9 @@ PP(pp_gt)
                RETURN;
            }
            { /* ## IV > UV ## */
-               IV aiv;
+               const IV aiv = SvIVX(TOPm1s);
                UV buv;
                
-               aiv = SvIVX(TOPm1s);
                if (aiv < 0) {
                    /* As (b) is a UV, it's >=0, so it cannot be > */
                    SP--;
@@ -1769,7 +1753,7 @@ PP(pp_gt)
 #ifdef PERL_PRESERVE_IVUV
     else
 #endif
-        if (SvROK(TOPs) && SvROK(TOPm1s)) {
+    if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
         SP--;
         SETs(boolSV(SvRV(TOPs) > SvRV(TOPp1s)));
         RETURN;
@@ -1794,8 +1778,8 @@ PP(pp_le)
            bool buvok = SvUOK(TOPs);
        
            if (!auvok && !buvok) { /* ## IV <= IV ## */
-               IV aiv = SvIVX(TOPm1s);
-               IV biv = SvIVX(TOPs);
+               const IV aiv = SvIVX(TOPm1s);
+               const IV biv = SvIVX(TOPs);
                
                SP--;
                SETs(boolSV(aiv <= biv));
@@ -1811,9 +1795,8 @@ PP(pp_le)
            }
            if (auvok) { /* ## UV <= IV ## */
                UV auv;
-               IV biv;
-               
-               biv = SvIVX(TOPs);
+               const IV biv = SvIVX(TOPs);
+
                SP--;
                if (biv < 0) {
                    /* As (a) is a UV, it's >=0, so a cannot be <= */
@@ -1825,10 +1808,9 @@ PP(pp_le)
                RETURN;
            }
            { /* ## IV <= UV ## */
-               IV aiv;
+               const IV aiv = SvIVX(TOPm1s);
                UV buv;
-               
-               aiv = SvIVX(TOPm1s);
+
                if (aiv < 0) {
                    /* As (b) is a UV, it's >=0, so a must be <= */
                    SP--;
@@ -1847,7 +1829,7 @@ PP(pp_le)
 #ifdef PERL_PRESERVE_IVUV
     else
 #endif
-        if (SvROK(TOPs) && SvROK(TOPm1s)) {
+    if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
         SP--;
         SETs(boolSV(SvRV(TOPs) <= SvRV(TOPp1s)));
         RETURN;
@@ -1872,26 +1854,25 @@ PP(pp_ge)
            bool buvok = SvUOK(TOPs);
        
            if (!auvok && !buvok) { /* ## IV >= IV ## */
-               IV aiv = SvIVX(TOPm1s);
-               IV biv = SvIVX(TOPs);
-               
+               const IV aiv = SvIVX(TOPm1s);
+               const IV biv = SvIVX(TOPs);
+
                SP--;
                SETs(boolSV(aiv >= biv));
                RETURN;
            }
            if (auvok && buvok) { /* ## UV >= UV ## */
-               UV auv = SvUVX(TOPm1s);
-               UV buv = SvUVX(TOPs);
-               
+               const UV auv = SvUVX(TOPm1s);
+               const UV buv = SvUVX(TOPs);
+
                SP--;
                SETs(boolSV(auv >= buv));
                RETURN;
            }
            if (auvok) { /* ## UV >= IV ## */
                UV auv;
-               IV biv;
-               
-               biv = SvIVX(TOPs);
+               const IV biv = SvIVX(TOPs);
+
                SP--;
                if (biv < 0) {
                    /* As (a) is a UV, it's >=0, so it must be >= */
@@ -1903,10 +1884,9 @@ PP(pp_ge)
                RETURN;
            }
            { /* ## IV >= UV ## */
-               IV aiv;
+               const IV aiv = SvIVX(TOPm1s);
                UV buv;
-               
-               aiv = SvIVX(TOPm1s);
+
                if (aiv < 0) {
                    /* As (b) is a UV, it's >=0, so a cannot be >= */
                    SP--;
@@ -1925,7 +1905,7 @@ PP(pp_ge)
 #ifdef PERL_PRESERVE_IVUV
     else
 #endif
-        if (SvROK(TOPs) && SvROK(TOPm1s)) {
+    if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
         SP--;
         SETs(boolSV(SvRV(TOPs) >= SvRV(TOPp1s)));
         RETURN;
@@ -1942,7 +1922,7 @@ PP(pp_ne)
 {
     dSP; tryAMAGICbinSET(ne,0);
 #ifndef NV_PRESERVES_UV
-    if (SvROK(TOPs) && SvROK(TOPm1s)) {
+    if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
         SP--;
        SETs(boolSV(SvRV(TOPs) != SvRV(TOPp1s)));
        RETURN;
@@ -1963,9 +1943,9 @@ PP(pp_ne)
                    differ from normal zero. As I understand it. (Need to
                    check - is negative zero implementation defined behaviour
                    anyway?). NWC  */
-               UV buv = SvUVX(POPs);
-               UV auv = SvUVX(TOPs);
-               
+               const UV buv = SvUVX(POPs);
+               const UV auv = SvUVX(TOPs);
+
                SETs(boolSV(auv != buv));
                RETURN;
            }
@@ -2011,7 +1991,7 @@ PP(pp_ncmp)
 {
     dSP; dTARGET; tryAMAGICbin(ncmp,0);
 #ifndef NV_PRESERVES_UV
-    if (SvROK(TOPs) && SvROK(TOPm1s)) {
+    if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
         UV right = PTR2UV(SvRV(POPs));
         UV left = PTR2UV(SvRV(TOPs));
        SETi((left > right) - (left < right));
@@ -2024,12 +2004,12 @@ PP(pp_ncmp)
     if (SvIOK(TOPs)) {
        SvIV_please(TOPm1s);
        if (SvIOK(TOPm1s)) {
-           bool leftuvok = SvUOK(TOPm1s);
-           bool rightuvok = SvUOK(TOPs);
+           const bool leftuvok = SvUOK(TOPm1s);
+           const bool rightuvok = SvUOK(TOPs);
            I32 value;
            if (!leftuvok && !rightuvok) { /* ## IV <=> IV ## */
-               IV leftiv = SvIVX(TOPm1s);
-               IV rightiv = SvIVX(TOPs);
+               const IV leftiv = SvIVX(TOPm1s);
+               const IV rightiv = SvIVX(TOPs);
                
                if (leftiv > rightiv)
                    value = 1;
@@ -2038,8 +2018,8 @@ PP(pp_ncmp)
                else
                    value = 0;
            } else if (leftuvok && rightuvok) { /* ## UV <=> UV ## */
-               UV leftuv = SvUVX(TOPm1s);
-               UV rightuv = SvUVX(TOPs);
+               const UV leftuv = SvUVX(TOPm1s);
+               const UV rightuv = SvUVX(TOPs);
                
                if (leftuv > rightuv)
                    value = 1;
@@ -2048,15 +2028,12 @@ PP(pp_ncmp)
                else
                    value = 0;
            } else if (leftuvok) { /* ## UV <=> IV ## */
-               UV leftuv;
-               IV rightiv;
-               
-               rightiv = SvIVX(TOPs);
+               const IV rightiv = SvIVX(TOPs);
                if (rightiv < 0) {
                    /* As (a) is a UV, it's >=0, so it cannot be < */
                    value = 1;
                } else {
-                   leftuv = SvUVX(TOPm1s);
+                   const UV leftuv = SvUVX(TOPm1s);
                    if (leftuv > (UV)rightiv) {
                        value = 1;
                    } else if (leftuv < (UV)rightiv) {
@@ -2066,15 +2043,12 @@ PP(pp_ncmp)
                    }
                }
            } else { /* ## IV <=> UV ## */
-               IV leftiv;
-               UV rightuv;
-               
-               leftiv = SvIVX(TOPm1s);
+               const IV leftiv = SvIVX(TOPm1s);
                if (leftiv < 0) {
                    /* As (b) is a UV, it's >=0, so it must be < */
                    value = -1;
                } else {
-                   rightuv = SvUVX(TOPs);
+                   const UV rightuv = SvUVX(TOPs);
                    if ((UV)leftiv > rightuv) {
                        value = 1;
                    } else if ((UV)leftiv < rightuv) {
@@ -2119,10 +2093,10 @@ PP(pp_ncmp)
 
 PP(pp_slt)
 {
-    dSP; tryAMAGICbinSET(slt,0);
+    dSP; tryAMAGICbinSET_var(slt_amg,0);
     {
       dPOPTOPssrl;
-      int cmp = (IN_LOCALE_RUNTIME
+      const int cmp = (IN_LOCALE_RUNTIME
                 ? sv_cmp_locale(left, right)
                 : sv_cmp(left, right));
       SETs(boolSV(cmp < 0));
@@ -2132,10 +2106,10 @@ PP(pp_slt)
 
 PP(pp_sgt)
 {
-    dSP; tryAMAGICbinSET(sgt,0);
+    dSP; tryAMAGICbinSET_var(sgt_amg,0);
     {
       dPOPTOPssrl;
-      int cmp = (IN_LOCALE_RUNTIME
+      const int cmp = (IN_LOCALE_RUNTIME
                 ? sv_cmp_locale(left, right)
                 : sv_cmp(left, right));
       SETs(boolSV(cmp > 0));
@@ -2145,10 +2119,10 @@ PP(pp_sgt)
 
 PP(pp_sle)
 {
-    dSP; tryAMAGICbinSET(sle,0);
+    dSP; tryAMAGICbinSET_var(sle_amg,0);
     {
       dPOPTOPssrl;
-      int cmp = (IN_LOCALE_RUNTIME
+      const int cmp = (IN_LOCALE_RUNTIME
                 ? sv_cmp_locale(left, right)
                 : sv_cmp(left, right));
       SETs(boolSV(cmp <= 0));
@@ -2158,10 +2132,10 @@ PP(pp_sle)
 
 PP(pp_sge)
 {
-    dSP; tryAMAGICbinSET(sge,0);
+    dSP; tryAMAGICbinSET_var(sge_amg,0);
     {
       dPOPTOPssrl;
-      int cmp = (IN_LOCALE_RUNTIME
+      const int cmp = (IN_LOCALE_RUNTIME
                 ? sv_cmp_locale(left, right)
                 : sv_cmp(left, right));
       SETs(boolSV(cmp >= 0));
@@ -2194,7 +2168,7 @@ PP(pp_scmp)
     dSP; dTARGET;  tryAMAGICbin(scmp,0);
     {
       dPOPTOPssrl;
-      int cmp = (IN_LOCALE_RUNTIME
+      const int cmp = (IN_LOCALE_RUNTIME
                 ? sv_cmp_locale(left, right)
                 : sv_cmp(left, right));
       SETi( cmp );
@@ -2207,13 +2181,15 @@ PP(pp_bit_and)
     dSP; dATARGET; tryAMAGICbin(band,opASSIGN);
     {
       dPOPTOPssrl;
+      SvGETMAGIC(left);
+      SvGETMAGIC(right);
       if (SvNIOKp(left) || SvNIOKp(right)) {
        if (PL_op->op_private & HINT_INTEGER) {
-         IV i = SvIV(left) & SvIV(right);
+         const IV i = SvIV_nomg(left) & SvIV_nomg(right);
          SETi(i);
        }
        else {
-         UV u = SvUV(left) & SvUV(right);
+         const UV u = SvUV_nomg(left) & SvUV_nomg(right);
          SETu(u);
        }
       }
@@ -2230,13 +2206,15 @@ PP(pp_bit_xor)
     dSP; dATARGET; tryAMAGICbin(bxor,opASSIGN);
     {
       dPOPTOPssrl;
+      SvGETMAGIC(left);
+      SvGETMAGIC(right);
       if (SvNIOKp(left) || SvNIOKp(right)) {
        if (PL_op->op_private & HINT_INTEGER) {
-         IV i = (USE_LEFT(left) ? SvIV(left) : 0) ^ SvIV(right);
+         const IV i = (USE_LEFT(left) ? SvIV_nomg(left) : 0) ^ SvIV_nomg(right);
          SETi(i);
        }
        else {
-         UV u = (USE_LEFT(left) ? SvUV(left) : 0) ^ SvUV(right);
+         const UV u = (USE_LEFT(left) ? SvUV_nomg(left) : 0) ^ SvUV_nomg(right);
          SETu(u);
        }
       }
@@ -2253,13 +2231,15 @@ PP(pp_bit_or)
     dSP; dATARGET; tryAMAGICbin(bor,opASSIGN);
     {
       dPOPTOPssrl;
+      SvGETMAGIC(left);
+      SvGETMAGIC(right);
       if (SvNIOKp(left) || SvNIOKp(right)) {
        if (PL_op->op_private & HINT_INTEGER) {
-         IV i = (USE_LEFT(left) ? SvIV(left) : 0) | SvIV(right);
+         const IV i = (USE_LEFT(left) ? SvIV_nomg(left) : 0) | SvIV_nomg(right);
          SETi(i);
        }
        else {
-         UV u = (USE_LEFT(left) ? SvUV(left) : 0) | SvUV(right);
+         const UV u = (USE_LEFT(left) ? SvUV_nomg(left) : 0) | SvUV_nomg(right);
          SETu(u);
        }
       }
@@ -2276,9 +2256,8 @@ PP(pp_negate)
     dSP; dTARGET; tryAMAGICun(neg);
     {
        dTOPss;
-       int flags = SvFLAGS(sv);
-       if (SvGMAGICAL(sv))
-           mg_get(sv);
+       const int flags = SvFLAGS(sv);
+       SvGETMAGIC(sv);
        if ((flags & SVf_IOK) || ((flags & (SVp_IOK | SVp_NOK)) == SVp_IOK)) {
            /* It's publicly an integer, or privately an integer-not-float */
        oops_its_an_int:
@@ -2308,7 +2287,7 @@ PP(pp_negate)
            SETn(-SvNV(sv));
        else if (SvPOKp(sv)) {
            STRLEN len;
-           char *s = SvPV(sv, len);
+           const char *s = SvPV_const(sv, len);
            if (isIDFIRST(*s)) {
                sv_setpvn(TARG, "-", 1);
                sv_catsv(TARG, sv);
@@ -2354,13 +2333,14 @@ PP(pp_complement)
     dSP; dTARGET; tryAMAGICun(compl);
     {
       dTOPss;
+      SvGETMAGIC(sv);
       if (SvNIOKp(sv)) {
        if (PL_op->op_private & HINT_INTEGER) {
-         IV i = ~SvIV(sv);
+         const IV i = ~SvIV_nomg(sv);
          SETi(i);
        }
        else {
-         UV u = ~SvUV(sv);
+         const UV u = ~SvUV_nomg(sv);
          SETu(u);
        }
       }
@@ -2369,7 +2349,8 @@ PP(pp_complement)
        register I32 anum;
        STRLEN len;
 
-       SvSetSV(TARG, sv);
+       (void)SvPV_nomg_const(sv,len); /* force check for uninit var */
+       sv_setsv_nomg(TARG, sv);
        tmps = (U8*)SvPV_force(TARG, len);
        anum = len;
        if (SvUTF8(TARG)) {
@@ -2383,7 +2364,7 @@ PP(pp_complement)
 
          send = tmps + len;
          while (tmps < send) {
-           UV c = utf8n_to_uvchr(tmps, send-tmps, &l, UTF8_ALLOW_ANYUV);
+           const UV c = utf8n_to_uvchr(tmps, send-tmps, &l, UTF8_ALLOW_ANYUV);
            tmps += UTF8SKIP(tmps);
            targlen += UNISKIP(~c);
            nchar++;
@@ -2395,9 +2376,9 @@ PP(pp_complement)
          tmps -= len;
 
          if (nwide) {
-             Newz(0, result, targlen + 1, U8);
+             Newxz(result, targlen + 1, U8);
              while (tmps < send) {
-                 UV c = utf8n_to_uvchr(tmps, send-tmps, &l, UTF8_ALLOW_ANYUV);
+                 const UV c = utf8n_to_uvchr(tmps, send-tmps, &l, UTF8_ALLOW_ANYUV);
                  tmps += UTF8SKIP(tmps);
                  result = uvchr_to_utf8_flags(result, ~c, UNICODE_ALLOW_ANY);
              }
@@ -2407,15 +2388,16 @@ PP(pp_complement)
              SvUTF8_on(TARG);
          }
          else {
-             Newz(0, result, nchar + 1, U8);
+             Newxz(result, nchar + 1, U8);
              while (tmps < send) {
-                 U8 c = (U8)utf8n_to_uvchr(tmps, 0, &l, UTF8_ALLOW_ANY);
+                 const U8 c = (U8)utf8n_to_uvchr(tmps, 0, &l, UTF8_ALLOW_ANY);
                  tmps += UTF8SKIP(tmps);
                  *result++ = ~c;
              }
              *result = '\0';
              result -= nchar;
              sv_setpvn(TARG, (char*)result, nchar);
+             SvUTF8_off(TARG);
          }
          Safefree(result);
          SETs(TARG);
@@ -2470,7 +2452,7 @@ STATIC
 PP(pp_i_modulo_0)
 {
      /* This is the vanilla old i_modulo. */
-     dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
+     dVAR; dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
      {
          dPOPTOPiirl;
          if (!right)
@@ -2487,7 +2469,7 @@ PP(pp_i_modulo_1)
      /* This is the i_modulo with the workaround for the _moddi3 bug
       * in (at least) glibc 2.2.5 (the PERL_ABS() the workaround).
       * See below for pp_i_modulo. */
-     dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
+     dVAR; dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
      {
          dPOPTOPiirl;
          if (!right)
@@ -2500,7 +2482,7 @@ PP(pp_i_modulo_1)
 
 PP(pp_i_modulo)
 {
-     dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
+     dVAR; dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
      {
          dPOPTOPiirl;
          if (!right)
@@ -2508,7 +2490,7 @@ PP(pp_i_modulo)
          /* The assumption is to use hereafter the old vanilla version... */
          PL_op->op_ppaddr =
               PL_ppaddr[OP_I_MODULO] =
-                  &Perl_pp_i_modulo_0;
+                  Perl_pp_i_modulo_0;
          /* .. but if we have glibc, we might have a buggy _moddi3
           * (at least glicb 2.2.5 is known to have this bug), in other
           * words our integer modulus with negative quad as the second
@@ -2659,10 +2641,8 @@ PP(pp_sin)
 {
     dSP; dTARGET; tryAMAGICun(sin);
     {
-      NV value;
-      value = POPn;
-      value = Perl_sin(value);
-      XPUSHn(value);
+      const NV value = POPn;
+      XPUSHn(Perl_sin(value));
       RETURN;
     }
 }
@@ -2671,10 +2651,8 @@ PP(pp_cos)
 {
     dSP; dTARGET; tryAMAGICun(cos);
     {
-      NV value;
-      value = POPn;
-      value = Perl_cos(value);
-      XPUSHn(value);
+      const NV value = POPn;
+      XPUSHn(Perl_cos(value));
       RETURN;
     }
 }
@@ -2727,87 +2705,6 @@ PP(pp_srand)
     RETPUSHYES;
 }
 
-STATIC U32
-S_seed(pTHX)
-{
-    /*
-     * This is really just a quick hack which grabs various garbage
-     * values.  It really should be a real hash algorithm which
-     * spreads the effect of every input bit onto every output bit,
-     * if someone who knows about such things would bother to write it.
-     * Might be a good idea to add that function to CORE as well.
-     * No numbers below come from careful analysis or anything here,
-     * except they are primes and SEED_C1 > 1E6 to get a full-width
-     * value from (tv_sec * SEED_C1 + tv_usec).  The multipliers should
-     * probably be bigger too.
-     */
-#if RANDBITS > 16
-#  define SEED_C1      1000003
-#define   SEED_C4      73819
-#else
-#  define SEED_C1      25747
-#define   SEED_C4      20639
-#endif
-#define   SEED_C2      3
-#define   SEED_C3      269
-#define   SEED_C5      26107
-
-#ifndef PERL_NO_DEV_RANDOM
-    int fd;
-#endif
-    U32 u;
-#ifdef VMS
-#  include <starlet.h>
-    /* when[] = (low 32 bits, high 32 bits) of time since epoch
-     * in 100-ns units, typically incremented ever 10 ms.        */
-    unsigned int when[2];
-#else
-#  ifdef HAS_GETTIMEOFDAY
-    struct timeval when;
-#  else
-    Time_t when;
-#  endif
-#endif
-
-/* This test is an escape hatch, this symbol isn't set by Configure. */
-#ifndef PERL_NO_DEV_RANDOM
-#ifndef PERL_RANDOM_DEVICE
-   /* /dev/random isn't used by default because reads from it will block
-    * if there isn't enough entropy available.  You can compile with
-    * PERL_RANDOM_DEVICE to it if you'd prefer Perl to block until there
-    * is enough real entropy to fill the seed. */
-#  define PERL_RANDOM_DEVICE "/dev/urandom"
-#endif
-    fd = PerlLIO_open(PERL_RANDOM_DEVICE, 0);
-    if (fd != -1) {
-       if (PerlLIO_read(fd, &u, sizeof u) != sizeof u)
-           u = 0;
-       PerlLIO_close(fd);
-       if (u)
-           return u;
-    }
-#endif
-
-#ifdef VMS
-    _ckvmssts(sys$gettim(when));
-    u = (U32)SEED_C1 * when[0] + (U32)SEED_C2 * when[1];
-#else
-#  ifdef HAS_GETTIMEOFDAY
-    PerlProc_gettimeofday(&when,NULL);
-    u = (U32)SEED_C1 * when.tv_sec + (U32)SEED_C2 * when.tv_usec;
-#  else
-    (void)time(&when);
-    u = (U32)SEED_C1 * when;
-#  endif
-#endif
-    u += SEED_C3 * (U32)PerlProc_getpid();
-    u += SEED_C4 * (U32)PTR2UV(PL_stack_sp);
-#ifndef PLAN9           /* XXX Plan9 assembler chokes on this; fix needed  */
-    u += SEED_C5 * (U32)PTR2UV(&when);
-#endif
-    return u;
-}
-
 PP(pp_exp)
 {
     dSP; dTARGET; tryAMAGICun(exp);
@@ -2824,14 +2721,12 @@ PP(pp_log)
 {
     dSP; dTARGET; tryAMAGICun(log);
     {
-      NV value;
-      value = POPn;
+      const NV value = POPn;
       if (value <= 0.0) {
        SET_NUMERIC_STANDARD();
        DIE(aTHX_ "Can't take log of %"NVgf, value);
       }
-      value = Perl_log(value);
-      XPUSHn(value);
+      XPUSHn(Perl_log(value));
       RETURN;
     }
 }
@@ -2840,91 +2735,48 @@ PP(pp_sqrt)
 {
     dSP; dTARGET; tryAMAGICun(sqrt);
     {
-      NV value;
-      value = POPn;
+      const NV value = POPn;
       if (value < 0.0) {
        SET_NUMERIC_STANDARD();
        DIE(aTHX_ "Can't take sqrt of %"NVgf, value);
       }
-      value = Perl_sqrt(value);
-      XPUSHn(value);
+      XPUSHn(Perl_sqrt(value));
       RETURN;
     }
 }
 
-/*
- * There are strange code-generation bugs caused on sparc64 by gcc-2.95.2.
- * These need to be revisited when a newer toolchain becomes available.
- */
-#if defined(__sparc64__) && defined(__GNUC__)
-#   if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
-#       undef  SPARC64_MODF_WORKAROUND
-#       define SPARC64_MODF_WORKAROUND 1
-#   endif
-#endif
-
-#if defined(SPARC64_MODF_WORKAROUND)
-static NV
-sparc64_workaround_modf(NV theVal, NV *theIntRes)
-{
-    NV res, ret;
-    ret = Perl_modf(theVal, &res);
-    *theIntRes = res;
-    return ret;
-}
-#endif
-
 PP(pp_int)
 {
     dSP; dTARGET; tryAMAGICun(int);
     {
-      NV value;
-      IV iv = TOPi; /* attempt to convert to IV if possible. */
+      const IV iv = TOPi; /* attempt to convert to IV if possible. */
       /* XXX it's arguable that compiler casting to IV might be subtly
         different from modf (for numbers inside (IV_MIN,UV_MAX)) in which
         else preferring IV has introduced a subtle behaviour change bug. OTOH
         relying on floating point to be accurate is a bug.  */
 
-      if (SvIOK(TOPs)) {
+      if (!SvOK(TOPs))
+        SETu(0);
+      else if (SvIOK(TOPs)) {
        if (SvIsUV(TOPs)) {
-           UV uv = TOPu;
+           const UV uv = TOPu;
            SETu(uv);
        } else
            SETi(iv);
       } else {
-         value = TOPn;
+         const NV value = TOPn;
          if (value >= 0.0) {
              if (value < (NV)UV_MAX + 0.5) {
                  SETu(U_V(value));
              } else {
-#if defined(SPARC64_MODF_WORKAROUND)
-                  (void)sparc64_workaround_modf(value, &value);
-#elif defined(HAS_MODFL_POW32_BUG)
-/* some versions of glibc split (i + d) into (i-1, d+1) for 2^32 <= i < 2^64 */
-                  NV offset = Perl_modf(value, &value);
-                  (void)Perl_modf(offset, &offset);
-                  value += offset;
-#else
-                  (void)Perl_modf(value, &value);
-#endif
-                 SETn(value);
+                 SETn(Perl_floor(value));
              }
          }
          else {
              if (value > (NV)IV_MIN - 0.5) {
                  SETi(I_V(value));
              } else {
-#if defined(SPARC64_MODF_WORKAROUND)
-                  (void)sparc64_workaround_modf(-value, &value);
-#elif defined(HAS_MODFL_POW32_BUG)
-/* some versions of glibc split (i + d) into (i-1, d+1) for 2^32 <= i < 2^64 */
-                  NV offset = Perl_modf(-value, &value);
-                  (void)Perl_modf(offset, &offset);
-                  value += offset;
-#else
-                 (void)Perl_modf(-value, &value);
-#endif
-                 SETn(-value);
+                 SETn(Perl_ceil(value));
              }
          }
       }
@@ -2937,9 +2789,11 @@ PP(pp_abs)
     dSP; dTARGET; tryAMAGICun(abs);
     {
       /* This will cache the NV value if string isn't actually integer  */
-      IV iv = TOPi;
+      const IV iv = TOPi;
 
-      if (SvIOK(TOPs)) {
+      if (!SvOK(TOPs))
+        SETu(0);
+      else if (SvIOK(TOPs)) {
        /* IVX is precise  */
        if (SvIsUV(TOPs)) {
          SETu(TOPu);   /* force it to be numeric only */
@@ -2957,10 +2811,11 @@ PP(pp_abs)
          }
        }
       } else{
-       NV value = TOPn;
+       const NV value = TOPn;
        if (value < 0.0)
-         value = -value;
-       SETn(value);
+         SETn(-value);
+       else
+         SETn(value);
       }
     }
     RETURN;
@@ -2970,22 +2825,22 @@ PP(pp_abs)
 PP(pp_hex)
 {
     dSP; dTARGET;
-    char *tmps;
+    const char *tmps;
     I32 flags = PERL_SCAN_ALLOW_UNDERSCORES;
     STRLEN len;
     NV result_nv;
     UV result_uv;
-    SV* sv = POPs;
+    SV* const sv = POPs;
 
-    tmps = (SvPVx(sv, len));
+    tmps = (SvPV_const(sv, len));
     if (DO_UTF8(sv)) {
         /* If Unicode, try to downgrade
          * If not possible, croak. */
-         SV* tsv = sv_2mortal(newSVsv(sv));
+        SV* const tsv = sv_2mortal(newSVsv(sv));
        
         SvUTF8_on(tsv);
         sv_utf8_downgrade(tsv, FALSE);
-        tmps = SvPVX(tsv);
+        tmps = SvPV_const(tsv, len);
     }
     result_uv = grok_hex (tmps, &len, &flags, &result_nv);
     if (flags & PERL_SCAN_GREATER_THAN_UV_MAX) {
@@ -3000,22 +2855,22 @@ PP(pp_hex)
 PP(pp_oct)
 {
     dSP; dTARGET;
-    char *tmps;
+    const char *tmps;
     I32 flags = PERL_SCAN_ALLOW_UNDERSCORES;
     STRLEN len;
     NV result_nv;
     UV result_uv;
-    SV* sv = POPs;
+    SV* const sv = POPs;
 
-    tmps = (SvPVx(sv, len));
+    tmps = (SvPV_const(sv, len));
     if (DO_UTF8(sv)) {
         /* If Unicode, try to downgrade
          * If not possible, croak. */
-         SV* tsv = sv_2mortal(newSVsv(sv));
+        SV* const tsv = sv_2mortal(newSVsv(sv));
        
         SvUTF8_on(tsv);
         sv_utf8_downgrade(tsv, FALSE);
-        tmps = SvPVX(tsv);
+        tmps = SvPV_const(tsv, len);
     }
     while (*tmps && len && isSPACE(*tmps))
         tmps++, len--;
@@ -3061,13 +2916,13 @@ PP(pp_substr)
     I32 pos;
     I32 rem;
     I32 fail;
-    I32 lvalue = PL_op->op_flags & OPf_MOD || LVRET;
-    char *tmps;
-    I32 arybase = PL_curcop->cop_arybase;
+    const I32 lvalue = PL_op->op_flags & OPf_MOD || LVRET;
+    const char *tmps;
+    const I32 arybase = PL_curcop->cop_arybase;
     SV *repl_sv = NULL;
-    char *repl = 0;
+    const char *repl = 0;
     STRLEN repl_len;
-    int num_args = PL_op->op_private & 7;
+    const int num_args = PL_op->op_private & 7;
     bool repl_need_utf8_upgrade = FALSE;
     bool repl_is_utf8 = FALSE;
 
@@ -3076,7 +2931,7 @@ PP(pp_substr)
     if (num_args > 2) {
        if (num_args > 3) {
            repl_sv = POPs;
-           repl = SvPV(repl_sv, repl_len);
+           repl = SvPV_const(repl_sv, repl_len);
            repl_is_utf8 = DO_UTF8(repl_sv) && SvCUR(repl_sv);
        }
        len = POPi;
@@ -3092,7 +2947,7 @@ PP(pp_substr)
        else if (DO_UTF8(sv))
            repl_need_utf8_upgrade = TRUE;
     }
-    tmps = SvPV(sv, curlen);
+    tmps = SvPV_const(sv, curlen);
     if (DO_UTF8(sv)) {
         utf8_curlen = sv_len_utf8(sv);
        if (utf8_curlen == curlen)
@@ -3144,11 +2999,24 @@ PP(pp_substr)
        RETPUSHUNDEF;
     }
     else {
-       I32 upos = pos;
-       I32 urem = rem;
+       const I32 upos = pos;
+       const I32 urem = rem;
        if (utf8_curlen)
            sv_pos_u2b(sv, &pos, &rem);
        tmps += pos;
+       /* we either return a PV or an LV. If the TARG hasn't been used
+        * before, or is of that type, reuse it; otherwise use a mortal
+        * instead. Note that LVs can have an extended lifetime, so also
+        * dont reuse if refcount > 1 (bug #20933) */
+       if (SvTYPE(TARG) > SVt_NULL) {
+           if ( (SvTYPE(TARG) == SVt_PVLV)
+                   ? (!lvalue || SvREFCNT(TARG) > 1)
+                   : lvalue)
+           {
+               TARG = sv_newmortal();
+           }
+       }
+
        sv_setpvn(TARG, tmps, rem);
 #ifdef USE_LOCALE_COLLATE
        sv_unmagic(TARG, PERL_MAGIC_collxfrm);
@@ -3161,7 +3029,7 @@ PP(pp_substr)
            if (repl_need_utf8_upgrade) {
                repl_sv_copy = newSVsv(repl_sv);
                sv_utf8_upgrade(repl_sv_copy);
-               repl = SvPV(repl_sv_copy, repl_len);
+               repl = SvPV_const(repl_sv_copy, repl_len);
                repl_is_utf8 = DO_UTF8(repl_sv_copy) && SvCUR(sv);
            }
            sv_insert(sv, pos, rem, repl, repl_len);
@@ -3173,8 +3041,7 @@ PP(pp_substr)
        else if (lvalue) {              /* it's an lvalue! */
            if (!SvGMAGICAL(sv)) {
                if (SvROK(sv)) {
-                   STRLEN n_a;
-                   SvPV_force(sv,n_a);
+                   SvPV_force_nolen(sv);
                    if (ckWARN(WARN_SUBSTR))
                        Perl_warner(aTHX_ packWARN(WARN_SUBSTR),
                                "Attempt to use reference as lvalue in substr");
@@ -3185,12 +3052,12 @@ PP(pp_substr)
                    sv_setpvn(sv,"",0); /* avoid lexical reincarnation */
            }
 
-           if (SvREFCNT(TARG) > 1)     /* don't share the TARG (#20933) */
-               TARG = sv_newmortal();
            if (SvTYPE(TARG) < SVt_PVLV) {
                sv_upgrade(TARG, SVt_PVLV);
                sv_magic(TARG, Nullsv, PERL_MAGIC_substr, Nullch, 0);
            }
+           else
+               SvOK_off(TARG);
 
            LvTYPE(TARG) = 'x';
            if (LvTARG(TARG) != sv) {
@@ -3210,10 +3077,10 @@ PP(pp_substr)
 PP(pp_vec)
 {
     dSP; dTARGET;
-    register IV size   = POPi;
-    register IV offset = POPi;
-    register SV *src = POPs;
-    I32 lvalue = PL_op->op_flags & OPf_MOD || LVRET;
+    register const IV size   = POPi;
+    register const IV offset = POPi;
+    register SV * const src = POPs;
+    const I32 lvalue = PL_op->op_flags & OPf_MOD || LVRET;
 
     SvTAINTED_off(TARG);               /* decontaminate */
     if (lvalue) {                      /* it's an lvalue! */
@@ -3243,12 +3110,15 @@ PP(pp_index)
     dSP; dTARGET;
     SV *big;
     SV *little;
+    SV *temp = Nullsv;
     I32 offset;
     I32 retval;
-    char *tmps;
-    char *tmps2;
+    const char *tmps;
+    const char *tmps2;
     STRLEN biglen;
-    I32 arybase = PL_curcop->cop_arybase;
+    const I32 arybase = PL_curcop->cop_arybase;
+    int big_utf8;
+    int little_utf8;
 
     if (MAXARG < 3)
        offset = 0;
@@ -3256,9 +3126,31 @@ PP(pp_index)
        offset = POPi - arybase;
     little = POPs;
     big = POPs;
-    tmps = SvPV(big, biglen);
-    if (offset > 0 && DO_UTF8(big))
+    big_utf8 = DO_UTF8(big);
+    little_utf8 = DO_UTF8(little);
+    if (big_utf8 ^ little_utf8) {
+       /* One needs to be upgraded.  */
+       SV * const bytes = little_utf8 ? big : little;
+       STRLEN len;
+       const char * const p = SvPV_const(bytes, len);
+
+       temp = newSVpvn(p, len);
+
+       if (PL_encoding) {
+           sv_recode_to_utf8(temp, PL_encoding);
+       } else {
+           sv_utf8_upgrade(temp);
+       }
+       if (little_utf8) {
+           big = temp;
+           big_utf8 = TRUE;
+       } else {
+           little = temp;
+       }
+    }
+    if (big_utf8 && offset > 0)
        sv_pos_u2b(big, &offset, 0);
+    tmps = SvPV_const(big, biglen);
     if (offset < 0)
        offset = 0;
     else if (offset > (I32)biglen)
@@ -3268,8 +3160,10 @@ PP(pp_index)
        retval = -1;
     else
        retval = tmps2 - tmps;
-    if (retval > 0 && DO_UTF8(big))
+    if (retval > 0 && big_utf8)
        sv_pos_b2u(big, &retval);
+    if (temp)
+       SvREFCNT_dec(temp);
     PUSHi(retval + arybase);
     RETURN;
 }
@@ -3279,24 +3173,50 @@ PP(pp_rindex)
     dSP; dTARGET;
     SV *big;
     SV *little;
+    SV *temp = Nullsv;
     STRLEN blen;
     STRLEN llen;
     I32 offset;
     I32 retval;
-    char *tmps;
-    char *tmps2;
-    I32 arybase = PL_curcop->cop_arybase;
+    const char *tmps;
+    const char *tmps2;
+    const I32 arybase = PL_curcop->cop_arybase;
+    int big_utf8;
+    int little_utf8;
 
     if (MAXARG >= 3)
        offset = POPi;
     little = POPs;
     big = POPs;
-    tmps2 = SvPV(little, llen);
-    tmps = SvPV(big, blen);
+    big_utf8 = DO_UTF8(big);
+    little_utf8 = DO_UTF8(little);
+    if (big_utf8 ^ little_utf8) {
+       /* One needs to be upgraded.  */
+       SV * const bytes = little_utf8 ? big : little;
+       STRLEN len;
+       const char *p = SvPV_const(bytes, len);
+
+       temp = newSVpvn(p, len);
+
+       if (PL_encoding) {
+           sv_recode_to_utf8(temp, PL_encoding);
+       } else {
+           sv_utf8_upgrade(temp);
+       }
+       if (little_utf8) {
+           big = temp;
+           big_utf8 = TRUE;
+       } else {
+           little = temp;
+       }
+    }
+    tmps2 = SvPV_const(little, llen);
+    tmps = SvPV_const(big, blen);
+
     if (MAXARG < 3)
        offset = blen;
     else {
-       if (offset > 0 && DO_UTF8(big))
+       if (offset > 0 && big_utf8)
            sv_pos_u2b(big, &offset, 0);
        offset = offset - arybase + llen;
     }
@@ -3309,8 +3229,10 @@ PP(pp_rindex)
        retval = -1;
     else
        retval = tmps2 - tmps;
-    if (retval > 0 && DO_UTF8(big))
+    if (retval > 0 && big_utf8)
        sv_pos_b2u(big, &retval);
+    if (temp)
+       SvREFCNT_dec(temp);
     PUSHi(retval + arybase);
     RETURN;
 }
@@ -3332,7 +3254,7 @@ PP(pp_ord)
     dSP; dTARGET;
     SV *argsv = POPs;
     STRLEN len;
-    U8 *s = (U8*)SvPVx(argsv, len);
+    const U8 *s = (U8*)SvPV_const(argsv, len);
     SV *tmpsv;
 
     if (PL_encoding && SvPOK(argsv) && !DO_UTF8(argsv)) {
@@ -3342,7 +3264,7 @@ PP(pp_ord)
     }
 
     XPUSHu(DO_UTF8(argsv) ?
-          utf8n_to_uvchr(s, UTF8_MAXLEN, 0, UTF8_ALLOW_ANYUV) :
+          utf8n_to_uvchr(s, UTF8_MAXBYTES, 0, UTF8_ALLOW_ANYUV) :
           (*s & 0xff));
 
     RETURN;
@@ -3352,14 +3274,27 @@ PP(pp_chr)
 {
     dSP; dTARGET;
     char *tmps;
-    UV value = POPu;
+    UV value;
+
+    if (((SvIOK_notUV(TOPs) && SvIV(TOPs) < 0)
+        ||
+        (SvNOK(TOPs) && SvNV(TOPs) < 0.0))) {
+       if (IN_BYTES) {
+           value = POPu; /* chr(-1) eq chr(0xff), etc. */
+       } else {
+           (void) POPs; /* Ignore the argument value. */
+           value = UNICODE_REPLACEMENT;
+       }
+    } else {
+       value = POPu;
+    }
 
-    (void)SvUPGRADE(TARG,SVt_PV);
+    SvUPGRADE(TARG,SVt_PV);
 
     if (value > 255 && !IN_BYTES) {
        SvGROW(TARG, (STRLEN)UNISKIP(value)+1);
        tmps = (char*)uvchr_to_utf8_flags((U8*)SvPVX(TARG), value, 0);
-       SvCUR_set(TARG, tmps - SvPVX(TARG));
+       SvCUR_set(TARG, tmps - SvPVX_const(TARG));
        *tmps = '\0';
        (void)SvPOK_only(TARG);
        SvUTF8_on(TARG);
@@ -3393,22 +3328,21 @@ PP(pp_chr)
 
 PP(pp_crypt)
 {
-    dSP; dTARGET;
 #ifdef HAS_CRYPT
+    dSP; dTARGET;
     dPOPTOPssrl;
-    STRLEN n_a;
     STRLEN len;
-    char *tmps = SvPV(left, len);
+    const char *tmps = SvPV_const(left, len);
 
     if (DO_UTF8(left)) {
          /* If Unicode, try to downgrade.
          * If not possible, croak.
          * Yes, we made this up.  */
-         SV* tsv = sv_2mortal(newSVsv(left));
+        SV* const tsv = sv_2mortal(newSVsv(left));
 
         SvUTF8_on(tsv);
         sv_utf8_downgrade(tsv, FALSE);
-        tmps = SvPVX(tsv);
+        tmps = SvPV_const(tsv, len);
     }
 #   ifdef USE_ITHREADS
 #     ifdef HAS_CRYPT_R
@@ -3429,9 +3363,9 @@ PP(pp_crypt)
 #     endif /* HAS_CRYPT_R */
 #   endif /* USE_ITHREADS */
 #   ifdef FCRYPT
-    sv_setpv(TARG, fcrypt(tmps, SvPV(right, n_a)));
+    sv_setpv(TARG, fcrypt(tmps, SvPV_nolen_const(right)));
 #   else
-    sv_setpv(TARG, PerlProc_crypt(tmps, SvPV(right, n_a)));
+    sv_setpv(TARG, PerlProc_crypt(tmps, SvPV_nolen_const(right)));
 #   endif
     SETs(TARG);
     RETURN;
@@ -3445,14 +3379,14 @@ PP(pp_ucfirst)
 {
     dSP;
     SV *sv = TOPs;
-    register U8 *s;
+    const U8 *s;
     STRLEN slen;
 
     SvGETMAGIC(sv);
     if (DO_UTF8(sv) &&
-       (s = (U8*)SvPV_nomg(sv, slen)) && slen &&
+       (s = (const U8*)SvPV_nomg_const(sv, slen)) && slen &&
        UTF8_IS_START(*s)) {
-       U8 tmpbuf[UTF8_MAXLEN_UCLC+1];
+       U8 tmpbuf[UTF8_MAXBYTES_CASE+1];
        STRLEN ulen;
        STRLEN tculen;
 
@@ -3481,6 +3415,7 @@ PP(pp_ucfirst)
        }
     }
     else {
+       U8 *s1;
        if (!SvPADTMP(sv) || SvREADONLY(sv)) {
            dTARGET;
            SvUTF8_off(TARG);                           /* decontaminate */
@@ -3488,15 +3423,15 @@ PP(pp_ucfirst)
            sv = TARG;
            SETs(sv);
        }
-       s = (U8*)SvPV_force_nomg(sv, slen);
-       if (*s) {
+       s1 = (U8*)SvPV_force_nomg(sv, slen);
+       if (*s1) {
            if (IN_LOCALE_RUNTIME) {
                TAINT;
                SvTAINTED_on(sv);
-               *s = toUPPER_LC(*s);
+               *s1 = toUPPER_LC(*s1);
            }
            else
-               *s = toUPPER(*s);
+               *s1 = toUPPER(*s1);
        }
     }
     SvSETMAGIC(sv);
@@ -3507,15 +3442,15 @@ PP(pp_lcfirst)
 {
     dSP;
     SV *sv = TOPs;
-    register U8 *s;
+    const U8 *s;
     STRLEN slen;
 
     SvGETMAGIC(sv);
     if (DO_UTF8(sv) &&
-       (s = (U8*)SvPV_nomg(sv, slen)) && slen &&
+       (s = (const U8*)SvPV_nomg_const(sv, slen)) && slen &&
        UTF8_IS_START(*s)) {
        STRLEN ulen;
-       U8 tmpbuf[UTF8_MAXLEN_UCLC+1];
+       U8 tmpbuf[UTF8_MAXBYTES_CASE+1];
        U8 *tend;
        UV uv;
 
@@ -3537,6 +3472,7 @@ PP(pp_lcfirst)
        }
     }
     else {
+       U8 *s1;
        if (!SvPADTMP(sv) || SvREADONLY(sv)) {
            dTARGET;
            SvUTF8_off(TARG);                           /* decontaminate */
@@ -3544,15 +3480,15 @@ PP(pp_lcfirst)
            sv = TARG;
            SETs(sv);
        }
-       s = (U8*)SvPV_force_nomg(sv, slen);
-       if (*s) {
+       s1 = (U8*)SvPV_force_nomg(sv, slen);
+       if (*s1) {
            if (IN_LOCALE_RUNTIME) {
                TAINT;
                SvTAINTED_on(sv);
-               *s = toLOWER_LC(*s);
+               *s1 = toLOWER_LC(*s1);
            }
            else
-               *s = toLOWER(*s);
+               *s1 = toLOWER(*s1);
        }
     }
     SvSETMAGIC(sv);
@@ -3563,7 +3499,6 @@ PP(pp_uc)
 {
     dSP;
     SV *sv = TOPs;
-    register U8 *s;
     STRLEN len;
 
     SvGETMAGIC(sv);
@@ -3571,36 +3506,52 @@ PP(pp_uc)
        dTARGET;
        STRLEN ulen;
        register U8 *d;
-       U8 *send;
-       U8 tmpbuf[UTF8_MAXLEN_UCLC+1];
+       const U8 *s;
+       const U8 *send;
+       U8 tmpbuf[UTF8_MAXBYTES+1];
 
-       s = (U8*)SvPV_nomg(sv,len);
+       s = (const U8*)SvPV_nomg_const(sv,len);
        if (!len) {
            SvUTF8_off(TARG);                           /* decontaminate */
            sv_setpvn(TARG, "", 0);
            SETs(TARG);
        }
        else {
-           STRLEN nchar = utf8_length(s, s + len);
+           STRLEN min = len + 1;
 
-           (void)SvUPGRADE(TARG, SVt_PV);
-           SvGROW(TARG, (nchar * UTF8_MAXLEN_UCLC) + 1);
+           SvUPGRADE(TARG, SVt_PV);
+           SvGROW(TARG, min);
            (void)SvPOK_only(TARG);
            d = (U8*)SvPVX(TARG);
            send = s + len;
            while (s < send) {
+               STRLEN u = UTF8SKIP(s);
+
                toUPPER_utf8(s, tmpbuf, &ulen);
+               if (ulen > u && (SvLEN(TARG) < (min += ulen - u))) {
+                   /* If the eventually required minimum size outgrows
+                    * the available space, we need to grow. */
+                   UV o = d - (U8*)SvPVX_const(TARG);
+
+                   /* If someone uppercases one million U+03B0s we
+                    * SvGROW() one million times.  Or we could try
+                    * guessing how much to allocate without allocating
+                    * too much. Such is life. */
+                   SvGROW(TARG, min);
+                   d = (U8*)SvPVX(TARG) + o;
+               }
                Copy(tmpbuf, d, ulen, U8);
                d += ulen;
-               s += UTF8SKIP(s);
+               s += u;
            }
            *d = '\0';
            SvUTF8_on(TARG);
-           SvCUR_set(TARG, d - (U8*)SvPVX(TARG));
+           SvCUR_set(TARG, d - (U8*)SvPVX_const(TARG));
            SETs(TARG);
        }
     }
     else {
+       U8 *s;
        if (!SvPADTMP(sv) || SvREADONLY(sv)) {
            dTARGET;
            SvUTF8_off(TARG);                           /* decontaminate */
@@ -3610,7 +3561,7 @@ PP(pp_uc)
        }
        s = (U8*)SvPV_force_nomg(sv, len);
        if (len) {
-           register U8 *send = s + len;
+           register const U8 *send = s + len;
 
            if (IN_LOCALE_RUNTIME) {
                TAINT;
@@ -3632,34 +3583,36 @@ PP(pp_lc)
 {
     dSP;
     SV *sv = TOPs;
-    register U8 *s;
     STRLEN len;
 
     SvGETMAGIC(sv);
     if (DO_UTF8(sv)) {
        dTARGET;
+       const U8 *s;
        STRLEN ulen;
        register U8 *d;
-       U8 *send;
-       U8 tmpbuf[UTF8_MAXLEN_UCLC+1];
+       const U8 *send;
+       U8 tmpbuf[UTF8_MAXBYTES_CASE+1];
 
-       s = (U8*)SvPV_nomg(sv,len);
+       s = (const U8*)SvPV_nomg_const(sv,len);
        if (!len) {
            SvUTF8_off(TARG);                           /* decontaminate */
            sv_setpvn(TARG, "", 0);
            SETs(TARG);
        }
        else {
-           STRLEN nchar = utf8_length(s, s + len);
+           STRLEN min = len + 1;
 
-           (void)SvUPGRADE(TARG, SVt_PV);
-           SvGROW(TARG, (nchar * UTF8_MAXLEN_UCLC) + 1);
+           SvUPGRADE(TARG, SVt_PV);
+           SvGROW(TARG, min);
            (void)SvPOK_only(TARG);
            d = (U8*)SvPVX(TARG);
            send = s + len;
            while (s < send) {
-               UV uv = toLOWER_utf8(s, tmpbuf, &ulen);
-#define GREEK_CAPITAL_LETTER_SIGMA 0x03A3 /* Unicode */
+               const STRLEN u = UTF8SKIP(s);
+               const UV uv = toLOWER_utf8(s, tmpbuf, &ulen);
+
+#define GREEK_CAPITAL_LETTER_SIGMA 0x03A3 /* Unicode U+03A3 */
                if (uv == GREEK_CAPITAL_LETTER_SIGMA) {
                     /*
                      * Now if the sigma is NOT followed by
@@ -3673,20 +3626,35 @@ PP(pp_lc)
                      * then it should be mapped to 0x03C2,
                      * (GREEK SMALL LETTER FINAL SIGMA),
                      * instead of staying 0x03A3.
-                     * See lib/unicore/SpecCase.txt.
+                     * "should be": in other words,
+                     * this is not implemented yet.
+                     * See lib/unicore/SpecialCasing.txt.
                      */
                }
+               if (ulen > u && (SvLEN(TARG) < (min += ulen - u))) {
+                   /* If the eventually required minimum size outgrows
+                    * the available space, we need to grow. */
+                   UV o = d - (U8*)SvPVX_const(TARG);
+
+                   /* If someone lowercases one million U+0130s we
+                    * SvGROW() one million times.  Or we could try
+                    * guessing how much to allocate without allocating.
+                    * too much.  Such is life. */
+                   SvGROW(TARG, min);
+                   d = (U8*)SvPVX(TARG) + o;
+               }
                Copy(tmpbuf, d, ulen, U8);
                d += ulen;
-               s += UTF8SKIP(s);
+               s += u;
            }
            *d = '\0';
            SvUTF8_on(TARG);
-           SvCUR_set(TARG, d - (U8*)SvPVX(TARG));
+           SvCUR_set(TARG, d - (U8*)SvPVX_const(TARG));
            SETs(TARG);
        }
     }
     else {
+       U8 *s;
        if (!SvPADTMP(sv) || SvREADONLY(sv)) {
            dTARGET;
            SvUTF8_off(TARG);                           /* decontaminate */
@@ -3697,7 +3665,7 @@ PP(pp_lc)
 
        s = (U8*)SvPV_force_nomg(sv, len);
        if (len) {
-           register U8 *send = s + len;
+           register const U8 * const send = s + len;
 
            if (IN_LOCALE_RUNTIME) {
                TAINT;
@@ -3718,14 +3686,14 @@ PP(pp_lc)
 PP(pp_quotemeta)
 {
     dSP; dTARGET;
-    SV *sv = TOPs;
+    SV * const sv = TOPs;
     STRLEN len;
-    register char *s = SvPV(sv,len);
-    register char *d;
+    register const char *s = SvPV_const(sv,len);
 
     SvUTF8_off(TARG);                          /* decontaminate */
     if (len) {
-       (void)SvUPGRADE(TARG, SVt_PV);
+       register char *d;
+       SvUPGRADE(TARG, SVt_PV);
        SvGROW(TARG, (len * 2) + 1);
        d = SvPVX(TARG);
        if (DO_UTF8(sv)) {
@@ -3755,7 +3723,7 @@ PP(pp_quotemeta)
            }
        }
        *d = '\0';
-       SvCUR_set(TARG, d - SvPVX(TARG));
+       SvCUR_set(TARG, d - SvPVX_const(TARG));
        (void)SvPOK_only_UTF8(TARG);
     }
     else
@@ -3771,17 +3739,16 @@ PP(pp_quotemeta)
 PP(pp_aslice)
 {
     dSP; dMARK; dORIGMARK;
-    register SV** svp;
-    register AV* av = (AV*)POPs;
-    register I32 lval = (PL_op->op_flags & OPf_MOD || LVRET);
-    I32 arybase = PL_curcop->cop_arybase;
-    I32 elem;
+    register AV* const av = (AV*)POPs;
+    register const I32 lval = (PL_op->op_flags & OPf_MOD || LVRET);
 
     if (SvTYPE(av) == SVt_PVAV) {
+       const I32 arybase = PL_curcop->cop_arybase;
        if (lval && PL_op->op_private & OPpLVAL_INTRO) {
+           register SV **svp;
            I32 max = -1;
            for (svp = MARK + 1; svp <= SP; svp++) {
-               elem = SvIVx(*svp);
+               const I32 elem = SvIVx(*svp);
                if (elem > max)
                    max = elem;
            }
@@ -3789,7 +3756,8 @@ PP(pp_aslice)
                av_extend(av, max);
        }
        while (++MARK <= SP) {
-           elem = SvIVx(*MARK);
+           register SV **svp;
+           I32 elem = SvIVx(*MARK);
 
            if (elem > 0)
                elem -= arybase;
@@ -3805,7 +3773,7 @@ PP(pp_aslice)
     }
     if (GIMME != G_ARRAY) {
        MARK = ORIGMARK;
-       *++MARK = *SP;
+       *++MARK = SP > ORIGMARK ? *SP : &PL_sv_undef;
        SP = MARK;
     }
     RETURN;
@@ -3816,9 +3784,9 @@ PP(pp_aslice)
 PP(pp_each)
 {
     dSP;
-    HV *hash = (HV*)POPs;
+    HV * const hash = (HV*)POPs;
     HE *entry;
-    I32 gimme = GIMME_V;
+    const I32 gimme = GIMME_V;
 
     PUTBACK;
     /* might clobber stack_sp */
@@ -3827,7 +3795,7 @@ PP(pp_each)
 
     EXTEND(SP, 2);
     if (entry) {
-        SV* sv = hv_iterkeysv(entry);
+       SV* const sv = hv_iterkeysv(entry);
        PUSHs(sv);      /* won't clobber stack_sp */
        if (gimme == G_ARRAY) {
            SV *val;
@@ -3844,39 +3812,26 @@ PP(pp_each)
     RETURN;
 }
 
-PP(pp_values)
-{
-    return do_kv();
-}
-
-PP(pp_keys)
-{
-    return do_kv();
-}
-
 PP(pp_delete)
 {
     dSP;
-    I32 gimme = GIMME_V;
-    I32 discard = (gimme == G_VOID) ? G_DISCARD : 0;
-    SV *sv;
-    HV *hv;
+    const I32 gimme = GIMME_V;
+    const I32 discard = (gimme == G_VOID) ? G_DISCARD : 0;
 
     if (PL_op->op_private & OPpSLICE) {
        dMARK; dORIGMARK;
-       U32 hvtype;
-       hv = (HV*)POPs;
-       hvtype = SvTYPE(hv);
+       HV * const hv = (HV*)POPs;
+       const U32 hvtype = SvTYPE(hv);
        if (hvtype == SVt_PVHV) {                       /* hash element */
            while (++MARK <= SP) {
-               sv = hv_delete_ent(hv, *MARK, discard, 0);
+               SV * const sv = hv_delete_ent(hv, *MARK, discard, 0);
                *MARK = sv ? sv : &PL_sv_undef;
            }
        }
        else if (hvtype == SVt_PVAV) {                  /* array element */
             if (PL_op->op_flags & OPf_SPECIAL) {
                 while (++MARK <= SP) {
-                    sv = av_delete((AV*)hv, SvIV(*MARK), discard);
+                    SV * const sv = av_delete((AV*)hv, SvIV(*MARK), discard);
                     *MARK = sv ? sv : &PL_sv_undef;
                 }
             }
@@ -3887,13 +3842,17 @@ PP(pp_delete)
            SP = ORIGMARK;
        else if (gimme == G_SCALAR) {
            MARK = ORIGMARK;
-           *++MARK = *SP;
+           if (SP > MARK)
+               *++MARK = *SP;
+           else
+               *++MARK = &PL_sv_undef;
            SP = MARK;
        }
     }
     else {
        SV *keysv = POPs;
-       hv = (HV*)POPs;
+       HV * const hv = (HV*)POPs;
+       SV *sv;
        if (SvTYPE(hv) == SVt_PVHV)
            sv = hv_delete_ent(hv, keysv, discard, 0);
        else if (SvTYPE(hv) == SVt_PVAV) {
@@ -3920,9 +3879,8 @@ PP(pp_exists)
 
     if (PL_op->op_private & OPpEXISTS_SUB) {
        GV *gv;
-       CV *cv;
        SV *sv = POPs;
-       cv = sv_2cv(sv, &hv, &gv, FALSE);
+       CV * const cv = sv_2cv(sv, &hv, &gv, FALSE);
        if (cv)
            RETPUSHYES;
        if (gv && isGV(gv) && GvCV(gv) && !GvCVGEN(gv))
@@ -3950,9 +3908,9 @@ PP(pp_exists)
 PP(pp_hslice)
 {
     dSP; dMARK; dORIGMARK;
-    register HV *hv = (HV*)POPs;
-    register I32 lval = (PL_op->op_flags & OPf_MOD || LVRET);
-    bool localizing = PL_op->op_private & OPpLVAL_INTRO ? TRUE : FALSE;
+    register HV * const hv = (HV*)POPs;
+    register const I32 lval = (PL_op->op_flags & OPf_MOD || LVRET);
+    const bool localizing = PL_op->op_private & OPpLVAL_INTRO;
     bool other_magic = FALSE;
 
     if (localizing) {
@@ -3970,7 +3928,7 @@ PP(pp_hslice)
     }
 
     while (++MARK <= SP) {
-        SV *keysv = *MARK;
+        SV * const keysv = *MARK;
         SV **svp;
         HE *he;
         bool preeminent = FALSE;
@@ -3985,15 +3943,14 @@ PP(pp_hslice)
 
         if (lval) {
             if (!svp || *svp == &PL_sv_undef) {
-                STRLEN n_a;
-                DIE(aTHX_ PL_no_helem, SvPV(keysv, n_a));
+                DIE(aTHX_ PL_no_helem_sv, keysv);
             }
             if (localizing) {
                 if (preeminent)
                     save_helem(hv, keysv, svp);
                 else {
                     STRLEN keylen;
-                    char *key = SvPV(keysv, keylen);
+                    const char *key = SvPV_const(keysv, keylen);
                     SAVEDELETE(hv, savepvn(key,keylen), keylen);
                 }
             }
@@ -4002,7 +3959,7 @@ PP(pp_hslice)
     }
     if (GIMME != G_ARRAY) {
        MARK = ORIGMARK;
-       *++MARK = *SP;
+       *++MARK = SP > ORIGMARK ? *SP : &PL_sv_undef;
        SP = MARK;
     }
     RETURN;
@@ -4026,20 +3983,18 @@ PP(pp_list)
 PP(pp_lslice)
 {
     dSP;
-    SV **lastrelem = PL_stack_sp;
-    SV **lastlelem = PL_stack_base + POPMARK;
-    SV **firstlelem = PL_stack_base + POPMARK + 1;
-    register SV **firstrelem = lastlelem + 1;
-    I32 arybase = PL_curcop->cop_arybase;
-    I32 lval = PL_op->op_flags & OPf_MOD;
-    I32 is_something_there = lval;
-
-    register I32 max = lastrelem - lastlelem;
+    SV ** const lastrelem = PL_stack_sp;
+    SV ** const lastlelem = PL_stack_base + POPMARK;
+    SV ** const firstlelem = PL_stack_base + POPMARK + 1;
+    register SV ** const firstrelem = lastlelem + 1;
+    const I32 arybase = PL_curcop->cop_arybase;
+    I32 is_something_there = PL_op->op_flags & OPf_MOD;
+
+    register const I32 max = lastrelem - lastlelem;
     register SV **lelem;
-    register I32 ix;
 
     if (GIMME != G_ARRAY) {
-       ix = SvIVx(*lastlelem);
+       I32 ix = SvIVx(*lastlelem);
        if (ix < 0)
            ix += max;
        else
@@ -4058,7 +4013,7 @@ PP(pp_lslice)
     }
 
     for (lelem = firstlelem; lelem <= lastlelem; lelem++) {
-       ix = SvIVx(*lelem);
+       I32 ix = SvIVx(*lelem);
        if (ix < 0)
            ix += max;
        else
@@ -4081,8 +4036,8 @@ PP(pp_lslice)
 PP(pp_anonlist)
 {
     dSP; dMARK; dORIGMARK;
-    I32 items = SP - MARK;
-    SV *av = sv_2mortal((SV*)av_make(items, MARK+1));
+    const I32 items = SP - MARK;
+    SV * const av = sv_2mortal((SV*)av_make(items, MARK+1));
     SP = ORIGMARK;             /* av_make() might realloc stack_sp */
     XPUSHs(av);
     RETURN;
@@ -4091,11 +4046,11 @@ PP(pp_anonlist)
 PP(pp_anonhash)
 {
     dSP; dMARK; dORIGMARK;
-    HV* hv = (HV*)sv_2mortal((SV*)newHV());
+    HV* const hv = (HV*)sv_2mortal((SV*)newHV());
 
     while (MARK < SP) {
-       SV* key = *++MARK;
-       SV *val = NEWSV(46, 0);
+       SV * const key = *++MARK;
+       SV * const val = NEWSV(46, 0);
        if (MARK < SP)
            sv_setsv(val, *++MARK);
        else if (ckWARN(WARN_MISC))
@@ -4109,7 +4064,7 @@ PP(pp_anonhash)
 
 PP(pp_splice)
 {
-    dSP; dMARK; dORIGMARK;
+    dVAR; dSP; dMARK; dORIGMARK;
     register AV *ary = (AV*)*++MARK;
     register SV **src;
     register SV **dst;
@@ -4120,9 +4075,9 @@ PP(pp_splice)
     I32 after;
     I32 diff;
     SV **tmparyval = 0;
-    MAGIC *mg;
+    const MAGIC * const mg = SvTIED_mg((SV*)ary, PERL_MAGIC_tied);
 
-    if ((mg = SvTIED_mg((SV*)ary, PERL_MAGIC_tied))) {
+    if (mg) {
        *MARK-- = SvTIED_obj((SV*)ary, mg);
        PUSHMARK(MARK);
        PUTBACK;
@@ -4178,9 +4133,15 @@ PP(pp_splice)
     if (newlen && !AvREAL(ary) && AvREIFY(ary))
        av_reify(ary);
 
+    /* make new elements SVs now: avoid problems if they're from the array */
+    for (dst = MARK, i = newlen; i; i--) {
+        SV * const h = *dst;
+       *dst++ = newSVsv(h);
+    }
+
     if (diff < 0) {                            /* shrinking the area */
        if (newlen) {
-           New(451, tmparyval, newlen, SV*);   /* so remember insertion */
+           Newx(tmparyval, newlen, SV*);       /* so remember insertion */
            Copy(MARK, tmparyval, newlen, SV*);
        }
 
@@ -4217,7 +4178,7 @@ PP(pp_splice)
                    *dst-- = *src--;
            }
            dst = AvARRAY(ary);
-           SvPVX(ary) = (char*)(AvARRAY(ary) - diff); /* diff is negative */
+           SvPV_set(ary, (char*)(AvARRAY(ary) - diff)); /* diff is negative */
            AvMAX(ary) += diff;
        }
        else {
@@ -4234,17 +4195,13 @@ PP(pp_splice)
            dst[--i] = &PL_sv_undef;
        
        if (newlen) {
-           for (src = tmparyval, dst = AvARRAY(ary) + offset;
-             newlen; newlen--) {
-               *dst = NEWSV(46, 0);
-               sv_setsv(*dst++, *src++);
-           }
+           Copy( tmparyval, AvARRAY(ary) + offset, newlen, SV* );
            Safefree(tmparyval);
        }
     }
     else {                                     /* no, expanding (or same) */
        if (length) {
-           New(452, tmparyval, length, SV*);   /* so remember deletion */
+           Newx(tmparyval, length, SV*);       /* so remember deletion */
            Copy(AvARRAY(ary)+offset, tmparyval, length, SV*);
        }
 
@@ -4258,7 +4215,7 @@ PP(pp_splice)
                    dst = src - diff;
                    Move(src, dst, offset, SV*);
                }
-               SvPVX(ary) = (char*)(AvARRAY(ary) - diff);/* diff is positive */
+               SvPV_set(ary, (char*)(AvARRAY(ary) - diff));/* diff is positive */
                AvMAX(ary) += diff;
                AvFILLp(ary) += diff;
            }
@@ -4277,10 +4234,10 @@ PP(pp_splice)
            }
        }
 
-       for (src = MARK, dst = AvARRAY(ary) + offset; newlen; newlen--) {
-           *dst = NEWSV(46, 0);
-           sv_setsv(*dst++, *src++);
+       if (newlen) {
+           Copy( MARK, AvARRAY(ary) + offset, newlen, SV* );
        }
+
        MARK = ORIGMARK + 1;
        if (GIMME == G_ARRAY) {                 /* copy return vals to stack */
            if (length) {
@@ -4314,12 +4271,11 @@ PP(pp_splice)
 
 PP(pp_push)
 {
-    dSP; dMARK; dORIGMARK; dTARGET;
+    dVAR; dSP; dMARK; dORIGMARK; dTARGET;
     register AV *ary = (AV*)*++MARK;
-    register SV *sv = &PL_sv_undef;
-    MAGIC *mg;
+    const MAGIC * const mg = SvTIED_mg((SV*)ary, PERL_MAGIC_tied);
 
-    if ((mg = SvTIED_mg((SV*)ary, PERL_MAGIC_tied))) {
+    if (mg) {
        *MARK-- = SvTIED_obj((SV*)ary, mg);
        PUSHMARK(MARK);
        PUTBACK;
@@ -4327,26 +4283,27 @@ PP(pp_push)
        call_method("PUSH",G_SCALAR|G_DISCARD);
        LEAVE;
        SPAGAIN;
+       SP = ORIGMARK;
+       PUSHi( AvFILL(ary) + 1 );
     }
     else {
-       /* Why no pre-extend of ary here ? */
        for (++MARK; MARK <= SP; MARK++) {
-           sv = NEWSV(51, 0);
+           SV * const sv = NEWSV(51, 0);
            if (*MARK)
                sv_setsv(sv, *MARK);
-           av_push(ary, sv);
+           av_store(ary, AvFILLp(ary)+1, sv);
        }
+       SP = ORIGMARK;
+       PUSHi( AvFILLp(ary) + 1 );
     }
-    SP = ORIGMARK;
-    PUSHi( AvFILL(ary) + 1 );
     RETURN;
 }
 
 PP(pp_pop)
 {
     dSP;
-    AV *av = (AV*)POPs;
-    SV *sv = av_pop(av);
+    AV * const av = (AV*)POPs;
+    SV * const sv = av_pop(av);
     if (AvREAL(av))
        (void)sv_2mortal(sv);
     PUSHs(sv);
@@ -4356,8 +4313,8 @@ PP(pp_pop)
 PP(pp_shift)
 {
     dSP;
-    AV *av = (AV*)POPs;
-    SV *sv = av_shift(av);
+    AV * const av = (AV*)POPs;
+    SV * const sv = av_shift(av);
     EXTEND(SP, 1);
     if (!sv)
        RETPUSHUNDEF;
@@ -4369,13 +4326,11 @@ PP(pp_shift)
 
 PP(pp_unshift)
 {
-    dSP; dMARK; dORIGMARK; dTARGET;
+    dVAR; dSP; dMARK; dORIGMARK; dTARGET;
     register AV *ary = (AV*)*++MARK;
-    register SV *sv;
-    register I32 i = 0;
-    MAGIC *mg;
+    const MAGIC * const mg = SvTIED_mg((SV*)ary, PERL_MAGIC_tied);
 
-    if ((mg = SvTIED_mg((SV*)ary, PERL_MAGIC_tied))) {
+    if (mg) {
        *MARK-- = SvTIED_obj((SV*)ary, mg);
        PUSHMARK(MARK);
        PUTBACK;
@@ -4385,10 +4340,10 @@ PP(pp_unshift)
        SPAGAIN;
     }
     else {
+       register I32 i = 0;
        av_unshift(ary, SP - MARK);
        while (MARK < SP) {
-           sv = NEWSV(27, 0);
-           sv_setsv(sv, *++MARK);
+           SV * const sv = newSVsv(*++MARK);
            (void)av_store(ary, i++, sv);
        }
     }
@@ -4400,13 +4355,12 @@ PP(pp_unshift)
 PP(pp_reverse)
 {
     dSP; dMARK;
-    register SV *tmp;
-    SV **oldsp = SP;
+    SV ** const oldsp = SP;
 
     if (GIMME == G_ARRAY) {
        MARK++;
        while (MARK < SP) {
-           tmp = *MARK;
+           register SV * const tmp = *MARK;
            *MARK++ = *SP;
            *SP-- = tmp;
        }
@@ -4419,17 +4373,22 @@ PP(pp_reverse)
        register I32 tmp;
        dTARGET;
        STRLEN len;
+       I32 padoff_du;
 
        SvUTF8_off(TARG);                               /* decontaminate */
        if (SP - MARK > 1)
            do_join(TARG, &PL_sv_no, MARK, SP);
        else
-           sv_setsv(TARG, (SP > MARK) ? *SP : DEFSV);
+           sv_setsv(TARG, (SP > MARK)
+                   ? *SP
+                   : (padoff_du = find_rundefsvoffset(),
+                       (padoff_du == NOT_IN_PAD || PAD_COMPNAME_FLAGS(padoff_du) & SVpad_OUR)
+                       ? DEFSV : PAD_SVl(padoff_du)));
        up = SvPV_force(TARG, len);
        if (len > 1) {
            if (DO_UTF8(TARG)) {        /* first reverse each character */
                U8* s = (U8*)SvPVX(TARG);
-               U8* send = (U8*)(s + len);
+               const U8* send = (U8*)(s + len);
                while (s < send) {
                    if (UTF8_IS_INVARIANT(*s)) {
                        s++;
@@ -4467,30 +4426,29 @@ PP(pp_reverse)
 
 PP(pp_split)
 {
-    dSP; dTARG;
+    dVAR; dSP; dTARG;
     AV *ary;
     register IV limit = POPi;                  /* note, negative is forever */
-    SV *sv = POPs;
+    SV * const sv = POPs;
     STRLEN len;
-    register char *s = SvPV(sv, len);
-    bool do_utf8 = DO_UTF8(sv);
-    char *strend = s + len;
+    register const char *s = SvPV_const(sv, len);
+    const bool do_utf8 = DO_UTF8(sv);
+    const char *strend = s + len;
     register PMOP *pm;
     register REGEXP *rx;
     register SV *dstr;
-    register char *m;
+    register const char *m;
     I32 iters = 0;
-    STRLEN slen = do_utf8 ? utf8_length((U8*)s, (U8*)strend) : (strend - s);
+    const STRLEN slen = do_utf8 ? utf8_length((U8*)s, (U8*)strend) : (strend - s);
     I32 maxiters = slen + 10;
-    I32 i;
-    char *orig;
-    I32 origlimit = limit;
+    const char *orig;
+    const I32 origlimit = limit;
     I32 realarray = 0;
     I32 base;
-    AV *oldstack = PL_curstack;
-    I32 gimme = GIMME_V;
-    I32 oldsave = PL_savestack_ix;
+    const I32 gimme = GIMME_V;
+    const I32 oldsave = PL_savestack_ix;
     I32 make_mortal = 1;
+    bool multiline = 0;
     MAGIC *mg = (MAGIC *) NULL;
 
 #ifdef DEBUGGING
@@ -4530,14 +4488,14 @@ PP(pp_split)
        }
        else {
            if (!AvREAL(ary)) {
+               I32 i;
                AvREAL_on(ary);
                AvREIFY_off(ary);
                for (i = AvFILLp(ary); i >= 0; i--)
                    AvARRAY(ary)[i] = &PL_sv_undef;     /* don't free mere refs */
            }
            /* temporarily switch stacks */
-           SWITCHSTACK(PL_curstack, ary);
-           PL_curstackinfo->si_stack = ary;
+           SAVESWITCHSTACK(PL_curstack, ary);
            make_mortal = 0;
        }
     }
@@ -4553,9 +4511,8 @@ PP(pp_split)
                s++;
        }
     }
-    if ((pm->op_pmflags & PMf_MULTILINE) != PL_multiline) {
-       SAVEINT(PL_multiline);
-       PL_multiline = pm->op_pmflags & PMf_MULTILINE;
+    if (pm->op_pmflags & PMf_MULTILINE) {
+       multiline = 1;
     }
 
     if (!limit)
@@ -4570,8 +4527,7 @@ PP(pp_split)
            if (m >= strend)
                break;
 
-           dstr = NEWSV(30, m-s);
-           sv_setpvn(dstr, s, m-s);
+           dstr = newSVpvn(s, m-s);
            if (make_mortal)
                sv_2mortal(dstr);
            if (do_utf8)
@@ -4585,15 +4541,14 @@ PP(pp_split)
                ++s;
        }
     }
-    else if (strEQ("^", rx->precomp)) {
+    else if (rx->precomp[0] == '^' && rx->precomp[1] == '\0') {
        while (--limit) {
-           /*SUPPRESS 530*/
-           for (m = s; m < strend && *m != '\n'; m++) ;
+           for (m = s; m < strend && *m != '\n'; m++)
+               ;
            m++;
            if (m >= strend)
                break;
-           dstr = NEWSV(30, m-s);
-           sv_setpvn(dstr, s, m-s);
+           dstr = newSVpvn(s, m-s);
            if (make_mortal)
                sv_2mortal(dstr);
            if (do_utf8)
@@ -4606,20 +4561,18 @@ PP(pp_split)
             (rx->reganch & RE_USE_INTUIT) && !rx->nparens
             && (rx->reganch & ROPT_CHECK_ALL)
             && !(rx->reganch & ROPT_ANCH)) {
-       int tail = (rx->reganch & RE_INTUIT_TAIL);
-       SV *csv = CALLREG_INTUIT_STRING(aTHX_ rx);
+       const int tail = (rx->reganch & RE_INTUIT_TAIL);
+       SV * const csv = CALLREG_INTUIT_STRING(aTHX_ rx);
 
        len = rx->minlen;
        if (len == 1 && !(rx->reganch & ROPT_UTF8) && !tail) {
-           STRLEN n_a;
-           char c = *SvPV(csv, n_a);
+           const char c = *SvPV_nolen_const(csv);
            while (--limit) {
-               /*SUPPRESS 530*/
-               for (m = s; m < strend && *m != c; m++) ;
+               for (m = s; m < strend && *m != c; m++)
+                   ;
                if (m >= strend)
                    break;
-               dstr = NEWSV(30, m-s);
-               sv_setpvn(dstr, s, m-s);
+               dstr = newSVpvn(s, m-s);
                if (make_mortal)
                    sv_2mortal(dstr);
                if (do_utf8)
@@ -4634,14 +4587,11 @@ PP(pp_split)
            }
        }
        else {
-#ifndef lint
            while (s < strend && --limit &&
              (m = fbm_instr((unsigned char*)s, (unsigned char*)strend,
-                            csv, PL_multiline ? FBMrf_MULTILINE : 0)) )
-#endif
+                            csv, multiline ? FBMrf_MULTILINE : 0)) )
            {
-               dstr = NEWSV(31, m-s);
-               sv_setpvn(dstr, s, m-s);
+               dstr = newSVpvn(s, m-s);
                if (make_mortal)
                    sv_2mortal(dstr);
                if (do_utf8)
@@ -4658,13 +4608,15 @@ PP(pp_split)
     }
     else {
        maxiters += slen * rx->nparens;
-       while (s < strend && --limit
-/*            && (!rx->check_substr
-                  || ((s = CALLREG_INTUIT_START(aTHX_ rx, sv, s, strend,
-                                                0, NULL))))
-*/            && CALLREGEXEC(aTHX_ rx, s, strend, orig,
-                             1 /* minend */, sv, NULL, 0))
+       while (s < strend && --limit)
        {
+           I32 rex_return;
+           PUTBACK;
+           rex_return = CALLREGEXEC(aTHX_ rx, (char*)s, (char*)strend, (char*)orig, 1 ,
+                           sv, NULL, 0);
+           SPAGAIN;
+           if (rex_return == 0)
+               break;
            TAINT_IF(RX_MATCH_TAINTED(rx));
            if (RX_MATCH_COPIED(rx) && rx->subbeg != orig) {
                m = s;
@@ -4674,14 +4626,14 @@ PP(pp_split)
                strend = s + (strend - m);
            }
            m = rx->startp[0] + orig;
-           dstr = NEWSV(32, m-s);
-           sv_setpvn(dstr, s, m-s);
+           dstr = newSVpvn(s, m-s);
            if (make_mortal)
                sv_2mortal(dstr);
            if (do_utf8)
                (void)SvUTF8_on(dstr);
            XPUSHs(dstr);
            if (rx->nparens) {
+               I32 i;
                for (i = 1; i <= (I32)rx->nparens; i++) {
                    s = rx->startp[i] + orig;
                    m = rx->endp[i] + orig;
@@ -4690,8 +4642,7 @@ PP(pp_split)
                       parens that didn't match -- they should be set to
                       undef, not the empty string */
                    if (m >= orig && s >= orig) {
-                       dstr = NEWSV(33, m-s);
-                       sv_setpvn(dstr, s, m-s);
+                       dstr = newSVpvn(s, m-s);
                    }
                    else
                        dstr = &PL_sv_undef;  /* undef, not "" */
@@ -4703,20 +4654,17 @@ PP(pp_split)
                }
            }
            s = rx->endp[0] + orig;
-           PUTBACK;
        }
     }
 
-    LEAVE_SCOPE(oldsave);
     iters = (SP - PL_stack_base) - base;
     if (iters > maxiters)
        DIE(aTHX_ "Split loop");
 
     /* keep field after final delim? */
     if (s < strend || (iters && origlimit)) {
-        STRLEN l = strend - s;
-       dstr = NEWSV(34, l);
-       sv_setpvn(dstr, s, l);
+        const STRLEN l = strend - s;
+       dstr = newSVpvn(s, l);
        if (make_mortal)
            sv_2mortal(dstr);
        if (do_utf8)
@@ -4729,14 +4677,15 @@ PP(pp_split)
            if (TOPs && !make_mortal)
                sv_2mortal(TOPs);
            iters--;
-           SP--;
+           *SP-- = &PL_sv_undef;
        }
     }
 
+    PUTBACK;
+    LEAVE_SCOPE(oldsave); /* may undo an earlier SWITCHSTACK */
+    SPAGAIN;
     if (realarray) {
        if (!mg) {
-           SWITCHSTACK(ary, oldstack);
-           PL_curstackinfo->si_stack = oldstack;
            if (SvSMAGICAL(ary)) {
                PUTBACK;
                mg_set((SV*)ary);
@@ -4756,6 +4705,7 @@ PP(pp_split)
            LEAVE;
            SPAGAIN;
            if (gimme == G_ARRAY) {
+               I32 i;
                /* EXTEND should not be needed - we just popped them */
                EXTEND(SP, iters);
                for (i=0; i < iters; i++) {
@@ -4790,7 +4740,19 @@ PP(pp_lock)
     RETURN;
 }
 
-PP(pp_threadsv)
+
+PP(unimplemented_op)
 {
-    DIE(aTHX_ "tried to access per-thread data in non-threaded perl");
+    DIE(aTHX_ "panic: unimplemented op %s (#%d) called", OP_NAME(PL_op),
+       PL_op->op_type);
 }
+
+/*
+ * Local variables:
+ * c-indentation-style: bsd
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ *
+ * ex: set ts=8 sts=4 sw=4 noet:
+ */