Stop "Possible use before definition" warning following change 24997
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index d68b689..e2649d3 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -1,6 +1,7 @@
 /*    pp.c
  *
- *    Copyright (c) 1991-2001, Larry Wall
+ *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ *    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"
+#include "keywords.h"
 
-/*
- * The compiler on Concurrent CX/UX systems has a subtle bug which only
- * seems to show up when compiling pp.c - it generates the wrong double
- * precision constant value for (double)UV_MAX when used inline in the body
- * of the code below, so this makes a static variable up front (which the
- * compiler seems to get correct) and uses it in place of UV_MAX below.
- */
-#ifdef CXUX_BROKEN_CONSTANT_CONVERT
-static double UV_MAX_cxux = ((double)UV_MAX);
-#endif
-
-/*
- * Offset for integer pack/unpack.
- *
- * On architectures where I16 and I32 aren't really 16 and 32 bits,
- * which for now are all Crays, pack and unpack have to play games.
- */
-
-/*
- * These values are required for portability of pack() output.
- * If they're not right on your machine, then pack() and unpack()
- * wouldn't work right anyway; you'll need to apply the Cray hack.
- * (I'd like to check them with #if, but you can't use sizeof() in
- * the preprocessor.)  --???
- */
-/*
-    The appropriate SHORTSIZE, INTSIZE, LONGSIZE, and LONGLONGSIZE
-    defines are now in config.h.  --Andy Dougherty  April 1998
- */
-#define SIZE16 2
-#define SIZE32 4
-
-/* CROSSCOMPILE and MULTIARCH are going to affect pp_pack() and pp_unpack().
-   --jhi Feb 1999 */
-
-#if SHORTSIZE != SIZE16 || LONGSIZE != SIZE32
-#   define PERL_NATINT_PACK
-#endif
-
-#if LONGSIZE > 4 && defined(_CRAY)
-#  if BYTEORDER == 0x12345678
-#    define OFF16(p)   (char*)(p)
-#    define OFF32(p)   (char*)(p)
-#  else
-#    if BYTEORDER == 0x87654321
-#      define OFF16(p) ((char*)(p) + (sizeof(U16) - SIZE16))
-#      define OFF32(p) ((char*)(p) + (sizeof(U32) - SIZE32))
-#    else
-       }}}} bad cray byte order
-#    endif
-#  endif
-#  define COPY16(s,p)  (*(p) = 0, Copy(s, OFF16(p), SIZE16, char))
-#  define COPY32(s,p)  (*(p) = 0, Copy(s, OFF32(p), SIZE32, char))
-#  define COPYNN(s,p,n) (*(p) = 0, Copy(s, (char *)(p), n, char))
-#  define CAT16(sv,p)  sv_catpvn(sv, OFF16(p), SIZE16)
-#  define CAT32(sv,p)  sv_catpvn(sv, OFF32(p), SIZE32)
-#else
-#  define COPY16(s,p)  Copy(s, p, SIZE16, char)
-#  define COPY32(s,p)  Copy(s, p, SIZE32, char)
-#  define COPYNN(s,p,n) Copy(s, (char *)(p), n, char)
-#  define CAT16(sv,p)  sv_catpvn(sv, (char*)(p), SIZE16)
-#  define CAT32(sv,p)  sv_catpvn(sv, (char*)(p), SIZE32)
-#endif
-
-/* variations on pp_null */
+#include "reentr.h"
 
 /* XXX I can't imagine anyone who doesn't have this actually _needs_
    it, since pid_t is an integral type.
@@ -90,6 +35,16 @@ static double UV_MAX_cxux = ((double)UV_MAX);
 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)
 {
     dSP;
@@ -108,8 +63,9 @@ PP(pp_scalar)
 PP(pp_padav)
 {
     dSP; dTARGET;
+    I32 gimme;
     if (PL_op->op_private & OPpLVAL_INTRO)
-       SAVECLEARSV(PL_curpad[PL_op->op_targ]);
+       SAVECLEARSV(PAD_SVl(PL_op->op_targ));
     EXTEND(SP, 1);
     if (PL_op->op_flags & OPf_REF) {
        PUSHs(TARG);
@@ -120,13 +76,14 @@ PP(pp_padav)
        PUSHs(TARG);
        RETURN;
     }
-    if (GIMME == G_ARRAY) {
-       I32 maxarg = AvFILL((AV*)TARG) + 1;
+    gimme = GIMME_V;
+    if (gimme == G_ARRAY) {
+       const I32 maxarg = AvFILL((AV*)TARG) + 1;
        EXTEND(SP, maxarg);
        if (SvMAGICAL(TARG)) {
            U32 i;
-           for (i=0; i < maxarg; i++) {
-               SV **svp = av_fetch((AV*)TARG, i, FALSE);
+           for (i=0; i < (U32)maxarg; i++) {
+               SV ** const svp = av_fetch((AV*)TARG, i, FALSE);
                SP[i+1] = (svp) ? *svp : &PL_sv_undef;
            }
        }
@@ -135,9 +92,9 @@ PP(pp_padav)
        }
        SP += maxarg;
     }
-    else {
-       SV* sv = sv_newmortal();
-       I32 maxarg = AvFILL((AV*)TARG) + 1;
+    else if (gimme == G_SCALAR) {
+       SV* const sv = sv_newmortal();
+       const I32 maxarg = AvFILL((AV*)TARG) + 1;
        sv_setiv(sv, maxarg);
        PUSHs(sv);
     }
@@ -151,7 +108,7 @@ PP(pp_padhv)
 
     XPUSHs(TARG);
     if (PL_op->op_private & OPpLVAL_INTRO)
-       SAVECLEARSV(PL_curpad[PL_op->op_targ]);
+       SAVECLEARSV(PAD_SVl(PL_op->op_targ));
     if (PL_op->op_flags & OPf_REF)
        RETURN;
     else if (LVRET) {
@@ -164,12 +121,7 @@ PP(pp_padhv)
        RETURNOP(do_kv());
     }
     else if (gimme == G_SCALAR) {
-       SV* sv = sv_newmortal();
-       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;
@@ -192,7 +144,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);
@@ -203,9 +155,6 @@ PP(pp_rv2gv)
     }
     else {
        if (SvTYPE(sv) != SVt_PVGV) {
-           char *sym;
-           STRLEN len;
-
            if (SvGMAGICAL(sv)) {
                mg_get(sv);
                if (SvROK(sv))
@@ -215,23 +164,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 = PL_curpad[cUNOP->op_targ];
-                       name = SvPV(namesv, len);
+                       SV *namesv = PAD_SV(cUNOP->op_targ);
+                       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;
@@ -240,25 +195,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);
            }
        }
     }
@@ -270,6 +224,7 @@ PP(pp_rv2gv)
 
 PP(pp_rv2sv)
 {
+    GV *gv = Nullgv;
     dSP; dTOPss;
 
     if (SvROK(sv)) {
@@ -285,9 +240,7 @@ PP(pp_rv2sv)
        }
     }
     else {
-       GV *gv = (GV*)sv;
-       char *sym;
-       STRLEN len;
+       gv = (GV*)sv;
 
        if (SvTYPE(gv) != SVt_PVGV) {
            if (SvGMAGICAL(sv)) {
@@ -300,32 +253,37 @@ 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);
     }
     if (PL_op->op_flags & OPf_MOD) {
-       if (PL_op->op_private & OPpLVAL_INTRO)
-           sv = save_scalar((GV*)TOPs);
+       if (PL_op->op_private & OPpLVAL_INTRO) {
+           if (cUNOP->op_first->op_type == OP_NULL)
+               sv = save_scalar((GV*)TOPs);
+           else if (gv)
+               sv = save_scalar(gv);
+           else
+               Perl_croak(aTHX_ PL_no_localize_ref);
+       }
        else if (PL_op->op_private & OPpDEREF)
            vivify_ref(sv, PL_op->op_private & OPpDEREF);
     }
@@ -336,14 +294,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, '#', 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;
 }
 
@@ -354,7 +312,7 @@ PP(pp_pos)
     if (PL_op->op_flags & OPf_MOD || LVRET) {
        if (SvTYPE(TARG) < SVt_PVLV) {
            sv_upgrade(TARG, SVt_PVLV);
-           sv_magic(TARG, Nullsv, '.', Nullch, 0);
+           sv_magic(TARG, Nullsv, PERL_MAGIC_pos, Nullch, 0);
        }
 
        LvTYPE(TARG) = '.';
@@ -367,10 +325,8 @@ PP(pp_pos)
        RETURN;
     }
     else {
-       MAGIC* mg;
-
        if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-           mg = mg_find(sv, 'g');
+           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))
@@ -418,17 +374,18 @@ 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
+                       || code == -KEY_exec || code == -KEY_system)
+                   goto set;
                while (i < MAXO) {      /* The slow way. */
                    if (strEQ(s + 6, PL_op_name[i])
                        || strEQ(s + 6, PL_op_desc[i]))
@@ -445,8 +402,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) */
@@ -470,7 +425,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;
@@ -479,7 +434,7 @@ PP(pp_prototype)
 PP(pp_anoncode)
 {
     dSP;
-    CV* cv = (CV*)PL_curpad[PL_op->op_targ];
+    CV* cv = (CV*)PAD_SV(PL_op->op_targ);
     if (CvCLONE(cv))
        cv = (CV*)sv_2mortal((SV*)cv_clone(cv));
     EXTEND(SP,1);
@@ -531,15 +486,15 @@ S_refto(pTHX_ SV *sv)
        SvTEMP_off(sv);
        (void)SvREFCNT_inc(sv);
     }
-    else if (SvPADTMP(sv))
-       sv = newSVsv(sv);
+    else if (SvPADTMP(sv) && !IS_PADGV(sv))
+        sv = newSVsv(sv);
     else {
        SvTEMP_off(sv);
        (void)SvREFCNT_inc(sv);
     }
     rv = sv_newmortal();
     sv_upgrade(rv, SVt_RV);
-    SvRV(rv) = sv;
+    SvRV_set(rv, sv);
     SvROK_on(rv);
     return rv;
 }
@@ -547,10 +502,8 @@ S_refto(pTHX_ SV *sv)
 PP(pp_ref)
 {
     dSP; dTARGET;
-    SV *sv;
-    char *pv;
-
-    sv = POPs;
+    const char *pv;
+    SV * const sv = POPs;
 
     if (sv && SvGMAGICAL(sv))
        mg_get(sv);
@@ -558,8 +511,7 @@ PP(pp_ref)
     if (!sv || !SvROK(sv))
        RETPUSHNO;
 
-    sv = SvRV(sv);
-    pv = sv_reftype(sv,TRUE);
+    pv = sv_reftype(SvRV(sv),TRUE);
     PUSHp(pv, strlen(pv));
     RETURN;
 }
@@ -572,15 +524,15 @@ 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);
+       ptr = SvPV_const(ssv,len);
        if (ckWARN(WARN_MISC) && len == 0)
-           Perl_warner(aTHX_ WARN_MISC,
+           Perl_warner(aTHX_ packWARN(WARN_MISC),
                   "Explicit blessing to '' (assuming package main)");
        stash = gv_stashpvn(ptr, len, TRUE);
     }
@@ -591,59 +543,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")) /* XXX deprecate in 5.005 */
-           tmpRef = (SV*)GvIOp(gv);
-       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"))
-           sv = newSVpv(HvNAME(GvSTASH(gv)), 0);
-       break;
-    case 'S':
-       if (strEQ(elem, "SCALAR"))
-           tmpRef = GvSV(gv);
-       break;
+    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;
+       }
     }
     if (tmpRef)
        sv = newRV(tmpRef);
@@ -706,7 +662,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
@@ -715,7 +671,8 @@ PP(pp_study)
     }
 
     SvSCREAM_on(sv);
-    sv_magic(sv, Nullsv, 'g', Nullch, 0);      /* piggyback on m//g magic */
+    /* piggyback on m//g magic */
+    sv_magic(sv, Nullsv, PERL_MAGIC_regex_global, Nullch, 0);
     RETPUSHYES;
 }
 
@@ -726,6 +683,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);
@@ -776,18 +735,19 @@ PP(pp_chomp)
 PP(pp_defined)
 {
     dSP;
-    register SV* sv;
+    register SV* const sv = POPs;
 
-    sv = POPs;
     if (!sv || !SvANY(sv))
        RETPUSHNO;
     switch (SvTYPE(sv)) {
     case SVt_PVAV:
-       if (AvMAX(sv) >= 0 || SvGMAGICAL(sv) || (SvRMAGICAL(sv) && mg_find(sv,'P')))
+       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,'P')))
+       if (HvARRAY(sv) || SvGMAGICAL(sv)
+               || (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
            RETPUSHYES;
        break;
     case SVt_PVCV:
@@ -817,8 +777,7 @@ PP(pp_undef)
     if (!sv)
        RETPUSHUNDEF;
 
-    if (SvTHINKFIRST(sv))
-       sv_force_normal(sv);
+    SV_CHECK_THINKFIRST_COW_DROP(sv);
 
     switch (SvTYPE(sv)) {
     case SVt_NULL:
@@ -831,7 +790,7 @@ PP(pp_undef)
        break;
     case SVt_PVCV:
        if (ckWARN(WARN_MISC) && cv_const_sv((CV*)sv))
-           Perl_warner(aTHX_ WARN_MISC, "Constant subroutine %s undefined",
+           Perl_warner(aTHX_ packWARN(WARN_MISC), "Constant subroutine %s undefined",
                 CvANON((CV*)sv) ? "(anonymous)" : GvENAME(CvGV((CV*)sv)));
        /* FALL THROUGH */
     case SVt_PVFM:
@@ -857,13 +816,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);
     }
 
@@ -873,12 +831,12 @@ PP(pp_undef)
 PP(pp_predec)
 {
     dSP;
-    if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
+    if (SvTYPE(TOPs) >= SVt_PVGV && SvTYPE(TOPs) != SVt_PVLV)
        DIE(aTHX_ PL_no_modify);
-    if (SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
-       SvIVX(TOPs) != IV_MIN)
+    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
@@ -890,18 +848,19 @@ PP(pp_predec)
 PP(pp_postinc)
 {
     dSP; dTARGET;
-    if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
+    if (SvTYPE(TOPs) >= SVt_PVGV && SvTYPE(TOPs) != SVt_PVLV)
        DIE(aTHX_ PL_no_modify);
     sv_setsv(TARG, TOPs);
-    if (SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
-       SvIVX(TOPs) != IV_MAX)
+    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
        sv_inc(TOPs);
     SvSETMAGIC(TOPs);
+    /* special case for undef: see thread at 2003-03/msg00536.html in archive */
     if (!SvOK(TARG))
        sv_setiv(TARG, 0);
     SETs(TARG);
@@ -911,13 +870,13 @@ PP(pp_postinc)
 PP(pp_postdec)
 {
     dSP; dTARGET;
-    if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
+    if (SvTYPE(TOPs) >= SVt_PVGV && SvTYPE(TOPs) != SVt_PVLV)
        DIE(aTHX_ PL_no_modify);
     sv_setsv(TARG, TOPs);
-    if (SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
-       SvIVX(TOPs) != IV_MIN)
+    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
@@ -931,11 +890,134 @@ PP(pp_postdec)
 
 PP(pp_pow)
 {
-    dSP; dATARGET; tryAMAGICbin(pow,opASSIGN);
+    dSP; dATARGET;
+#ifdef PERL_PRESERVE_IVUV
+    bool is_int = 0;
+#endif
+    tryAMAGICbin(pow,opASSIGN);
+#ifdef PERL_PRESERVE_IVUV
+    /* For integer to integer power, we do the calculation by hand wherever
+       we're sure it is safe; otherwise we call pow() and try to convert to
+       integer afterwards. */
     {
-      dPOPTOPnnrl;
-      SETn( Perl_pow( left, right) );
-      RETURN;
+        SvIV_please(TOPm1s);
+        if (SvIOK(TOPm1s)) {
+            bool baseuok = SvUOK(TOPm1s);
+            UV baseuv;
+
+            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 */
+                }
+            }
+            SvIV_please(TOPs);
+            if (SvIOK(TOPs)) {
+                UV power;
+
+                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.  */
+                    }
+                }
+                /* now we have integer ** positive integer. */
+                is_int = 1;
+
+                /* foo & (foo - 1) is zero only for a power of 2.  */
+                if (!(baseuv & (baseuv - 1))) {
+                    /* We are raising power-of-2 to a positive integer.
+                       The logic here will work for any base (even non-integer
+                       bases) but it can be less accurate than
+                       pow (base,power) or exp (power * log (base)) when the
+                       intermediate values start to spill out of the mantissa.
+                       With powers of 2 we know this can't happen.
+                       And powers of 2 are the favourite thing for perl
+                       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.  */
+                       const 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;
+                        }
+                    }
+                    SP--;
+                    SETn( result );
+                    SvIV_please(TOPs);
+                    RETURN;
+               } else {
+                   register unsigned int highbit = 8 * sizeof(UV);
+                   register unsigned int lowbit = 0;
+                   register unsigned int diff;
+                   bool odd_power = (bool)(power & 1);
+                   while ((diff = (highbit - lowbit) >> 1)) {
+                       if (baseuv & ~((1 << (lowbit + diff)) - 1))
+                           lowbit += diff;
+                       else 
+                           highbit -= diff;
+                   }
+                   /* we now have baseuv < 2 ** highbit */
+                   if (power * highbit <= 8 * sizeof(UV)) {
+                       /* result will definitely fit in UV, so use UV math
+                          on same algorithm as above */
+                       register UV result = 1;
+                       register UV base = baseuv;
+                       register int n = 0;
+                       for (; power; base *= base, n++) {
+                           register const UV bit = (UV)1 << (UV)n;
+                           if (power & bit) {
+                               result *= base;
+                               power -= bit;
+                               if (power == 0) break;
+                           }
+                       }
+                       SP--;
+                       if (baseuok || !odd_power)
+                           /* answer is positive */
+                           SETu( result );
+                       else if (result <= (UV)IV_MAX)
+                           /* answer negative, fits in IV */
+                           SETi( -(IV)result );
+                       else if (result == (UV)IV_MIN) 
+                           /* 2's complement assumption: special case IV_MIN */
+                           SETi( IV_MIN );
+                       else
+                           /* answer negative, doesn't fit */
+                           SETn( -(NV)result );
+                       RETURN;
+                   } 
+               }
+           }
+       }
+    }
+  float_it:
+#endif    
+    {
+       dPOPTOPnnrl;
+       SETn( Perl_pow( left, right) );
+#ifdef PERL_PRESERVE_IVUV
+       if (is_int)
+           SvIV_please(TOPs);
+#endif
+       RETURN;
     }
 }
 
@@ -963,7 +1045,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 */
@@ -974,7 +1056,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 */
@@ -1004,7 +1086,7 @@ PP(pp_multiply)
                    /* 2s complement assumption that (UV)-IV_MIN is correct.  */
                    /* -ve result, which could overflow an IV  */
                    SP--;
-                   SETi( -product );
+                   SETi( -(IV)product );
                    RETURN;
                } /* else drop to NVs below. */
            } else {
@@ -1041,7 +1123,7 @@ PP(pp_multiply)
                            /* 2s complement assumption again  */
                            /* -ve result, which could overflow an IV  */
                            SP--;
-                           SETi( -product_low );
+                           SETi( -(IV)product_low );
                            RETURN;
                        } /* else drop to NVs below. */
                    }
@@ -1060,29 +1142,115 @@ PP(pp_multiply)
 PP(pp_divide)
 {
     dSP; dATARGET; tryAMAGICbin(div,opASSIGN);
-    {
-      dPOPPOPnnrl;
-      NV value;
-      if (right == 0.0)
-       DIE(aTHX_ "Illegal division by zero");
+    /* Only try to do UV divide first
+       if ((SLOPPYDIVIDE is true) or
+           (PERL_PRESERVE_IVUV is true and one or both SV is a UV too large
+            to preserve))
+       The assumption is that it is better to use floating point divide
+       whenever possible, only doing integer divide first if we can't be sure.
+       If NV_PRESERVES_UV is true then we know at compile time that no UV
+       can be too large to preserve, so don't need to compile the code to
+       test the size of UVs.  */
+
 #ifdef SLOPPYDIVIDE
-      /* insure that 20./5. == 4. */
-      {
-       IV k;
-       if ((NV)I_V(left)  == left &&
-           (NV)I_V(right) == right &&
-           (k = I_V(left)/I_V(right))*I_V(right) == I_V(left)) {
-           value = k;
-       }
-       else {
-           value = left / right;
-       }
-      }
+#  define PERL_TRY_UV_DIVIDE
+    /* ensure that 20./5. == 4. */
 #else
-      value = left / right;
+#  ifdef PERL_PRESERVE_IVUV
+#    ifndef NV_PRESERVES_UV
+#      define PERL_TRY_UV_DIVIDE
+#    endif
+#  endif
 #endif
-      PUSHn( value );
-      RETURN;
+
+#ifdef PERL_TRY_UV_DIVIDE
+    SvIV_please(TOPs);
+    if (SvIOK(TOPs)) {
+        SvIV_please(TOPm1s);
+        if (SvIOK(TOPm1s)) {
+            bool left_non_neg = SvUOK(TOPm1s);
+            bool right_non_neg = SvUOK(TOPs);
+            UV left;
+            UV right;
+
+            if (right_non_neg) {
+                right = SvUVX(TOPs);
+            }
+           else {
+               const IV biv = SvIVX(TOPs);
+                if (biv >= 0) {
+                    right = biv;
+                    right_non_neg = TRUE; /* effectively it's a UV now */
+                }
+               else {
+                    right = -biv;
+                }
+            }
+            /* historically undef()/0 gives a "Use of uninitialized value"
+               warning before dieing, hence this test goes here.
+               If it were immediately before the second SvIV_please, then
+               DIE() would be invoked before left was even inspected, so
+               no inpsection would give no warning.  */
+            if (right == 0)
+                DIE(aTHX_ "Illegal division by zero");
+
+            if (left_non_neg) {
+                left = SvUVX(TOPm1s);
+            }
+           else {
+               const IV aiv = SvIVX(TOPm1s);
+                if (aiv >= 0) {
+                    left = aiv;
+                    left_non_neg = TRUE; /* effectively it's a UV now */
+                }
+               else {
+                    left = -aiv;
+                }
+            }
+
+            if (left >= right
+#ifdef SLOPPYDIVIDE
+                /* For sloppy divide we always attempt integer division.  */
+#else
+                /* Otherwise we only attempt it if either or both operands
+                   would not be preserved by an NV.  If both fit in NVs
+                   we fall through to the NV divide code below.  However,
+                   as left >= right to ensure integer result here, we know that
+                   we can skip the test on the right operand - right big
+                   enough not to be preserved can't get here unless left is
+                   also too big.  */
+
+                && (left > ((UV)1 << NV_PRESERVES_UV_BITS))
+#endif
+                ) {
+                /* Integer division can't overflow, but it can be imprecise.  */
+               const UV result = left / right;
+                if (result * right == left) {
+                    SP--; /* result is valid */
+                    if (left_non_neg == right_non_neg) {
+                        /* signs identical, result is positive.  */
+                        SETu( result );
+                        RETURN;
+                    }
+                    /* 2s complement assumption */
+                    if (result <= (UV)IV_MIN)
+                        SETi( -(IV)result );
+                    else {
+                        /* It's exact but too negative for IV. */
+                        SETn( -(NV)result );
+                    }
+                    RETURN;
+                } /* tried integer divide but it was not an integer result */
+            } /* else (PERL_ABS(result) < 1.0) or (both UVs in range for NV) */
+        } /* left wasn't SvIOK */
+    } /* right wasn't SvIOK */
+#endif /* PERL_TRY_UV_DIVIDE */
+    {
+       dPOPPOPnnrl;
+       if (right == 0.0)
+           DIE(aTHX_ "Illegal division by zero");
+       PUSHn( left / right );
+       RETURN;
     }
 }
 
@@ -1090,66 +1258,95 @@ PP(pp_modulo)
 {
     dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
     {
-       UV left;
-       UV right;
-       bool left_neg;
-       bool right_neg;
-       bool use_double = 0;
-       NV dright;
-       NV dleft;
-
-       if (SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)) {
-           IV i = SvIVX(POPs);
-           right = (right_neg = (i < 0)) ? -i : i;
-       }
-       else {
+       UV left  = 0;
+       UV right = 0;
+       bool left_neg = FALSE;
+       bool right_neg = FALSE;
+       bool use_double = FALSE;
+       bool dright_valid = FALSE;
+       NV dright = 0.0;
+       NV dleft  = 0.0;
+
+        SvIV_please(TOPs);
+        if (SvIOK(TOPs)) {
+            right_neg = !SvUOK(TOPs);
+            if (!right_neg) {
+                right = SvUVX(POPs);
+            } else {
+               const IV biv = SvIVX(POPs);
+                if (biv >= 0) {
+                    right = biv;
+                    right_neg = FALSE; /* effectively it's a UV now */
+                } else {
+                    right = -biv;
+                }
+            }
+        }
+        else {
            dright = POPn;
-           use_double = 1;
            right_neg = dright < 0;
            if (right_neg)
                dright = -dright;
+            if (dright < UV_MAX_P1) {
+                right = U_V(dright);
+                dright_valid = TRUE; /* In case we need to use double below.  */
+            } else {
+                use_double = TRUE;
+            }
        }
 
-       if (!use_double && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)) {
-           IV i = SvIVX(POPs);
-           left = (left_neg = (i < 0)) ? -i : i;
-       }
+        /* At this point use_double is only true if right is out of range for
+           a UV.  In range NV has been rounded down to nearest UV and
+           use_double false.  */
+        SvIV_please(TOPs);
+       if (!use_double && SvIOK(TOPs)) {
+            if (SvIOK(TOPs)) {
+                left_neg = !SvUOK(TOPs);
+                if (!left_neg) {
+                    left = SvUVX(POPs);
+                } else {
+                    IV aiv = SvIVX(POPs);
+                    if (aiv >= 0) {
+                        left = aiv;
+                        left_neg = FALSE; /* effectively it's a UV now */
+                    } else {
+                        left = -aiv;
+                    }
+                }
+            }
+        }
        else {
            dleft = POPn;
-           if (!use_double) {
-               use_double = 1;
-               dright = right;
-           }
            left_neg = dleft < 0;
            if (left_neg)
                dleft = -dleft;
-       }
 
+            /* This should be exactly the 5.6 behaviour - if left and right are
+               both in range for UV then use U_V() rather than floor.  */
+           if (!use_double) {
+                if (dleft < UV_MAX_P1) {
+                    /* right was in range, so is dleft, so use UVs not double.
+                     */
+                    left = U_V(dleft);
+                }
+                /* left is out of range for UV, right was in range, so promote
+                   right (back) to double.  */
+                else {
+                    /* The +0.5 is used in 5.6 even though it is not strictly
+                       consistent with the implicit +0 floor in the U_V()
+                       inside the #if 1. */
+                    dleft = Perl_floor(dleft + 0.5);
+                    use_double = TRUE;
+                    if (dright_valid)
+                        dright = Perl_floor(dright + 0.5);
+                    else
+                        dright = right;
+                }
+            }
+        }
        if (use_double) {
            NV dans;
 
-#if 1
-/* Somehow U_V is pessimized even if CASTFLAGS is 0 */
-#  if CASTFLAGS & 2
-#    define CAST_D2UV(d) U_V(d)
-#  else
-#    define CAST_D2UV(d) ((UV)(d))
-#  endif
-           /* Tried to do this only in the case DOUBLESIZE <= UV_SIZE,
-            * or, in other words, precision of UV more than of NV.
-            * But in fact the approach below turned out to be an
-            * optimization - floor() may be slow */
-           if (dright <= UV_MAX && dleft <= UV_MAX) {
-               right = CAST_D2UV(dright);
-               left  = CAST_D2UV(dleft);
-               goto do_uv;
-           }
-#endif
-
-           /* Backward-compatibility clause: */
-           dright = Perl_floor(dright + 0.5);
-           dleft  = Perl_floor(dleft + 0.5);
-
            if (!dright)
                DIE(aTHX_ "Illegal modulus zero");
 
@@ -1163,7 +1360,6 @@ PP(pp_modulo)
        else {
            UV ans;
 
-       do_uv:
            if (!right)
                DIE(aTHX_ "Illegal modulus zero");
 
@@ -1190,18 +1386,76 @@ PP(pp_repeat)
 {
   dSP; dATARGET; tryAMAGICbin(repeat,opASSIGN);
   {
-    register IV count = POPi;
+    register IV count;
+    dPOPss;
+    if (SvGMAGICAL(sv))
+        mg_get(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) {
-               if (*SP)
-                   SvTEMP_off((*SP));
+#if 0
+             /* This code was intended to fix 20010809.028:
+
+                $x = 'abcd';
+                for (($x =~ /./g) x 2) {
+                    print chop; # "abcdabcd" expected as output.
+                }
+
+              * but that change (#11635) broke this code:
+
+              $x = [("foo")x2]; # only one "foo" ended up in the anonlist.
+
+              * I can't think of a better fix that doesn't introduce
+              * an efficiency hit by copying the SVs. The stack isn't
+              * refcounted, and mortalisation obviously doesn't
+              * Do The Right Thing when the stack has more than
+              * one pointer to the same mortal value.
+              * .robin.
+              */
+               if (*SP) {
+                   *SP = sv_2mortal(newSVsv(*SP));
+                   SvREADONLY_on(*SP);
+               }
+#else
+               if (*SP)
+                  SvTEMP_off((*SP));
+#endif
                SP--;
            }
            MARK++;
@@ -1216,6 +1470,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);
@@ -1224,9 +1480,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';
        }
@@ -1262,8 +1522,8 @@ PP(pp_subtract)
        /* Unless the left argument is integer in range we are going to have to
           use NV maths. Hence only attempt to coerce the right argument if
           we know the left is integer.  */
-       register UV auv;
-       bool auvok;
+       register UV auv = 0;
+       bool auvok = FALSE;
        bool a_valid = 0;
 
        if (!useleft) {
@@ -1277,7 +1537,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.  */
@@ -1297,7 +1557,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;
@@ -1305,7 +1565,7 @@ PP(pp_subtract)
                    buv = (UV)-biv;
            }
            /* ?uvok if value is >= 0. basically, flagged as UV if it's +ve,
-              else "IV" now, independant of how it came in.
+              else "IV" now, independent of how it came in.
               if a, b represents positive, A, B negative, a maps to -A etc
               a - b =>  (a - b)
               A - b => -(a + b)
@@ -1371,7 +1631,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);
@@ -1388,7 +1648,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);
@@ -1413,16 +1673,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));
@@ -1430,9 +1690,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 < */
@@ -1440,19 +1698,13 @@ PP(pp_lt)
                    RETURN;
                }
                auv = SvUVX(TOPs);
-               if (auv >= (UV) IV_MAX) {
-                   /* As (b) is an IV, it cannot be > IV_MAX */
-                   SETs(&PL_sv_no);
-                   RETURN;
-               }
                SETs(boolSV(auv < (UV)biv));
                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--;
@@ -1461,17 +1713,22 @@ PP(pp_lt)
                }
                buv = SvUVX(TOPs);
                SP--;
-               if (buv > (UV) IV_MAX) {
-                   /* As (a) is an IV, it cannot be > IV_MAX */
-                   SETs(&PL_sv_yes);
-                   RETURN;
-               }
                SETs(boolSV((UV)aiv < buv));
                RETURN;
            }
        }
     }
 #endif
+#ifndef NV_PRESERVES_UV
+#ifdef PERL_PRESERVE_IVUV
+    else
+#endif
+    if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
+       SP--;
+       SETs(boolSV(SvRV(TOPs) < SvRV(TOPp1s)));
+       RETURN;
+    }
+#endif
     {
       dPOPnv;
       SETs(boolSV(TOPn < value));
@@ -1491,16 +1748,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));
@@ -1508,9 +1765,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 > */
@@ -1518,19 +1774,13 @@ PP(pp_gt)
                    RETURN;
                }
                auv = SvUVX(TOPs);
-               if (auv > (UV) IV_MAX) {
-                   /* As (b) is an IV, it cannot be > IV_MAX */
-                   SETs(&PL_sv_yes);
-                   RETURN;
-               }
                SETs(boolSV(auv > (UV)biv));
                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--;
@@ -1539,17 +1789,22 @@ PP(pp_gt)
                }
                buv = SvUVX(TOPs);
                SP--;
-               if (buv >= (UV) IV_MAX) {
-                   /* As (a) is an IV, it cannot be > IV_MAX */
-                   SETs(&PL_sv_no);
-                   RETURN;
-               }
                SETs(boolSV((UV)aiv > buv));
                RETURN;
            }
        }
     }
 #endif
+#ifndef NV_PRESERVES_UV
+#ifdef PERL_PRESERVE_IVUV
+    else
+#endif
+    if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
+        SP--;
+        SETs(boolSV(SvRV(TOPs) > SvRV(TOPp1s)));
+        RETURN;
+    }
+#endif
     {
       dPOPnv;
       SETs(boolSV(TOPn > value));
@@ -1569,8 +1824,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));
@@ -1586,9 +1841,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 <= */
@@ -1596,19 +1850,13 @@ PP(pp_le)
                    RETURN;
                }
                auv = SvUVX(TOPs);
-               if (auv > (UV) IV_MAX) {
-                   /* As (b) is an IV, it cannot be > IV_MAX */
-                   SETs(&PL_sv_no);
-                   RETURN;
-               }
                SETs(boolSV(auv <= (UV)biv));
                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--;
@@ -1617,17 +1865,22 @@ PP(pp_le)
                }
                buv = SvUVX(TOPs);
                SP--;
-               if (buv >= (UV) IV_MAX) {
-                   /* As (a) is an IV, it cannot be > IV_MAX */
-                   SETs(&PL_sv_yes);
-                   RETURN;
-               }
                SETs(boolSV((UV)aiv <= buv));
                RETURN;
            }
        }
     }
 #endif
+#ifndef NV_PRESERVES_UV
+#ifdef PERL_PRESERVE_IVUV
+    else
+#endif
+    if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
+        SP--;
+        SETs(boolSV(SvRV(TOPs) <= SvRV(TOPp1s)));
+        RETURN;
+    }
+#endif
     {
       dPOPnv;
       SETs(boolSV(TOPn <= value));
@@ -1647,26 +1900,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 >= */
@@ -1674,19 +1926,13 @@ PP(pp_ge)
                    RETURN;
                }
                auv = SvUVX(TOPs);
-               if (auv >= (UV) IV_MAX) {
-                   /* As (b) is an IV, it cannot be > IV_MAX */
-                   SETs(&PL_sv_yes);
-                   RETURN;
-               }
                SETs(boolSV(auv >= (UV)biv));
                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--;
@@ -1695,17 +1941,22 @@ PP(pp_ge)
                }
                buv = SvUVX(TOPs);
                SP--;
-               if (buv > (UV) IV_MAX) {
-                   /* As (a) is an IV, it cannot be > IV_MAX */
-                   SETs(&PL_sv_no);
-                   RETURN;
-               }
                SETs(boolSV((UV)aiv >= buv));
                RETURN;
            }
        }
     }
 #endif
+#ifndef NV_PRESERVES_UV
+#ifdef PERL_PRESERVE_IVUV
+    else
+#endif
+    if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
+        SP--;
+        SETs(boolSV(SvRV(TOPs) >= SvRV(TOPp1s)));
+        RETURN;
+    }
+#endif
     {
       dPOPnv;
       SETs(boolSV(TOPn >= value));
@@ -1717,8 +1968,9 @@ PP(pp_ne)
 {
     dSP; tryAMAGICbinSET(ne,0);
 #ifndef NV_PRESERVES_UV
-    if (SvROK(TOPs) && SvROK(TOPm1s)) {
-       SETs(boolSV(SvRV(TOPs) != SvRV(TOPm1s)));
+    if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
+        SP--;
+       SETs(boolSV(SvRV(TOPs) != SvRV(TOPp1s)));
        RETURN;
     }
 #endif
@@ -1730,19 +1982,16 @@ PP(pp_ne)
            bool auvok = SvUOK(TOPm1s);
            bool buvok = SvUOK(TOPs);
        
-           if (!auvok && !buvok) { /* ## IV <=> IV ## */
-               IV aiv = SvIVX(TOPm1s);
-               IV biv = SvIVX(TOPs);
-               
-               SP--;
-               SETs(boolSV(aiv != biv));
-               RETURN;
-           }
-           if (auvok && buvok) { /* ## UV != UV ## */
-               UV auv = SvUVX(TOPm1s);
-               UV buv = SvUVX(TOPs);
-               
-               SP--;
+           if (auvok == buvok) { /* ## IV == IV or UV == UV ## */
+                /* Casting IV to UV before comparison isn't going to matter
+                   on 2s complement. On 1s complement or sign&magnitude
+                   (if we have any of them) it could make negative zero
+                   differ from normal zero. As I understand it. (Need to
+                   check - is negative zero implementation defined behaviour
+                   anyway?). NWC  */
+               const UV buv = SvUVX(POPs);
+               const UV auv = SvUVX(TOPs);
+
                SETs(boolSV(auv != buv));
                RETURN;
            }
@@ -1771,11 +2020,6 @@ PP(pp_ne)
                    }
                    uv = SvUVX(*(SP+1)); /* Do I want TOPp1s() ? */
                }
-               /* we know iv is >= 0 */
-               if (uv > (UV) IV_MAX) {
-                   SETs(&PL_sv_yes);
-                   RETURN;
-               }
                SETs(boolSV((UV)iv != uv));
                RETURN;
            }
@@ -1793,8 +2037,10 @@ PP(pp_ncmp)
 {
     dSP; dTARGET; tryAMAGICbin(ncmp,0);
 #ifndef NV_PRESERVES_UV
-    if (SvROK(TOPs) && SvROK(TOPm1s)) {
-       SETi(PTR2UV(SvRV(TOPs)) - PTR2UV(SvRV(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));
        RETURN;
     }
 #endif
@@ -1804,12 +2050,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;
@@ -1818,8 +2064,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;
@@ -1828,19 +2074,13 @@ 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);
-                   if (leftuv > (UV) IV_MAX) {
-                       /* As (b) is an IV, it cannot be > IV_MAX */
-                       value = 1;
-                   } else if (leftuv > (UV)rightiv) {
+                   const UV leftuv = SvUVX(TOPm1s);
+                   if (leftuv > (UV)rightiv) {
                        value = 1;
                    } else if (leftuv < (UV)rightiv) {
                        value = -1;
@@ -1849,21 +2089,15 @@ 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);
-                   if (rightuv > (UV) IV_MAX) {
-                       /* As (a) is an IV, it cannot be > IV_MAX */
-                       value = -1;
-                   } else if (leftiv > (UV)rightuv) {
+                   const UV rightuv = SvUVX(TOPs);
+                   if ((UV)leftiv > rightuv) {
                        value = 1;
-                   } else if (leftiv < (UV)rightuv) {
+                   } else if ((UV)leftiv < rightuv) {
                        value = -1;
                    } else {
                        value = 0;
@@ -1908,7 +2142,7 @@ PP(pp_slt)
     dSP; tryAMAGICbinSET(slt,0);
     {
       dPOPTOPssrl;
-      int cmp = ((PL_op->op_private & OPpLOCALE)
+      const int cmp = (IN_LOCALE_RUNTIME
                 ? sv_cmp_locale(left, right)
                 : sv_cmp(left, right));
       SETs(boolSV(cmp < 0));
@@ -1921,7 +2155,7 @@ PP(pp_sgt)
     dSP; tryAMAGICbinSET(sgt,0);
     {
       dPOPTOPssrl;
-      int cmp = ((PL_op->op_private & OPpLOCALE)
+      const int cmp = (IN_LOCALE_RUNTIME
                 ? sv_cmp_locale(left, right)
                 : sv_cmp(left, right));
       SETs(boolSV(cmp > 0));
@@ -1934,7 +2168,7 @@ PP(pp_sle)
     dSP; tryAMAGICbinSET(sle,0);
     {
       dPOPTOPssrl;
-      int cmp = ((PL_op->op_private & OPpLOCALE)
+      const int cmp = (IN_LOCALE_RUNTIME
                 ? sv_cmp_locale(left, right)
                 : sv_cmp(left, right));
       SETs(boolSV(cmp <= 0));
@@ -1947,7 +2181,7 @@ PP(pp_sge)
     dSP; tryAMAGICbinSET(sge,0);
     {
       dPOPTOPssrl;
-      int cmp = ((PL_op->op_private & OPpLOCALE)
+      const int cmp = (IN_LOCALE_RUNTIME
                 ? sv_cmp_locale(left, right)
                 : sv_cmp(left, right));
       SETs(boolSV(cmp >= 0));
@@ -1980,7 +2214,7 @@ PP(pp_scmp)
     dSP; dTARGET;  tryAMAGICbin(scmp,0);
     {
       dPOPTOPssrl;
-      int cmp = ((PL_op->op_private & OPpLOCALE)
+      const int cmp = (IN_LOCALE_RUNTIME
                 ? sv_cmp_locale(left, right)
                 : sv_cmp(left, right));
       SETi( cmp );
@@ -1993,13 +2227,15 @@ PP(pp_bit_and)
     dSP; dATARGET; tryAMAGICbin(band,opASSIGN);
     {
       dPOPTOPssrl;
+      if (SvGMAGICAL(left)) mg_get(left);
+      if (SvGMAGICAL(right)) mg_get(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);
        }
       }
@@ -2016,13 +2252,15 @@ PP(pp_bit_xor)
     dSP; dATARGET; tryAMAGICbin(bxor,opASSIGN);
     {
       dPOPTOPssrl;
+      if (SvGMAGICAL(left)) mg_get(left);
+      if (SvGMAGICAL(right)) mg_get(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);
        }
       }
@@ -2039,13 +2277,15 @@ PP(pp_bit_or)
     dSP; dATARGET; tryAMAGICbin(bor,opASSIGN);
     {
       dPOPTOPssrl;
+      if (SvGMAGICAL(left)) mg_get(left);
+      if (SvGMAGICAL(right)) mg_get(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);
        }
       }
@@ -2062,7 +2302,7 @@ PP(pp_negate)
     dSP; dTARGET; tryAMAGICun(neg);
     {
        dTOPss;
-       int flags = SvFLAGS(sv);
+       const int flags = SvFLAGS(sv);
        if (SvGMAGICAL(sv))
            mg_get(sv);
        if ((flags & SVf_IOK) || ((flags & (SVp_IOK | SVp_NOK)) == SVp_IOK)) {
@@ -2094,7 +2334,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);
@@ -2103,15 +2343,22 @@ PP(pp_negate)
                sv_setsv(TARG, sv);
                *SvPV_force(TARG, len) = *s == '-' ? '+' : '-';
            }
-           else if (DO_UTF8(sv) && UTF8_IS_START(*s) && isIDFIRST_utf8((U8*)s)) {
-               sv_setpvn(TARG, "-", 1);
-               sv_catsv(TARG, sv);
+           else if (DO_UTF8(sv)) {
+               SvIV_please(sv);
+               if (SvIOK(sv))
+                   goto oops_its_an_int;
+               if (SvNOK(sv))
+                   sv_setnv(TARG, -SvNV(sv));
+               else {
+                   sv_setpvn(TARG, "-", 1);
+                   sv_catsv(TARG, sv);
+               }
            }
            else {
-             SvIV_please(sv);
-             if (SvIOK(sv))
-               goto oops_its_an_int;
-             sv_setnv(TARG, -SvNV(sv));
+               SvIV_please(sv);
+               if (SvIOK(sv))
+                 goto oops_its_an_int;
+               sv_setnv(TARG, -SvNV(sv));
            }
            SETTARG;
        }
@@ -2133,13 +2380,15 @@ PP(pp_complement)
     dSP; dTARGET; tryAMAGICun(compl);
     {
       dTOPss;
+      if (SvGMAGICAL(sv))
+         mg_get(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);
        }
       }
@@ -2148,7 +2397,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)) {
@@ -2162,7 +2412,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++;
@@ -2176,9 +2426,9 @@ PP(pp_complement)
          if (nwide) {
              Newz(0, 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(result, ~c);
+                 result = uvchr_to_utf8_flags(result, ~c, UNICODE_ALLOW_ANY);
              }
              *result = '\0';
              result -= targlen;
@@ -2188,13 +2438,14 @@ PP(pp_complement)
          else {
              Newz(0, 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);
@@ -2245,16 +2496,76 @@ PP(pp_i_divide)
     }
 }
 
+STATIC
+PP(pp_i_modulo_0)
+{
+     /* This is the vanilla old i_modulo. */
+     dVAR; dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
+     {
+         dPOPTOPiirl;
+         if (!right)
+              DIE(aTHX_ "Illegal modulus zero");
+         SETi( left % right );
+         RETURN;
+     }
+}
+
+#if defined(__GLIBC__) && IVSIZE == 8
+STATIC
+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. */
+     dVAR; dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
+     {
+         dPOPTOPiirl;
+         if (!right)
+              DIE(aTHX_ "Illegal modulus zero");
+         SETi( left % PERL_ABS(right) );
+         RETURN;
+     }
+}
+#endif
+
 PP(pp_i_modulo)
 {
-    dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
-    {
-      dPOPTOPiirl;
-      if (!right)
-       DIE(aTHX_ "Illegal modulus zero");
-      SETi( left % right );
-      RETURN;
-    }
+     dVAR; dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
+     {
+         dPOPTOPiirl;
+         if (!right)
+              DIE(aTHX_ "Illegal modulus zero");
+         /* The assumption is to use hereafter the old vanilla version... */
+         PL_op->op_ppaddr =
+              PL_ppaddr[OP_I_MODULO] =
+                  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
+          * argument might be broken.  Test for this and re-patch the
+          * opcode dispatch table if that is the case, remembering to
+          * also apply the workaround so that this first round works
+          * right, too.  See [perl #9402] for more information. */
+#if defined(__GLIBC__) && IVSIZE == 8
+         {
+              IV l =   3;
+              IV r = -10;
+              /* Cannot do this check with inlined IV constants since
+               * that seems to work correctly even with the buggy glibc. */
+              if (l % r == -3) {
+                   /* Yikes, we have the bug.
+                    * Patch in the workaround version. */
+                   PL_op->op_ppaddr =
+                        PL_ppaddr[OP_I_MODULO] =
+                            &Perl_pp_i_modulo_1;
+                   /* Make certain we work right this time, too. */
+                   right = PERL_ABS(right);
+              }
+         }
+#endif
+         SETi( left % right );
+         RETURN;
+     }
 }
 
 PP(pp_i_add)
@@ -2378,10 +2689,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;
     }
 }
@@ -2390,10 +2699,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;
     }
 }
@@ -2446,87 +2753,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
-    gettimeofday(&when,(struct timezone *) 0);
-    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);
@@ -2543,14 +2769,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 %g", value);
+       DIE(aTHX_ "Can't take log of %"NVgf, value);
       }
-      value = Perl_log(value);
-      XPUSHn(value);
+      XPUSHn(Perl_log(value));
       RETURN;
     }
 }
@@ -2559,14 +2783,12 @@ 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 %g", value);
+       DIE(aTHX_ "Can't take sqrt of %"NVgf, value);
       }
-      value = Perl_sqrt(value);
-      XPUSHn(value);
+      XPUSHn(Perl_sqrt(value));
       RETURN;
     }
 }
@@ -2575,48 +2797,34 @@ 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(HAS_MODFL) || defined(LONG_DOUBLE_EQUALS_DOUBLE)
-                 (void)Perl_modf(value, &value);
-#else
-                 double tmp = (double)value;
-                 (void)Perl_modf(tmp, &tmp);
-                 value = (NV)tmp;
-#endif
-                 SETn(value);
+                 SETn(Perl_floor(value));
              }
          }
          else {
              if (value > (NV)IV_MIN - 0.5) {
                  SETi(I_V(value));
              } else {
-#if defined(HAS_MODFL) || defined(LONG_DOUBLE_EQUALS_DOUBLE)
-                 (void)Perl_modf(-value, &value);
-                 value = -value;
-#else
-                 double tmp = (double)value;
-                 (void)Perl_modf(-tmp, &tmp);
-                 value = -(NV)tmp;
-#endif
-                 SETn(value);
+                 SETn(Perl_ceil(value));
              }
          }
       }
@@ -2629,9 +2837,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 */
@@ -2649,49 +2859,84 @@ 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;
 }
 
+
 PP(pp_hex)
 {
     dSP; dTARGET;
-    char *tmps;
-    STRLEN argtype;
+    const char *tmps;
+    I32 flags = PERL_SCAN_ALLOW_UNDERSCORES;
     STRLEN len;
+    NV result_nv;
+    UV result_uv;
+    SV* const sv = POPs;
 
-    tmps = (SvPVx(POPs, len));
-    argtype = 1;               /* allow underscores */
-    XPUSHn(scan_hex(tmps, len, &argtype));
+    tmps = (SvPV_const(sv, len));
+    if (DO_UTF8(sv)) {
+        /* If Unicode, try to downgrade
+         * If not possible, croak. */
+        SV* const tsv = sv_2mortal(newSVsv(sv));
+       
+        SvUTF8_on(tsv);
+        sv_utf8_downgrade(tsv, FALSE);
+        tmps = SvPV_const(tsv, len);
+    }
+    result_uv = grok_hex (tmps, &len, &flags, &result_nv);
+    if (flags & PERL_SCAN_GREATER_THAN_UV_MAX) {
+        XPUSHn(result_nv);
+    }
+    else {
+        XPUSHu(result_uv);
+    }
     RETURN;
 }
 
 PP(pp_oct)
 {
     dSP; dTARGET;
-    NV value;
-    STRLEN argtype;
-    char *tmps;
+    const char *tmps;
+    I32 flags = PERL_SCAN_ALLOW_UNDERSCORES;
     STRLEN len;
+    NV result_nv;
+    UV result_uv;
+    SV* const sv = POPs;
 
-    tmps = (SvPVx(POPs, len));
+    tmps = (SvPV_const(sv, len));
+    if (DO_UTF8(sv)) {
+        /* If Unicode, try to downgrade
+         * If not possible, croak. */
+        SV* const tsv = sv_2mortal(newSVsv(sv));
+       
+        SvUTF8_on(tsv);
+        sv_utf8_downgrade(tsv, FALSE);
+        tmps = SvPV_const(tsv, len);
+    }
     while (*tmps && len && isSPACE(*tmps))
-       tmps++, len--;
+        tmps++, len--;
     if (*tmps == '0')
-       tmps++, len--;
-    argtype = 1;               /* allow underscores */
+        tmps++, len--;
     if (*tmps == 'x')
-       value = scan_hex(++tmps, --len, &argtype);
+        result_uv = grok_hex (tmps, &len, &flags, &result_nv);
     else if (*tmps == 'b')
-       value = scan_bin(++tmps, --len, &argtype);
+        result_uv = grok_bin (tmps, &len, &flags, &result_nv);
     else
-       value = scan_oct(tmps, len, &argtype);
-    XPUSHn(value);
+        result_uv = grok_oct (tmps, &len, &flags, &result_nv);
+
+    if (flags & PERL_SCAN_GREATER_THAN_UV_MAX) {
+        XPUSHn(result_nv);
+    }
+    else {
+        XPUSHu(result_uv);
+    }
     RETURN;
 }
 
@@ -2713,19 +2958,19 @@ PP(pp_substr)
 {
     dSP; dTARGET;
     SV *sv;
-    I32 len;
+    I32 len = 0;
     STRLEN curlen;
     STRLEN utf8_curlen;
     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;
 
@@ -2734,7 +2979,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;
@@ -2750,7 +2995,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)
@@ -2798,18 +3043,31 @@ PP(pp_substr)
        if (lvalue || repl)
            Perl_croak(aTHX_ "substr outside of string");
        if (ckWARN(WARN_SUBSTR))
-           Perl_warner(aTHX_ WARN_SUBSTR, "substr outside of string");
+           Perl_warner(aTHX_ packWARN(WARN_SUBSTR), "substr outside of string");
        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, 'o');
+       sv_unmagic(TARG, PERL_MAGIC_collxfrm);
 #endif
        if (utf8_curlen)
            SvUTF8_on(TARG);
@@ -2819,7 +3077,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);
@@ -2831,10 +3089,9 @@ 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_ WARN_SUBSTR,
+                       Perl_warner(aTHX_ packWARN(WARN_SUBSTR),
                                "Attempt to use reference as lvalue in substr");
                }
                if (SvOK(sv))           /* is it defined ? */
@@ -2845,8 +3102,10 @@ PP(pp_substr)
 
            if (SvTYPE(TARG) < SVt_PVLV) {
                sv_upgrade(TARG, SVt_PVLV);
-               sv_magic(TARG, Nullsv, 'x', Nullch, 0);
+               sv_magic(TARG, Nullsv, PERL_MAGIC_substr, Nullch, 0);
            }
+           else
+               SvOK_off(TARG);
 
            LvTYPE(TARG) = 'x';
            if (LvTARG(TARG) != sv) {
@@ -2866,16 +3125,18 @@ 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! */
+       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, 'v', Nullch, 0);
+           sv_magic(TARG, Nullsv, PERL_MAGIC_vec, Nullch, 0);
        }
        LvTYPE(TARG) = 'v';
        if (LvTARG(TARG) != src) {
@@ -2897,12 +3158,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;
@@ -2910,20 +3174,44 @@ 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 > biglen)
+    else if (offset > (I32)biglen)
        offset = biglen;
     if (!(tmps2 = fbm_instr((unsigned char*)tmps + offset,
       (unsigned char*)tmps + biglen, little, 0)))
        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;
 }
@@ -2933,38 +3221,66 @@ 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;
     }
     if (offset < 0)
        offset = 0;
-    else if (offset > blen)
+    else if (offset > (I32)blen)
        offset = blen;
     if (!(tmps2 = rninstr(tmps,  tmps  + offset,
                          tmps2, tmps2 + llen)))
        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;
 }
@@ -2974,6 +3290,8 @@ PP(pp_sprintf)
     dSP; dMARK; dORIGMARK; dTARGET;
     do_sprintf(TARG, SP-MARK, MARK+1);
     TAINT_IF(SvTAINTED(TARG));
+    if (DO_UTF8(*(MARK+1)))
+       SvUTF8_on(TARG);
     SP = ORIGMARK;
     PUSHTARG;
     RETURN;
@@ -2984,9 +3302,19 @@ 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)) {
+        tmpsv = sv_2mortal(newSVsv(argsv));
+        s = (U8*)sv_recode_to_utf8(tmpsv, PL_encoding);
+        argsv = tmpsv;
+    }
+
+    XPUSHu(DO_UTF8(argsv) ?
+          utf8n_to_uvchr(s, UTF8_MAXBYTES, 0, UTF8_ALLOW_ANYUV) :
+          (*s & 0xff));
 
-    XPUSHu(DO_UTF8(argsv) ? utf8_to_uvchr(s, 0) : (*s & 0xff));
     RETURN;
 }
 
@@ -2994,14 +3322,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_BYTE) {
-       SvGROW(TARG, UNISKIP(value)+1);
-       tmps = (char*)uvchr_to_utf8((U8*)SvPVX(TARG), value);
-       SvCUR_set(TARG, tmps - SvPVX(TARG));
+    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_const(TARG));
        *tmps = '\0';
        (void)SvPOK_only(TARG);
        SvUTF8_on(TARG);
@@ -3012,88 +3353,136 @@ PP(pp_chr)
     SvGROW(TARG,2);
     SvCUR_set(TARG, 1);
     tmps = SvPVX(TARG);
-    *tmps++ = value;
+    *tmps++ = (char)value;
     *tmps = '\0';
     (void)SvPOK_only(TARG);
+    if (PL_encoding && !IN_BYTES) {
+        sv_recode_to_utf8(TARG, PL_encoding);
+       tmps = SvPVX(TARG);
+       if (SvCUR(TARG) == 0 || !is_utf8_string((U8*)tmps, SvCUR(TARG)) ||
+           memEQ(tmps, "\xef\xbf\xbd\0", 4)) {
+           SvGROW(TARG, 3);
+           tmps = SvPVX(TARG);
+           SvCUR_set(TARG, 2);
+           *tmps++ = (U8)UTF8_EIGHT_BIT_HI(value);
+           *tmps++ = (U8)UTF8_EIGHT_BIT_LO(value);
+           *tmps = '\0';
+           SvUTF8_on(TARG);
+       }
+    }
     XPUSHs(TARG);
     RETURN;
 }
 
 PP(pp_crypt)
 {
-    dSP; dTARGET; dPOPTOPssrl;
-    STRLEN n_a;
 #ifdef HAS_CRYPT
-    char *tmps = SvPV(left, n_a);
-#ifdef FCRYPT
-    sv_setpv(TARG, fcrypt(tmps, SvPV(right, n_a)));
-#else
-    sv_setpv(TARG, PerlProc_crypt(tmps, SvPV(right, n_a)));
+    dSP; dTARGET;
+    dPOPTOPssrl;
+    STRLEN 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* const tsv = sv_2mortal(newSVsv(left));
+
+        SvUTF8_on(tsv);
+        sv_utf8_downgrade(tsv, FALSE);
+        tmps = SvPV_const(tsv, len);
+    }
+#   ifdef USE_ITHREADS
+#     ifdef HAS_CRYPT_R
+    if (!PL_reentrant_buffer->_crypt_struct_buffer) {
+      /* This should be threadsafe because in ithreads there is only
+       * one thread per interpreter.  If this would not be true,
+       * we would need a mutex to protect this malloc. */
+        PL_reentrant_buffer->_crypt_struct_buffer =
+         (struct crypt_data *)safemalloc(sizeof(struct crypt_data));
+#if defined(__GLIBC__) || defined(__EMX__)
+       if (PL_reentrant_buffer->_crypt_struct_buffer) {
+           PL_reentrant_buffer->_crypt_struct_buffer->initialized = 0;
+           /* work around glibc-2.2.5 bug */
+           PL_reentrant_buffer->_crypt_struct_buffer->current_saltbits = 0;
+       }
 #endif
+    }
+#     endif /* HAS_CRYPT_R */
+#   endif /* USE_ITHREADS */
+#   ifdef FCRYPT
+    sv_setpv(TARG, fcrypt(tmps, SvPV_nolen_const(right)));
+#   else
+    sv_setpv(TARG, PerlProc_crypt(tmps, SvPV_nolen_const(right)));
+#   endif
+    SETs(TARG);
+    RETURN;
 #else
     DIE(aTHX_
       "The crypt() function is unimplemented due to excessive paranoia.");
 #endif
-    SETs(TARG);
-    RETURN;
 }
 
 PP(pp_ucfirst)
 {
     dSP;
     SV *sv = TOPs;
-    register U8 *s;
+    const U8 *s;
     STRLEN slen;
 
-    if (DO_UTF8(sv) && (s = (U8*)SvPV(sv, slen)) && slen && UTF8_IS_START(*s)) {
+    SvGETMAGIC(sv);
+    if (DO_UTF8(sv) &&
+       (s = (const U8*)SvPV_nomg_const(sv, slen)) && slen &&
+       UTF8_IS_START(*s)) {
+       U8 tmpbuf[UTF8_MAXBYTES_CASE+1];
        STRLEN ulen;
-       U8 tmpbuf[UTF8_MAXLEN+1];
-       U8 *tend;
-       UV uv;
+       STRLEN tculen;
 
-       if (PL_op->op_private & OPpLOCALE) {
-           TAINT;
-           SvTAINTED_on(sv);
-           uv = toTITLE_LC_uvchr(utf8n_to_uvchr(s, slen, &ulen, 0));
-       }
-       else
-           uv = toTITLE_utf8(s);
-       
-       tend = uvchr_to_utf8(tmpbuf, uv);
+       utf8_to_uvchr(s, &ulen);
+       toTITLE_utf8(s, tmpbuf, &tculen);
+       utf8_to_uvchr(tmpbuf, 0);
 
-       if (!SvPADTMP(sv) || tend - tmpbuf != ulen || SvREADONLY(sv)) {
+       if (!SvPADTMP(sv) || SvREADONLY(sv)) {
            dTARGET;
-           sv_setpvn(TARG, (char*)tmpbuf, tend - tmpbuf);
-           sv_catpvn(TARG, (char*)(s + ulen), slen - ulen);
+           /* slen is the byte length of the whole SV.
+            * ulen is the byte length of the original Unicode character
+            * stored as UTF-8 at s.
+            * tculen is the byte length of the freshly titlecased
+            * Unicode character stored as UTF-8 at tmpbuf.
+            * We first set the result to be the titlecased character,
+            * and then append the rest of the SV data. */
+           sv_setpvn(TARG, (char*)tmpbuf, tculen);
+           if (slen > ulen)
+               sv_catpvn(TARG, (char*)(s + ulen), slen - ulen);
            SvUTF8_on(TARG);
            SETs(TARG);
        }
        else {
-           s = (U8*)SvPV_force(sv, slen);
-           Copy(tmpbuf, s, ulen, U8);
+           s = (U8*)SvPV_force_nomg(sv, slen);
+           Copy(tmpbuf, s, tculen, U8);
        }
     }
     else {
+       U8 *s1;
        if (!SvPADTMP(sv) || SvREADONLY(sv)) {
            dTARGET;
            SvUTF8_off(TARG);                           /* decontaminate */
-           sv_setsv(TARG, sv);
+           sv_setsv_nomg(TARG, sv);
            sv = TARG;
            SETs(sv);
        }
-       s = (U8*)SvPV_force(sv, slen);
-       if (*s) {
-           if (PL_op->op_private & OPpLOCALE) {
+       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);
        }
     }
-    if (SvSMAGICAL(sv))
-       mg_set(sv);
+    SvSETMAGIC(sv);
     RETURN;
 }
 
@@ -3101,58 +3490,56 @@ PP(pp_lcfirst)
 {
     dSP;
     SV *sv = TOPs;
-    register U8 *s;
+    const U8 *s;
     STRLEN slen;
 
-    if (DO_UTF8(sv) && (s = (U8*)SvPV(sv, slen)) && slen && UTF8_IS_START(*s)) {
+    SvGETMAGIC(sv);
+    if (DO_UTF8(sv) &&
+       (s = (const U8*)SvPV_nomg_const(sv, slen)) && slen &&
+       UTF8_IS_START(*s)) {
        STRLEN ulen;
-       U8 tmpbuf[UTF8_MAXLEN+1];
+       U8 tmpbuf[UTF8_MAXBYTES_CASE+1];
        U8 *tend;
        UV uv;
 
-       if (PL_op->op_private & OPpLOCALE) {
-           TAINT;
-           SvTAINTED_on(sv);
-           uv = toLOWER_LC_uvchr(utf8n_to_uvchr(s, slen, &ulen, 0));
-       }
-       else
-           uv = toLOWER_utf8(s);
-       
+       toLOWER_utf8(s, tmpbuf, &ulen);
+       uv = utf8_to_uvchr(tmpbuf, 0);
        tend = uvchr_to_utf8(tmpbuf, uv);
 
-       if (!SvPADTMP(sv) || tend - tmpbuf != ulen || SvREADONLY(sv)) {
+       if (!SvPADTMP(sv) || (STRLEN)(tend - tmpbuf) != ulen || SvREADONLY(sv)) {
            dTARGET;
            sv_setpvn(TARG, (char*)tmpbuf, tend - tmpbuf);
-           sv_catpvn(TARG, (char*)(s + ulen), slen - ulen);
+           if (slen > ulen)
+               sv_catpvn(TARG, (char*)(s + ulen), slen - ulen);
            SvUTF8_on(TARG);
            SETs(TARG);
        }
        else {
-           s = (U8*)SvPV_force(sv, slen);
+           s = (U8*)SvPV_force_nomg(sv, slen);
            Copy(tmpbuf, s, ulen, U8);
        }
     }
     else {
+       U8 *s1;
        if (!SvPADTMP(sv) || SvREADONLY(sv)) {
            dTARGET;
            SvUTF8_off(TARG);                           /* decontaminate */
-           sv_setsv(TARG, sv);
+           sv_setsv_nomg(TARG, sv);
            sv = TARG;
            SETs(sv);
        }
-       s = (U8*)SvPV_force(sv, slen);
-       if (*s) {
-           if (PL_op->op_private & OPpLOCALE) {
+       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);
        }
     }
-    if (SvSMAGICAL(sv))
-       mg_set(sv);
+    SvSETMAGIC(sv);
     RETURN;
 }
 
@@ -3160,60 +3547,71 @@ PP(pp_uc)
 {
     dSP;
     SV *sv = TOPs;
-    register U8 *s;
     STRLEN len;
 
+    SvGETMAGIC(sv);
     if (DO_UTF8(sv)) {
        dTARGET;
        STRLEN ulen;
        register U8 *d;
-       U8 *send;
+       const U8 *s;
+       const U8 *send;
+       U8 tmpbuf[UTF8_MAXBYTES+1];
 
-       s = (U8*)SvPV(sv,len);
+       s = (const U8*)SvPV_nomg_const(sv,len);
        if (!len) {
            SvUTF8_off(TARG);                           /* decontaminate */
            sv_setpvn(TARG, "", 0);
            SETs(TARG);
        }
        else {
-           (void)SvUPGRADE(TARG, SVt_PV);
-           SvGROW(TARG, (len * 2) + 1);
+           STRLEN min = len + 1;
+
+           SvUPGRADE(TARG, SVt_PV);
+           SvGROW(TARG, min);
            (void)SvPOK_only(TARG);
            d = (U8*)SvPVX(TARG);
            send = s + len;
-           if (PL_op->op_private & OPpLOCALE) {
-               TAINT;
-               SvTAINTED_on(TARG);
-               while (s < send) {
-                   d = uvchr_to_utf8(d, toUPPER_LC_uvchr( utf8n_to_uvchr(s, len, &ulen, 0)));
-                   s += ulen;
-               }
-           }
-           else {
-               while (s < send) {
-                   d = uvchr_to_utf8(d, toUPPER_utf8( s ));
-                   s += UTF8SKIP(s);
+           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 += 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 */
-           sv_setsv(TARG, sv);
+           sv_setsv_nomg(TARG, sv);
            sv = TARG;
            SETs(sv);
        }
-       s = (U8*)SvPV_force(sv, len);
+       s = (U8*)SvPV_force_nomg(sv, len);
        if (len) {
-           register U8 *send = s + len;
+           const register U8 *send = s + len;
 
-           if (PL_op->op_private & OPpLOCALE) {
+           if (IN_LOCALE_RUNTIME) {
                TAINT;
                SvTAINTED_on(sv);
                for (; s < send; s++)
@@ -3225,8 +3623,7 @@ PP(pp_uc)
            }
        }
     }
-    if (SvSMAGICAL(sv))
-       mg_set(sv);
+    SvSETMAGIC(sv);
     RETURN;
 }
 
@@ -3234,61 +3631,91 @@ 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;
+       const U8 *send;
+       U8 tmpbuf[UTF8_MAXBYTES_CASE+1];
 
-       s = (U8*)SvPV(sv,len);
+       s = (const U8*)SvPV_nomg_const(sv,len);
        if (!len) {
            SvUTF8_off(TARG);                           /* decontaminate */
            sv_setpvn(TARG, "", 0);
            SETs(TARG);
        }
        else {
-           (void)SvUPGRADE(TARG, SVt_PV);
-           SvGROW(TARG, (len * 2) + 1);
+           STRLEN min = len + 1;
+
+           SvUPGRADE(TARG, SVt_PV);
+           SvGROW(TARG, min);
            (void)SvPOK_only(TARG);
            d = (U8*)SvPVX(TARG);
            send = s + len;
-           if (PL_op->op_private & OPpLOCALE) {
-               TAINT;
-               SvTAINTED_on(TARG);
-               while (s < send) {
-                   d = uvchr_to_utf8(d, toLOWER_LC_uvchr( utf8n_to_uvchr(s, len, &ulen, 0)));
-                   s += ulen;
+           while (s < send) {
+               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
+                     * /$ignorable_sequence$cased_letter/;
+                     * and it IS preceded by
+                     * /$cased_letter$ignorable_sequence/;
+                     * where $ignorable_sequence is
+                     * [\x{2010}\x{AD}\p{Mn}]*
+                     * and $cased_letter is
+                     * [\p{Ll}\p{Lo}\p{Lt}]
+                     * then it should be mapped to 0x03C2,
+                     * (GREEK SMALL LETTER FINAL SIGMA),
+                     * instead of staying 0x03A3.
+                     * "should be": in other words,
+                     * this is not implemented yet.
+                     * See lib/unicore/SpecialCasing.txt.
+                     */
                }
-           }
-           else {
-               while (s < send) {
-                   d = uvchr_to_utf8(d, toLOWER_utf8(s));
-                   s += UTF8SKIP(s);
+               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 += 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 */
-           sv_setsv(TARG, sv);
+           sv_setsv_nomg(TARG, sv);
            sv = TARG;
            SETs(sv);
        }
 
-       s = (U8*)SvPV_force(sv, len);
+       s = (U8*)SvPV_force_nomg(sv, len);
        if (len) {
-           register U8 *send = s + len;
+           register const U8 * const send = s + len;
 
-           if (PL_op->op_private & OPpLOCALE) {
+           if (IN_LOCALE_RUNTIME) {
                TAINT;
                SvTAINTED_on(sv);
                for (; s < send; s++)
@@ -3300,22 +3727,21 @@ PP(pp_lc)
            }
        }
     }
-    if (SvSMAGICAL(sv))
-       mg_set(sv);
+    SvSETMAGIC(sv);
     RETURN;
 }
 
 PP(pp_quotemeta)
 {
     dSP; dTARGET;
-    SV *sv = TOPs;
+    SV * const sv = TOPs;
     STRLEN len;
-    register char *s = SvPV(sv,len);
-    register char *d;
+    const register 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)) {
@@ -3345,7 +3771,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
@@ -3361,17 +3787,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;
            }
@@ -3379,7 +3804,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;
@@ -3395,7 +3821,7 @@ PP(pp_aslice)
     }
     if (GIMME != G_ARRAY) {
        MARK = ORIGMARK;
-       *++MARK = *SP;
+       *++MARK = SP > ORIGMARK ? *SP : &PL_sv_undef;
        SP = MARK;
     }
     RETURN;
@@ -3406,25 +3832,24 @@ PP(pp_aslice)
 PP(pp_each)
 {
     dSP;
-    HV *hash = (HV*)POPs;
+    HV * const hash = (HV*)POPs;
     HE *entry;
-    I32 gimme = GIMME_V;
-    I32 realhv = (SvTYPE(hash) == SVt_PVHV);
+    const I32 gimme = GIMME_V;
 
     PUTBACK;
     /* might clobber stack_sp */
-    entry = realhv ? hv_iternext(hash) : avhv_iternext((AV*)hash);
+    entry = hv_iternext(hash);
     SPAGAIN;
 
     EXTEND(SP, 2);
     if (entry) {
-       PUSHs(hv_iterkeysv(entry));     /* won't clobber stack_sp */
+       SV* const sv = hv_iterkeysv(entry);
+       PUSHs(sv);      /* won't clobber stack_sp */
        if (gimme == G_ARRAY) {
            SV *val;
            PUTBACK;
            /* might clobber stack_sp */
-           val = realhv ?
-                 hv_iterval(hash, entry) : avhv_iterval((AV*)hash, entry);
+           val = hv_iterval(hash, entry);
            SPAGAIN;
            PUSHs(val);
        }
@@ -3448,35 +3873,26 @@ PP(pp_keys)
 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) {
-           if (PL_op->op_flags & OPf_SPECIAL) {        /* array element */
-               while (++MARK <= SP) {
-                   sv = av_delete((AV*)hv, SvIV(*MARK), discard);
-                   *MARK = sv ? sv : &PL_sv_undef;
-               }
-           }
-           else {                                      /* pseudo-hash element */
-               while (++MARK <= SP) {
-                   sv = avhv_delete_ent((AV*)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 * const sv = av_delete((AV*)hv, SvIV(*MARK), discard);
+                    *MARK = sv ? sv : &PL_sv_undef;
+                }
+            }
        }
        else
            DIE(aTHX_ "Not a HASH reference");
@@ -3484,20 +3900,24 @@ 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) {
            if (PL_op->op_flags & OPf_SPECIAL)
                sv = av_delete((AV*)hv, SvIV(keysv), discard);
            else
-               sv = avhv_delete_ent((AV*)hv, keysv, discard, 0);
+               DIE(aTHX_ "panic: avhv_delete no longer supported");
        }
        else
            DIE(aTHX_ "Not a HASH reference");
@@ -3517,9 +3937,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))
@@ -3537,8 +3956,6 @@ PP(pp_exists)
            if (av_exists((AV*)hv, SvIV(tmpsv)))
                RETPUSHYES;
        }
-       else if (avhv_exists_ent((AV*)hv, tmpsv, 0))    /* pseudo-hash element */
-           RETPUSHYES;
     }
     else {
        DIE(aTHX_ "Not a HASH reference");
@@ -3549,48 +3966,58 @@ PP(pp_exists)
 PP(pp_hslice)
 {
     dSP; dMARK; dORIGMARK;
-    register HV *hv = (HV*)POPs;
-    register I32 lval = (PL_op->op_flags & OPf_MOD || LVRET);
-    I32 realhv = (SvTYPE(hv) == SVt_PVHV);
+    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) {
+        MAGIC *mg;
+        HV *stash;
+
+        other_magic = mg_find((SV*)hv, PERL_MAGIC_env) ||
+            ((mg = mg_find((SV*)hv, PERL_MAGIC_tied))
+             /* Try to preserve the existenceness of a tied hash
+              * element by using EXISTS and DELETE if possible.
+              * Fallback to FETCH and STORE otherwise */
+             && (stash = SvSTASH(SvRV(SvTIED_obj((SV*)hv, mg))))
+             && gv_fetchmethod_autoload(stash, "EXISTS", TRUE)
+             && gv_fetchmethod_autoload(stash, "DELETE", TRUE));
+    }
+
+    while (++MARK <= SP) {
+        SV * const keysv = *MARK;
+        SV **svp;
+        HE *he;
+        bool preeminent = FALSE;
+
+        if (localizing) {
+            preeminent = SvRMAGICAL(hv) && !other_magic ? 1 :
+                hv_exists_ent(hv, keysv, 0);
+        }
 
-    if (!realhv && PL_op->op_private & OPpLVAL_INTRO)
-       DIE(aTHX_ "Can't localize pseudo-hash element");
+        he = hv_fetch_ent(hv, keysv, lval, 0);
+        svp = he ? &HeVAL(he) : 0;
 
-    if (realhv || SvTYPE(hv) == SVt_PVAV) {
-       while (++MARK <= SP) {
-           SV *keysv = *MARK;
-           SV **svp;
-           I32 preeminent = SvRMAGICAL(hv) ? 1 :
-                               realhv ? hv_exists_ent(hv, keysv, 0)
-                                      : avhv_exists_ent((AV*)hv, keysv, 0);
-           if (realhv) {
-               HE *he = hv_fetch_ent(hv, keysv, lval, 0);
-               svp = he ? &HeVAL(he) : 0;
-           }
-           else {
-               svp = avhv_fetch_ent((AV*)hv, keysv, lval, 0);
-           }
-           if (lval) {
-               if (!svp || *svp == &PL_sv_undef) {
-                   STRLEN n_a;
-                   DIE(aTHX_ PL_no_helem, SvPV(keysv, n_a));
-               }
-               if (PL_op->op_private & OPpLVAL_INTRO) {
-                   if (preeminent)
-                       save_helem(hv, keysv, svp);
-                   else {
-                       STRLEN keylen;
-                       char *key = SvPV(keysv, keylen);
-                       SAVEDELETE(hv, savepvn(key,keylen), keylen);
-                   }
+        if (lval) {
+            if (!svp || *svp == &PL_sv_undef) {
+                DIE(aTHX_ PL_no_helem_sv, keysv);
+            }
+            if (localizing) {
+                if (preeminent)
+                    save_helem(hv, keysv, svp);
+                else {
+                    STRLEN keylen;
+                    const char *key = SvPV_const(keysv, keylen);
+                    SAVEDELETE(hv, savepvn(key,keylen), keylen);
                 }
-           }
-           *MARK = svp ? *svp : &PL_sv_undef;
-       }
+            }
+        }
+        *MARK = svp ? *svp : &PL_sv_undef;
     }
     if (GIMME != G_ARRAY) {
        MARK = ORIGMARK;
-       *++MARK = *SP;
+       *++MARK = SP > ORIGMARK ? *SP : &PL_sv_undef;
        SP = MARK;
     }
     RETURN;
@@ -3614,20 +4041,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
@@ -3646,7 +4071,7 @@ PP(pp_lslice)
     }
 
     for (lelem = firstlelem; lelem <= lastlelem; lelem++) {
-       ix = SvIVx(*lelem);
+       I32 ix = SvIVx(*lelem);
        if (ix < 0)
            ix += max;
        else
@@ -3669,8 +4094,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;
@@ -3679,15 +4104,15 @@ 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))
-           Perl_warner(aTHX_ WARN_MISC, "Odd number of elements in hash assignment");
+           Perl_warner(aTHX_ packWARN(WARN_MISC), "Odd number of elements in anonymous hash");
        (void)hv_store_ent(hv,key,val,0);
     }
     SP = ORIGMARK;
@@ -3697,7 +4122,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;
@@ -3708,9 +4133,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, 'P'))) {
+    if (mg) {
        *MARK-- = SvTIED_obj((SV*)ary, mg);
        PUSHMARK(MARK);
        PUTBACK;
@@ -3746,8 +4171,11 @@ PP(pp_splice)
        offset = 0;
        length = AvMAX(ary) + 1;
     }
-    if (offset > AvFILLp(ary) + 1)
+    if (offset > AvFILLp(ary) + 1) {
+       if (ckWARN(WARN_MISC))
+           Perl_warner(aTHX_ packWARN(WARN_MISC), "splice() offset past end of array" );
        offset = AvFILLp(ary) + 1;
+    }
     after = AvFILLp(ary) + 1 - (offset + length);
     if (after < 0) {                           /* not that much array */
        length += after;                        /* offset+length now in array */
@@ -3763,6 +4191,12 @@ 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 */
@@ -3802,7 +4236,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 {
@@ -3819,11 +4253,7 @@ 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);
        }
     }
@@ -3843,7 +4273,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;
            }
@@ -3862,10 +4292,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) {
@@ -3899,12 +4329,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, 'P'))) {
+    if (mg) {
        *MARK-- = SvTIED_obj((SV*)ary, mg);
        PUSHMARK(MARK);
        PUTBACK;
@@ -3916,7 +4345,7 @@ PP(pp_push)
     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);
@@ -3930,8 +4359,8 @@ PP(pp_push)
 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);
@@ -3941,8 +4370,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;
@@ -3954,13 +4383,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, 'P'))) {
+    if (mg) {
        *MARK-- = SvTIED_obj((SV*)ary, mg);
        PUSHMARK(MARK);
        PUTBACK;
@@ -3970,10 +4397,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);
        }
     }
@@ -3985,13 +4412,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;
        }
@@ -4004,17 +4430,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++;
@@ -4030,7 +4461,7 @@ PP(pp_reverse)
                        while (down > up) {
                            tmp = *up;
                            *up++ = *down;
-                           *down-- = tmp;
+                           *down-- = (char)tmp;
                        }
                    }
                }
@@ -4040,7 +4471,7 @@ PP(pp_reverse)
            while (down > up) {
                tmp = *up;
                *up++ = *down;
-               *down-- = tmp;
+               *down-- = (char)tmp;
            }
            (void)SvPOK_only_UTF8(TARG);
        }
@@ -4050,1813 +4481,79 @@ PP(pp_reverse)
     RETURN;
 }
 
-STATIC SV *
-S_mul128(pTHX_ SV *sv, U8 m)
+PP(pp_split)
 {
-  STRLEN          len;
-  char           *s = SvPV(sv, len);
-  char           *t;
-  U32             i = 0;
-
-  if (!strnEQ(s, "0000", 4)) {  /* need to grow sv */
-    SV             *tmpNew = newSVpvn("0000000000", 10);
-
-    sv_catsv(tmpNew, sv);
-    SvREFCNT_dec(sv);          /* free old sv */
-    sv = tmpNew;
-    s = SvPV(sv, len);
-  }
-  t = s + len - 1;
-  while (!*t)                   /* trailing '\0'? */
-    t--;
-  while (t > s) {
-    i = ((*t - '0') << 7) + m;
-    *(t--) = '0' + (i % 10);
-    m = i / 10;
-  }
-  return (sv);
-}
-
-/* Explosives and implosives. */
+    dVAR; dSP; dTARG;
+    AV *ary;
+    register IV limit = POPi;                  /* note, negative is forever */
+    SV * const sv = POPs;
+    STRLEN 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 const char *m;
+    I32 iters = 0;
+    const STRLEN slen = do_utf8 ? utf8_length((U8*)s, (U8*)strend) : (strend - s);
+    I32 maxiters = slen + 10;
+    const char *orig;
+    const I32 origlimit = limit;
+    I32 realarray = 0;
+    I32 base;
+    const I32 gimme = GIMME_V;
+    const I32 oldsave = PL_savestack_ix;
+    I32 make_mortal = 1;
+    bool multiline = 0;
+    MAGIC *mg = (MAGIC *) NULL;
 
-#if 'I' == 73 && 'J' == 74
-/* On an ASCII/ISO kind of system */
-#define ISUUCHAR(ch)    ((ch) >= ' ' && (ch) < 'a')
+#ifdef DEBUGGING
+    Copy(&LvTARGOFF(POPs), &pm, 1, PMOP*);
 #else
-/*
-  Some other sort of character set - use memchr() so we don't match
-  the null byte.
- */
-#define ISUUCHAR(ch)    (memchr(PL_uuemap, (ch), sizeof(PL_uuemap)-1) || (ch) == ' ')
+    pm = (PMOP*)POPs;
 #endif
+    if (!pm || !s)
+       DIE(aTHX_ "panic: pp_split");
+    rx = PM_GETRE(pm);
 
+    TAINT_IF((pm->op_pmflags & PMf_LOCALE) &&
+            (pm->op_pmflags & (PMf_WHITE | PMf_SKIPWHITE)));
 
-PP(pp_unpack)
-{
-    dSP;
-    dPOPPOPssrl;
-    I32 start_sp_offset = SP - PL_stack_base;
-    I32 gimme = GIMME_V;
-    SV *sv;
-    STRLEN llen;
-    STRLEN rlen;
-    register char *pat = SvPV(left, llen);
-#ifdef PACKED_IS_OCTETS
-    /* Packed side is assumed to be octets - so force downgrade if it
-       has been UTF-8 encoded by accident
-     */
-    register char *s = SvPVbyte(right, rlen);
+    RX_MATCH_UTF8_set(rx, do_utf8);
+
+    if (pm->op_pmreplroot) {
+#ifdef USE_ITHREADS
+       ary = GvAVn((GV*)PAD_SVl(INT2PTR(PADOFFSET, pm->op_pmreplroot)));
 #else
-    register char *s = SvPV(right, rlen);
-#endif
-    char *strend = s + rlen;
-    char *strbeg = s;
-    register char *patend = pat + llen;
-    I32 datumtype;
-    register I32 len;
-    register I32 bits;
-    register char *str;
-
-    /* These must not be in registers: */
-    short ashort;
-    int aint;
-    long along;
-#ifdef HAS_QUAD
-    Quad_t aquad;
-#endif
-    U16 aushort;
-    unsigned int auint;
-    U32 aulong;
-#ifdef HAS_QUAD
-    Uquad_t auquad;
-#endif
-    char *aptr;
-    float afloat;
-    double adouble;
-    I32 checksum = 0;
-    register U32 culong;
-    NV cdouble;
-    int commas = 0;
-    int star;
-#ifdef PERL_NATINT_PACK
-    int natint;                /* native integer */
-    int unatint;       /* unsigned native integer */
+       ary = GvAVn((GV*)pm->op_pmreplroot);
 #endif
-
-    if (gimme != G_ARRAY) {            /* arrange to do first one only */
-       /*SUPPRESS 530*/
-       for (patend = pat; !isALPHA(*patend) || *patend == 'x'; patend++) ;
-       if (strchr("aAZbBhHP", *patend) || *pat == '%') {
-           patend++;
-           while (isDIGIT(*patend) || *patend == '*')
-               patend++;
-       }
-       else
-           patend++;
     }
-    while (pat < patend) {
-      reparse:
-       datumtype = *pat++ & 0xFF;
-#ifdef PERL_NATINT_PACK
-       natint = 0;
-#endif
-       if (isSPACE(datumtype))
-           continue;
-       if (datumtype == '#') {
-           while (pat < patend && *pat != '\n')
-               pat++;
-           continue;
-       }
-       if (*pat == '!') {
-           char *natstr = "sSiIlL";
-
-           if (strchr(natstr, datumtype)) {
-#ifdef PERL_NATINT_PACK
-               natint = 1;
-#endif
-               pat++;
-           }
-           else
-               DIE(aTHX_ "'!' allowed only after types %s", natstr);
-       }
-       star = 0;
-       if (pat >= patend)
-           len = 1;
-       else if (*pat == '*') {
-           len = strend - strbeg;      /* long enough */
-           pat++;
-           star = 1;
+    else if (gimme != G_ARRAY)
+       ary = GvAVn(PL_defgv);
+    else
+       ary = Nullav;
+    if (ary && (gimme != G_ARRAY || (pm->op_pmflags & PMf_ONCE))) {
+       realarray = 1;
+       PUTBACK;
+       av_extend(ary,0);
+       av_clear(ary);
+       SPAGAIN;
+       if ((mg = SvTIED_mg((SV*)ary, PERL_MAGIC_tied))) {
+           PUSHMARK(SP);
+           XPUSHs(SvTIED_obj((SV*)ary, mg));
        }
-       else if (isDIGIT(*pat)) {
-           len = *pat++ - '0';
-           while (isDIGIT(*pat)) {
-               len = (len * 10) + (*pat++ - '0');
-               if (len < 0)
-                   DIE(aTHX_ "Repeat count in unpack overflows");
+       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 */
            }
-       }
-       else
-           len = (datumtype != '@');
-      redo_switch:
-       switch(datumtype) {
-       default:
-           DIE(aTHX_ "Invalid type in unpack: '%c'", (int)datumtype);
-       case ',': /* grandfather in commas but with a warning */
-           if (commas++ == 0 && ckWARN(WARN_UNPACK))
-               Perl_warner(aTHX_ WARN_UNPACK,
-                           "Invalid type in unpack: '%c'", (int)datumtype);
-           break;
-       case '%':
-           if (len == 1 && pat[-1] != '1')
-               len = 16;
-           checksum = len;
-           culong = 0;
-           cdouble = 0;
-           if (pat < patend)
-               goto reparse;
-           break;
-       case '@':
-           if (len > strend - strbeg)
-               DIE(aTHX_ "@ outside of string");
-           s = strbeg + len;
-           break;
-       case 'X':
-           if (len > s - strbeg)
-               DIE(aTHX_ "X outside of string");
-           s -= len;
-           break;
-       case 'x':
-           if (len > strend - s)
-               DIE(aTHX_ "x outside of string");
-           s += len;
-           break;
-       case '/':
-           if (start_sp_offset >= SP - PL_stack_base)
-               DIE(aTHX_ "/ must follow a numeric type");
-           datumtype = *pat++;
-           if (*pat == '*')
-               pat++;          /* ignore '*' for compatibility with pack */
-           if (isDIGIT(*pat))
-               DIE(aTHX_ "/ cannot take a count" );
-           len = POPi;
-           star = 0;
-           goto redo_switch;
-       case 'A':
-       case 'Z':
-       case 'a':
-           if (len > strend - s)
-               len = strend - s;
-           if (checksum)
-               goto uchar_checksum;
-           sv = NEWSV(35, len);
-           sv_setpvn(sv, s, len);
-           s += len;
-           if (datumtype == 'A' || datumtype == 'Z') {
-               aptr = s;       /* borrow register */
-               if (datumtype == 'Z') { /* 'Z' strips stuff after first null */
-                   s = SvPVX(sv);
-                   while (*s)
-                       s++;
-               }
-               else {          /* 'A' strips both nulls and spaces */
-                   s = SvPVX(sv) + len - 1;
-                   while (s >= SvPVX(sv) && (!*s || isSPACE(*s)))
-                       s--;
-                   *++s = '\0';
-               }
-               SvCUR_set(sv, s - SvPVX(sv));
-               s = aptr;       /* unborrow register */
-           }
-           XPUSHs(sv_2mortal(sv));
-           break;
-       case 'B':
-       case 'b':
-           if (star || len > (strend - s) * 8)
-               len = (strend - s) * 8;
-           if (checksum) {
-               if (!PL_bitcount) {
-                   Newz(601, PL_bitcount, 256, char);
-                   for (bits = 1; bits < 256; bits++) {
-                       if (bits & 1)   PL_bitcount[bits]++;
-                       if (bits & 2)   PL_bitcount[bits]++;
-                       if (bits & 4)   PL_bitcount[bits]++;
-                       if (bits & 8)   PL_bitcount[bits]++;
-                       if (bits & 16)  PL_bitcount[bits]++;
-                       if (bits & 32)  PL_bitcount[bits]++;
-                       if (bits & 64)  PL_bitcount[bits]++;
-                       if (bits & 128) PL_bitcount[bits]++;
-                   }
-               }
-               while (len >= 8) {
-                   culong += PL_bitcount[*(unsigned char*)s++];
-                   len -= 8;
-               }
-               if (len) {
-                   bits = *s;
-                   if (datumtype == 'b') {
-                       while (len-- > 0) {
-                           if (bits & 1) culong++;
-                           bits >>= 1;
-                       }
-                   }
-                   else {
-                       while (len-- > 0) {
-                           if (bits & 128) culong++;
-                           bits <<= 1;
-                       }
-                   }
-               }
-               break;
-           }
-           sv = NEWSV(35, len + 1);
-           SvCUR_set(sv, len);
-           SvPOK_on(sv);
-           str = SvPVX(sv);
-           if (datumtype == 'b') {
-               aint = len;
-               for (len = 0; len < aint; len++) {
-                   if (len & 7)                /*SUPPRESS 595*/
-                       bits >>= 1;
-                   else
-                       bits = *s++;
-                   *str++ = '0' + (bits & 1);
-               }
-           }
-           else {
-               aint = len;
-               for (len = 0; len < aint; len++) {
-                   if (len & 7)
-                       bits <<= 1;
-                   else
-                       bits = *s++;
-                   *str++ = '0' + ((bits & 128) != 0);
-               }
-           }
-           *str = '\0';
-           XPUSHs(sv_2mortal(sv));
-           break;
-       case 'H':
-       case 'h':
-           if (star || len > (strend - s) * 2)
-               len = (strend - s) * 2;
-           sv = NEWSV(35, len + 1);
-           SvCUR_set(sv, len);
-           SvPOK_on(sv);
-           str = SvPVX(sv);
-           if (datumtype == 'h') {
-               aint = len;
-               for (len = 0; len < aint; len++) {
-                   if (len & 1)
-                       bits >>= 4;
-                   else
-                       bits = *s++;
-                   *str++ = PL_hexdigit[bits & 15];
-               }
-           }
-           else {
-               aint = len;
-               for (len = 0; len < aint; len++) {
-                   if (len & 1)
-                       bits <<= 4;
-                   else
-                       bits = *s++;
-                   *str++ = PL_hexdigit[(bits >> 4) & 15];
-               }
-           }
-           *str = '\0';
-           XPUSHs(sv_2mortal(sv));
-           break;
-       case 'c':
-           if (len > strend - s)
-               len = strend - s;
-           if (checksum) {
-               while (len-- > 0) {
-                   aint = *s++;
-                   if (aint >= 128)    /* fake up signed chars */
-                       aint -= 256;
-                   culong += aint;
-               }
-           }
-           else {
-               EXTEND(SP, len);
-               EXTEND_MORTAL(len);
-               while (len-- > 0) {
-                   aint = *s++;
-                   if (aint >= 128)    /* fake up signed chars */
-                       aint -= 256;
-                   sv = NEWSV(36, 0);
-                   sv_setiv(sv, (IV)aint);
-                   PUSHs(sv_2mortal(sv));
-               }
-           }
-           break;
-       case 'C':
-           if (len > strend - s)
-               len = strend - s;
-           if (checksum) {
-             uchar_checksum:
-               while (len-- > 0) {
-                   auint = *s++ & 255;
-                   culong += auint;
-               }
-           }
-           else {
-               EXTEND(SP, len);
-               EXTEND_MORTAL(len);
-               while (len-- > 0) {
-                   auint = *s++ & 255;
-                   sv = NEWSV(37, 0);
-                   sv_setiv(sv, (IV)auint);
-                   PUSHs(sv_2mortal(sv));
-               }
-           }
-           break;
-       case 'U':
-           if (len > strend - s)
-               len = strend - s;
-           if (checksum) {
-               while (len-- > 0 && s < strend) {
-                   STRLEN alen;
-                   auint = utf8n_to_uvchr((U8*)s, strend - s, &alen, 0);
-                   along = alen;
-                   s += along;
-                   if (checksum > 32)
-                       cdouble += (NV)auint;
-                   else
-                       culong += auint;
-               }
-           }
-           else {
-               EXTEND(SP, len);
-               EXTEND_MORTAL(len);
-               while (len-- > 0 && s < strend) {
-                   STRLEN alen;
-                   auint = utf8n_to_uvchr((U8*)s, strend - s, &alen, 0);
-                   along = alen;
-                   s += along;
-                   sv = NEWSV(37, 0);
-                   sv_setuv(sv, (UV)auint);
-                   PUSHs(sv_2mortal(sv));
-               }
-           }
-           break;
-       case 's':
-#if SHORTSIZE == SIZE16
-           along = (strend - s) / SIZE16;
-#else
-           along = (strend - s) / (natint ? sizeof(short) : SIZE16);
-#endif
-           if (len > along)
-               len = along;
-           if (checksum) {
-#if SHORTSIZE != SIZE16
-               if (natint) {
-                   short ashort;
-                   while (len-- > 0) {
-                       COPYNN(s, &ashort, sizeof(short));
-                       s += sizeof(short);
-                       culong += ashort;
-
-                   }
-               }
-               else
-#endif
-                {
-                   while (len-- > 0) {
-                       COPY16(s, &ashort);
-#if SHORTSIZE > SIZE16
-                       if (ashort > 32767)
-                         ashort -= 65536;
-#endif
-                       s += SIZE16;
-                       culong += ashort;
-                   }
-               }
-           }
-           else {
-               EXTEND(SP, len);
-               EXTEND_MORTAL(len);
-#if SHORTSIZE != SIZE16
-               if (natint) {
-                   short ashort;
-                   while (len-- > 0) {
-                       COPYNN(s, &ashort, sizeof(short));
-                       s += sizeof(short);
-                       sv = NEWSV(38, 0);
-                       sv_setiv(sv, (IV)ashort);
-                       PUSHs(sv_2mortal(sv));
-                   }
-               }
-               else
-#endif
-                {
-                   while (len-- > 0) {
-                       COPY16(s, &ashort);
-#if SHORTSIZE > SIZE16
-                       if (ashort > 32767)
-                         ashort -= 65536;
-#endif
-                       s += SIZE16;
-                       sv = NEWSV(38, 0);
-                       sv_setiv(sv, (IV)ashort);
-                       PUSHs(sv_2mortal(sv));
-                   }
-               }
-           }
-           break;
-       case 'v':
-       case 'n':
-       case 'S':
-#if SHORTSIZE == SIZE16
-           along = (strend - s) / SIZE16;
-#else
-           unatint = natint && datumtype == 'S';
-           along = (strend - s) / (unatint ? sizeof(unsigned short) : SIZE16);
-#endif
-           if (len > along)
-               len = along;
-           if (checksum) {
-#if SHORTSIZE != SIZE16
-               if (unatint) {
-                   unsigned short aushort;
-                   while (len-- > 0) {
-                       COPYNN(s, &aushort, sizeof(unsigned short));
-                       s += sizeof(unsigned short);
-                       culong += aushort;
-                   }
-               }
-               else
-#endif
-                {
-                   while (len-- > 0) {
-                       COPY16(s, &aushort);
-                       s += SIZE16;
-#ifdef HAS_NTOHS
-                       if (datumtype == 'n')
-                           aushort = PerlSock_ntohs(aushort);
-#endif
-#ifdef HAS_VTOHS
-                       if (datumtype == 'v')
-                           aushort = vtohs(aushort);
-#endif
-                       culong += aushort;
-                   }
-               }
-           }
-           else {
-               EXTEND(SP, len);
-               EXTEND_MORTAL(len);
-#if SHORTSIZE != SIZE16
-               if (unatint) {
-                   unsigned short aushort;
-                   while (len-- > 0) {
-                       COPYNN(s, &aushort, sizeof(unsigned short));
-                       s += sizeof(unsigned short);
-                       sv = NEWSV(39, 0);
-                       sv_setiv(sv, (UV)aushort);
-                       PUSHs(sv_2mortal(sv));
-                   }
-               }
-               else
-#endif
-                {
-                   while (len-- > 0) {
-                       COPY16(s, &aushort);
-                       s += SIZE16;
-                       sv = NEWSV(39, 0);
-#ifdef HAS_NTOHS
-                       if (datumtype == 'n')
-                           aushort = PerlSock_ntohs(aushort);
-#endif
-#ifdef HAS_VTOHS
-                       if (datumtype == 'v')
-                           aushort = vtohs(aushort);
-#endif
-                       sv_setiv(sv, (UV)aushort);
-                       PUSHs(sv_2mortal(sv));
-                   }
-               }
-           }
-           break;
-       case 'i':
-           along = (strend - s) / sizeof(int);
-           if (len > along)
-               len = along;
-           if (checksum) {
-               while (len-- > 0) {
-                   Copy(s, &aint, 1, int);
-                   s += sizeof(int);
-                   if (checksum > 32)
-                       cdouble += (NV)aint;
-                   else
-                       culong += aint;
-               }
-           }
-           else {
-               EXTEND(SP, len);
-               EXTEND_MORTAL(len);
-               while (len-- > 0) {
-                   Copy(s, &aint, 1, int);
-                   s += sizeof(int);
-                   sv = NEWSV(40, 0);
-#ifdef __osf__
-                    /* Without the dummy below unpack("i", pack("i",-1))
-                     * return 0xFFffFFff instead of -1 for Digital Unix V4.0
-                     * cc with optimization turned on.
-                    *
-                    * The bug was detected in
-                    * DEC C V5.8-009 on Digital UNIX V4.0 (Rev. 1091) (V4.0E)
-                    * with optimization (-O4) turned on.
-                    * DEC C V5.2-040 on Digital UNIX V4.0 (Rev. 564) (V4.0B)
-                    * does not have this problem even with -O4.
-                    *
-                    * This bug was reported as DECC_BUGS 1431
-                    * and tracked internally as GEM_BUGS 7775.
-                    *
-                    * The bug is fixed in
-                    * Tru64 UNIX V5.0:      Compaq C V6.1-006 or later
-                    * UNIX V4.0F support:   DEC C V5.9-006 or later
-                    * UNIX V4.0E support:   DEC C V5.8-011 or later
-                    * and also in DTK.
-                    *
-                    * See also few lines later for the same bug.
-                    */
-                    (aint) ?
-                       sv_setiv(sv, (IV)aint) :
-#endif
-                   sv_setiv(sv, (IV)aint);
-                   PUSHs(sv_2mortal(sv));
-               }
-           }
-           break;
-       case 'I':
-           along = (strend - s) / sizeof(unsigned int);
-           if (len > along)
-               len = along;
-           if (checksum) {
-               while (len-- > 0) {
-                   Copy(s, &auint, 1, unsigned int);
-                   s += sizeof(unsigned int);
-                   if (checksum > 32)
-                       cdouble += (NV)auint;
-                   else
-                       culong += auint;
-               }
-           }
-           else {
-               EXTEND(SP, len);
-               EXTEND_MORTAL(len);
-               while (len-- > 0) {
-                   Copy(s, &auint, 1, unsigned int);
-                   s += sizeof(unsigned int);
-                   sv = NEWSV(41, 0);
-#ifdef __osf__
-                    /* Without the dummy below unpack("I", pack("I",0xFFFFFFFF))
-                     * returns 1.84467440737096e+19 instead of 0xFFFFFFFF.
-                    * See details few lines earlier. */
-                    (auint) ?
-                       sv_setuv(sv, (UV)auint) :
-#endif
-                   sv_setuv(sv, (UV)auint);
-                   PUSHs(sv_2mortal(sv));
-               }
-           }
-           break;
-       case 'l':
-#if LONGSIZE == SIZE32
-           along = (strend - s) / SIZE32;
-#else
-           along = (strend - s) / (natint ? sizeof(long) : SIZE32);
-#endif
-           if (len > along)
-               len = along;
-           if (checksum) {
-#if LONGSIZE != SIZE32
-               if (natint) {
-                   while (len-- > 0) {
-                       COPYNN(s, &along, sizeof(long));
-                       s += sizeof(long);
-                       if (checksum > 32)
-                           cdouble += (NV)along;
-                       else
-                           culong += along;
-                   }
-               }
-               else
-#endif
-                {
-                   while (len-- > 0) {
-#if LONGSIZE > SIZE32 && INTSIZE == SIZE32
-                       I32 along;
-#endif
-                       COPY32(s, &along);
-#if LONGSIZE > SIZE32
-                       if (along > 2147483647)
-                         along -= 4294967296;
-#endif
-                       s += SIZE32;
-                       if (checksum > 32)
-                           cdouble += (NV)along;
-                       else
-                           culong += along;
-                   }
-               }
-           }
-           else {
-               EXTEND(SP, len);
-               EXTEND_MORTAL(len);
-#if LONGSIZE != SIZE32
-               if (natint) {
-                   while (len-- > 0) {
-                       COPYNN(s, &along, sizeof(long));
-                       s += sizeof(long);
-                       sv = NEWSV(42, 0);
-                       sv_setiv(sv, (IV)along);
-                       PUSHs(sv_2mortal(sv));
-                   }
-               }
-               else
-#endif
-                {
-                   while (len-- > 0) {
-#if LONGSIZE > SIZE32 && INTSIZE == SIZE32
-                       I32 along;
-#endif
-                       COPY32(s, &along);
-#if LONGSIZE > SIZE32
-                       if (along > 2147483647)
-                         along -= 4294967296;
-#endif
-                       s += SIZE32;
-                       sv = NEWSV(42, 0);
-                       sv_setiv(sv, (IV)along);
-                       PUSHs(sv_2mortal(sv));
-                   }
-               }
-           }
-           break;
-       case 'V':
-       case 'N':
-       case 'L':
-#if LONGSIZE == SIZE32
-           along = (strend - s) / SIZE32;
-#else
-           unatint = natint && datumtype == 'L';
-           along = (strend - s) / (unatint ? sizeof(unsigned long) : SIZE32);
-#endif
-           if (len > along)
-               len = along;
-           if (checksum) {
-#if LONGSIZE != SIZE32
-               if (unatint) {
-                   unsigned long aulong;
-                   while (len-- > 0) {
-                       COPYNN(s, &aulong, sizeof(unsigned long));
-                       s += sizeof(unsigned long);
-                       if (checksum > 32)
-                           cdouble += (NV)aulong;
-                       else
-                           culong += aulong;
-                   }
-               }
-               else
-#endif
-                {
-                   while (len-- > 0) {
-                       COPY32(s, &aulong);
-                       s += SIZE32;
-#ifdef HAS_NTOHL
-                       if (datumtype == 'N')
-                           aulong = PerlSock_ntohl(aulong);
-#endif
-#ifdef HAS_VTOHL
-                       if (datumtype == 'V')
-                           aulong = vtohl(aulong);
-#endif
-                       if (checksum > 32)
-                           cdouble += (NV)aulong;
-                       else
-                           culong += aulong;
-                   }
-               }
-           }
-           else {
-               EXTEND(SP, len);
-               EXTEND_MORTAL(len);
-#if LONGSIZE != SIZE32
-               if (unatint) {
-                   unsigned long aulong;
-                   while (len-- > 0) {
-                       COPYNN(s, &aulong, sizeof(unsigned long));
-                       s += sizeof(unsigned long);
-                       sv = NEWSV(43, 0);
-                       sv_setuv(sv, (UV)aulong);
-                       PUSHs(sv_2mortal(sv));
-                   }
-               }
-               else
-#endif
-                {
-                   while (len-- > 0) {
-                       COPY32(s, &aulong);
-                       s += SIZE32;
-#ifdef HAS_NTOHL
-                       if (datumtype == 'N')
-                           aulong = PerlSock_ntohl(aulong);
-#endif
-#ifdef HAS_VTOHL
-                       if (datumtype == 'V')
-                           aulong = vtohl(aulong);
-#endif
-                       sv = NEWSV(43, 0);
-                       sv_setuv(sv, (UV)aulong);
-                       PUSHs(sv_2mortal(sv));
-                   }
-               }
-           }
-           break;
-       case 'p':
-           along = (strend - s) / sizeof(char*);
-           if (len > along)
-               len = along;
-           EXTEND(SP, len);
-           EXTEND_MORTAL(len);
-           while (len-- > 0) {
-               if (sizeof(char*) > strend - s)
-                   break;
-               else {
-                   Copy(s, &aptr, 1, char*);
-                   s += sizeof(char*);
-               }
-               sv = NEWSV(44, 0);
-               if (aptr)
-                   sv_setpv(sv, aptr);
-               PUSHs(sv_2mortal(sv));
-           }
-           break;
-       case 'w':
-           EXTEND(SP, len);
-           EXTEND_MORTAL(len);
-           {
-               UV auv = 0;
-               U32 bytes = 0;
-               
-               while ((len > 0) && (s < strend)) {
-                   auv = (auv << 7) | (*s & 0x7f);
-                   /* UTF8_IS_XXXXX not right here - using constant 0x80 */
-                   if ((U8)(*s++) < 0x80) {
-                       bytes = 0;
-                       sv = NEWSV(40, 0);
-                       sv_setuv(sv, auv);
-                       PUSHs(sv_2mortal(sv));
-                       len--;
-                       auv = 0;
-                   }
-                   else if (++bytes >= sizeof(UV)) {   /* promote to string */
-                       char *t;
-                       STRLEN n_a;
-
-                       sv = Perl_newSVpvf(aTHX_ "%.*"UVf, (int)TYPE_DIGITS(UV), auv);
-                       while (s < strend) {
-                           sv = mul128(sv, *s & 0x7f);
-                           if (!(*s++ & 0x80)) {
-                               bytes = 0;
-                               break;
-                           }
-                       }
-                       t = SvPV(sv, n_a);
-                       while (*t == '0')
-                           t++;
-                       sv_chop(sv, t);
-                       PUSHs(sv_2mortal(sv));
-                       len--;
-                       auv = 0;
-                   }
-               }
-               if ((s >= strend) && bytes)
-                   DIE(aTHX_ "Unterminated compressed integer");
-           }
-           break;
-       case 'P':
-           EXTEND(SP, 1);
-           if (sizeof(char*) > strend - s)
-               break;
-           else {
-               Copy(s, &aptr, 1, char*);
-               s += sizeof(char*);
-           }
-           sv = NEWSV(44, 0);
-           if (aptr)
-               sv_setpvn(sv, aptr, len);
-           PUSHs(sv_2mortal(sv));
-           break;
-#ifdef HAS_QUAD
-       case 'q':
-           along = (strend - s) / sizeof(Quad_t);
-           if (len > along)
-               len = along;
-           EXTEND(SP, len);
-           EXTEND_MORTAL(len);
-           while (len-- > 0) {
-               if (s + sizeof(Quad_t) > strend)
-                   aquad = 0;
-               else {
-                   Copy(s, &aquad, 1, Quad_t);
-                   s += sizeof(Quad_t);
-               }
-               sv = NEWSV(42, 0);
-               if (aquad >= IV_MIN && aquad <= IV_MAX)
-                   sv_setiv(sv, (IV)aquad);
-               else
-                   sv_setnv(sv, (NV)aquad);
-               PUSHs(sv_2mortal(sv));
-           }
-           break;
-       case 'Q':
-           along = (strend - s) / sizeof(Quad_t);
-           if (len > along)
-               len = along;
-           EXTEND(SP, len);
-           EXTEND_MORTAL(len);
-           while (len-- > 0) {
-               if (s + sizeof(Uquad_t) > strend)
-                   auquad = 0;
-               else {
-                   Copy(s, &auquad, 1, Uquad_t);
-                   s += sizeof(Uquad_t);
-               }
-               sv = NEWSV(43, 0);
-               if (auquad <= UV_MAX)
-                   sv_setuv(sv, (UV)auquad);
-               else
-                   sv_setnv(sv, (NV)auquad);
-               PUSHs(sv_2mortal(sv));
-           }
-           break;
-#endif
-       /* float and double added gnb@melba.bby.oz.au 22/11/89 */
-       case 'f':
-       case 'F':
-           along = (strend - s) / sizeof(float);
-           if (len > along)
-               len = along;
-           if (checksum) {
-               while (len-- > 0) {
-                   Copy(s, &afloat, 1, float);
-                   s += sizeof(float);
-                   cdouble += afloat;
-               }
-           }
-           else {
-               EXTEND(SP, len);
-               EXTEND_MORTAL(len);
-               while (len-- > 0) {
-                   Copy(s, &afloat, 1, float);
-                   s += sizeof(float);
-                   sv = NEWSV(47, 0);
-                   sv_setnv(sv, (NV)afloat);
-                   PUSHs(sv_2mortal(sv));
-               }
-           }
-           break;
-       case 'd':
-       case 'D':
-           along = (strend - s) / sizeof(double);
-           if (len > along)
-               len = along;
-           if (checksum) {
-               while (len-- > 0) {
-                   Copy(s, &adouble, 1, double);
-                   s += sizeof(double);
-                   cdouble += adouble;
-               }
-           }
-           else {
-               EXTEND(SP, len);
-               EXTEND_MORTAL(len);
-               while (len-- > 0) {
-                   Copy(s, &adouble, 1, double);
-                   s += sizeof(double);
-                   sv = NEWSV(48, 0);
-                   sv_setnv(sv, (NV)adouble);
-                   PUSHs(sv_2mortal(sv));
-               }
-           }
-           break;
-       case 'u':
-           /* MKS:
-            * Initialise the decode mapping.  By using a table driven
-             * algorithm, the code will be character-set independent
-             * (and just as fast as doing character arithmetic)
-             */
-            if (PL_uudmap['M'] == 0) {
-                int i;
-
-                for (i = 0; i < sizeof(PL_uuemap); i += 1)
-                    PL_uudmap[(U8)PL_uuemap[i]] = i;
-                /*
-                 * Because ' ' and '`' map to the same value,
-                 * we need to decode them both the same.
-                 */
-                PL_uudmap[' '] = 0;
-            }
-
-           along = (strend - s) * 3 / 4;
-           sv = NEWSV(42, along);
-           if (along)
-               SvPOK_on(sv);
-           while (s < strend && *s > ' ' && ISUUCHAR(*s)) {
-               I32 a, b, c, d;
-               char hunk[4];
-
-               hunk[3] = '\0';
-               len = PL_uudmap[*(U8*)s++] & 077;
-               while (len > 0) {
-                   if (s < strend && ISUUCHAR(*s))
-                       a = PL_uudmap[*(U8*)s++] & 077;
-                   else
-                       a = 0;
-                   if (s < strend && ISUUCHAR(*s))
-                       b = PL_uudmap[*(U8*)s++] & 077;
-                   else
-                       b = 0;
-                   if (s < strend && ISUUCHAR(*s))
-                       c = PL_uudmap[*(U8*)s++] & 077;
-                   else
-                       c = 0;
-                   if (s < strend && ISUUCHAR(*s))
-                       d = PL_uudmap[*(U8*)s++] & 077;
-                   else
-                       d = 0;
-                   hunk[0] = (a << 2) | (b >> 4);
-                   hunk[1] = (b << 4) | (c >> 2);
-                   hunk[2] = (c << 6) | d;
-                   sv_catpvn(sv, hunk, (len > 3) ? 3 : len);
-                   len -= 3;
-               }
-               if (*s == '\n')
-                   s++;
-               else if (s[1] == '\n')          /* possible checksum byte */
-                   s += 2;
-           }
-           XPUSHs(sv_2mortal(sv));
-           break;
-       }
-       if (checksum) {
-           sv = NEWSV(42, 0);
-           if (strchr("fFdD", datumtype) ||
-             (checksum > 32 && strchr("iIlLNU", datumtype)) ) {
-               NV trouble;
-
-               adouble = 1.0;
-               while (checksum >= 16) {
-                   checksum -= 16;
-                   adouble *= 65536.0;
-               }
-               while (checksum >= 4) {
-                   checksum -= 4;
-                   adouble *= 16.0;
-               }
-               while (checksum--)
-                   adouble *= 2.0;
-               along = (1 << checksum) - 1;
-               while (cdouble < 0.0)
-                   cdouble += adouble;
-               cdouble = Perl_modf(cdouble / adouble, &trouble) * adouble;
-               sv_setnv(sv, cdouble);
-           }
-           else {
-               if (checksum < 32) {
-                   aulong = (1 << checksum) - 1;
-                   culong &= aulong;
-               }
-               sv_setuv(sv, (UV)culong);
-           }
-           XPUSHs(sv_2mortal(sv));
-           checksum = 0;
-       }
-    }
-    if (SP - PL_stack_base == start_sp_offset && gimme == G_SCALAR)
-       PUSHs(&PL_sv_undef);
-    RETURN;
-}
-
-STATIC void
-S_doencodes(pTHX_ register SV *sv, register char *s, register I32 len)
-{
-    char hunk[5];
-
-    *hunk = PL_uuemap[len];
-    sv_catpvn(sv, hunk, 1);
-    hunk[4] = '\0';
-    while (len > 2) {
-       hunk[0] = PL_uuemap[(077 & (*s >> 2))];
-       hunk[1] = PL_uuemap[(077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017)))];
-       hunk[2] = PL_uuemap[(077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03)))];
-       hunk[3] = PL_uuemap[(077 & (s[2] & 077))];
-       sv_catpvn(sv, hunk, 4);
-       s += 3;
-       len -= 3;
-    }
-    if (len > 0) {
-       char r = (len > 1 ? s[1] : '\0');
-       hunk[0] = PL_uuemap[(077 & (*s >> 2))];
-       hunk[1] = PL_uuemap[(077 & (((*s << 4) & 060) | ((r >> 4) & 017)))];
-       hunk[2] = PL_uuemap[(077 & ((r << 2) & 074))];
-       hunk[3] = PL_uuemap[0];
-       sv_catpvn(sv, hunk, 4);
-    }
-    sv_catpvn(sv, "\n", 1);
-}
-
-STATIC SV *
-S_is_an_int(pTHX_ char *s, STRLEN l)
-{
-  STRLEN        n_a;
-  SV             *result = newSVpvn(s, l);
-  char           *result_c = SvPV(result, n_a);        /* convenience */
-  char           *out = result_c;
-  bool            skip = 1;
-  bool            ignore = 0;
-
-  while (*s) {
-    switch (*s) {
-    case ' ':
-      break;
-    case '+':
-      if (!skip) {
-       SvREFCNT_dec(result);
-       return (NULL);
-      }
-      break;
-    case '0':
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-      skip = 0;
-      if (!ignore) {
-       *(out++) = *s;
-      }
-      break;
-    case '.':
-      ignore = 1;
-      break;
-    default:
-      SvREFCNT_dec(result);
-      return (NULL);
-    }
-    s++;
-  }
-  *(out++) = '\0';
-  SvCUR_set(result, out - result_c);
-  return (result);
-}
-
-/* pnum must be '\0' terminated */
-STATIC int
-S_div128(pTHX_ SV *pnum, bool *done)
-{
-  STRLEN          len;
-  char           *s = SvPV(pnum, len);
-  int             m = 0;
-  int             r = 0;
-  char           *t = s;
-
-  *done = 1;
-  while (*t) {
-    int             i;
-
-    i = m * 10 + (*t - '0');
-    m = i & 0x7F;
-    r = (i >> 7);              /* r < 10 */
-    if (r) {
-      *done = 0;
-    }
-    *(t++) = '0' + r;
-  }
-  *(t++) = '\0';
-  SvCUR_set(pnum, (STRLEN) (t - s));
-  return (m);
-}
-
-
-PP(pp_pack)
-{
-    dSP; dMARK; dORIGMARK; dTARGET;
-    register SV *cat = TARG;
-    register I32 items;
-    STRLEN fromlen;
-    register char *pat = SvPVx(*++MARK, fromlen);
-    char *patcopy;
-    register char *patend = pat + fromlen;
-    register I32 len;
-    I32 datumtype;
-    SV *fromstr;
-    /*SUPPRESS 442*/
-    static char null10[] = {0,0,0,0,0,0,0,0,0,0};
-    static char *space10 = "          ";
-
-    /* These must not be in registers: */
-    char achar;
-    I16 ashort;
-    int aint;
-    unsigned int auint;
-    I32 along;
-    U32 aulong;
-#ifdef HAS_QUAD
-    Quad_t aquad;
-    Uquad_t auquad;
-#endif
-    char *aptr;
-    float afloat;
-    double adouble;
-    int commas = 0;
-#ifdef PERL_NATINT_PACK
-    int natint;                /* native integer */
-#endif
-
-    items = SP - MARK;
-    MARK++;
-    sv_setpvn(cat, "", 0);
-    patcopy = pat;
-    while (pat < patend) {
-       SV *lengthcode = Nullsv;
-#define NEXTFROM ( lengthcode ? lengthcode : items-- > 0 ? *MARK++ : &PL_sv_no)
-       datumtype = *pat++ & 0xFF;
-#ifdef PERL_NATINT_PACK
-       natint = 0;
-#endif
-       if (isSPACE(datumtype)) {
-           patcopy++;
-           continue;
-        }
-#ifndef PACKED_IS_OCTETS
-       if (datumtype == 'U' && pat == patcopy+1)
-           SvUTF8_on(cat);
-#endif
-       if (datumtype == '#') {
-           while (pat < patend && *pat != '\n')
-               pat++;
-           continue;
-       }
-        if (*pat == '!') {
-           char *natstr = "sSiIlL";
-
-           if (strchr(natstr, datumtype)) {
-#ifdef PERL_NATINT_PACK
-               natint = 1;
-#endif
-               pat++;
-           }
-           else
-               DIE(aTHX_ "'!' allowed only after types %s", natstr);
-       }
-       if (*pat == '*') {
-           len = strchr("@Xxu", datumtype) ? 0 : items;
-           pat++;
-       }
-       else if (isDIGIT(*pat)) {
-           len = *pat++ - '0';
-           while (isDIGIT(*pat)) {
-               len = (len * 10) + (*pat++ - '0');
-               if (len < 0)
-                   DIE(aTHX_ "Repeat count in pack overflows");
-           }
-       }
-       else
-           len = 1;
-       if (*pat == '/') {
-           ++pat;
-           if ((*pat != 'a' && *pat != 'A' && *pat != 'Z') || pat[1] != '*')
-               DIE(aTHX_ "/ must be followed by a*, A* or Z*");
-           lengthcode = sv_2mortal(newSViv(sv_len(items > 0
-                                                  ? *MARK : &PL_sv_no)
-                                            + (*pat == 'Z' ? 1 : 0)));
-       }
-       switch(datumtype) {
-       default:
-           DIE(aTHX_ "Invalid type in pack: '%c'", (int)datumtype);
-       case ',': /* grandfather in commas but with a warning */
-           if (commas++ == 0 && ckWARN(WARN_PACK))
-               Perl_warner(aTHX_ WARN_PACK,
-                           "Invalid type in pack: '%c'", (int)datumtype);
-           break;
-       case '%':
-           DIE(aTHX_ "%% may only be used in unpack");
-       case '@':
-           len -= SvCUR(cat);
-           if (len > 0)
-               goto grow;
-           len = -len;
-           if (len > 0)
-               goto shrink;
-           break;
-       case 'X':
-         shrink:
-           if (SvCUR(cat) < len)
-               DIE(aTHX_ "X outside of string");
-           SvCUR(cat) -= len;
-           *SvEND(cat) = '\0';
-           break;
-       case 'x':
-         grow:
-           while (len >= 10) {
-               sv_catpvn(cat, null10, 10);
-               len -= 10;
-           }
-           sv_catpvn(cat, null10, len);
-           break;
-       case 'A':
-       case 'Z':
-       case 'a':
-           fromstr = NEXTFROM;
-           aptr = SvPV(fromstr, fromlen);
-           if (pat[-1] == '*') {
-               len = fromlen;
-               if (datumtype == 'Z')
-                   ++len;
-           }
-           if (fromlen >= len) {
-               sv_catpvn(cat, aptr, len);
-               if (datumtype == 'Z')
-                   *(SvEND(cat)-1) = '\0';
-           }
-           else {
-               sv_catpvn(cat, aptr, fromlen);
-               len -= fromlen;
-               if (datumtype == 'A') {
-                   while (len >= 10) {
-                       sv_catpvn(cat, space10, 10);
-                       len -= 10;
-                   }
-                   sv_catpvn(cat, space10, len);
-               }
-               else {
-                   while (len >= 10) {
-                       sv_catpvn(cat, null10, 10);
-                       len -= 10;
-                   }
-                   sv_catpvn(cat, null10, len);
-               }
-           }
-           break;
-       case 'B':
-       case 'b':
-           {
-               register char *str;
-               I32 saveitems;
-
-               fromstr = NEXTFROM;
-               saveitems = items;
-               str = SvPV(fromstr, fromlen);
-               if (pat[-1] == '*')
-                   len = fromlen;
-               aint = SvCUR(cat);
-               SvCUR(cat) += (len+7)/8;
-               SvGROW(cat, SvCUR(cat) + 1);
-               aptr = SvPVX(cat) + aint;
-               if (len > fromlen)
-                   len = fromlen;
-               aint = len;
-               items = 0;
-               if (datumtype == 'B') {
-                   for (len = 0; len++ < aint;) {
-                       items |= *str++ & 1;
-                       if (len & 7)
-                           items <<= 1;
-                       else {
-                           *aptr++ = items & 0xff;
-                           items = 0;
-                       }
-                   }
-               }
-               else {
-                   for (len = 0; len++ < aint;) {
-                       if (*str++ & 1)
-                           items |= 128;
-                       if (len & 7)
-                           items >>= 1;
-                       else {
-                           *aptr++ = items & 0xff;
-                           items = 0;
-                       }
-                   }
-               }
-               if (aint & 7) {
-                   if (datumtype == 'B')
-                       items <<= 7 - (aint & 7);
-                   else
-                       items >>= 7 - (aint & 7);
-                   *aptr++ = items & 0xff;
-               }
-               str = SvPVX(cat) + SvCUR(cat);
-               while (aptr <= str)
-                   *aptr++ = '\0';
-
-               items = saveitems;
-           }
-           break;
-       case 'H':
-       case 'h':
-           {
-               register char *str;
-               I32 saveitems;
-
-               fromstr = NEXTFROM;
-               saveitems = items;
-               str = SvPV(fromstr, fromlen);
-               if (pat[-1] == '*')
-                   len = fromlen;
-               aint = SvCUR(cat);
-               SvCUR(cat) += (len+1)/2;
-               SvGROW(cat, SvCUR(cat) + 1);
-               aptr = SvPVX(cat) + aint;
-               if (len > fromlen)
-                   len = fromlen;
-               aint = len;
-               items = 0;
-               if (datumtype == 'H') {
-                   for (len = 0; len++ < aint;) {
-                       if (isALPHA(*str))
-                           items |= ((*str++ & 15) + 9) & 15;
-                       else
-                           items |= *str++ & 15;
-                       if (len & 1)
-                           items <<= 4;
-                       else {
-                           *aptr++ = items & 0xff;
-                           items = 0;
-                       }
-                   }
-               }
-               else {
-                   for (len = 0; len++ < aint;) {
-                       if (isALPHA(*str))
-                           items |= (((*str++ & 15) + 9) & 15) << 4;
-                       else
-                           items |= (*str++ & 15) << 4;
-                       if (len & 1)
-                           items >>= 4;
-                       else {
-                           *aptr++ = items & 0xff;
-                           items = 0;
-                       }
-                   }
-               }
-               if (aint & 1)
-                   *aptr++ = items & 0xff;
-               str = SvPVX(cat) + SvCUR(cat);
-               while (aptr <= str)
-                   *aptr++ = '\0';
-
-               items = saveitems;
-           }
-           break;
-       case 'C':
-       case 'c':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               aint = SvIV(fromstr);
-               achar = aint;
-               sv_catpvn(cat, &achar, sizeof(char));
-           }
-           break;
-       case 'U':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               auint = SvUV(fromstr);
-               SvGROW(cat, SvCUR(cat) + UTF8_MAXLEN + 1);
-               SvCUR_set(cat, (char*)uvchr_to_utf8((U8*)SvEND(cat),auint)
-                              - SvPVX(cat));
-           }
-           *SvEND(cat) = '\0';
-           break;
-       /* Float and double added by gnb@melba.bby.oz.au  22/11/89 */
-       case 'f':
-       case 'F':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               afloat = (float)SvNV(fromstr);
-               sv_catpvn(cat, (char *)&afloat, sizeof (float));
-           }
-           break;
-       case 'd':
-       case 'D':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               adouble = (double)SvNV(fromstr);
-               sv_catpvn(cat, (char *)&adouble, sizeof (double));
-           }
-           break;
-       case 'n':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               ashort = (I16)SvIV(fromstr);
-#ifdef HAS_HTONS
-               ashort = PerlSock_htons(ashort);
-#endif
-               CAT16(cat, &ashort);
-           }
-           break;
-       case 'v':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               ashort = (I16)SvIV(fromstr);
-#ifdef HAS_HTOVS
-               ashort = htovs(ashort);
-#endif
-               CAT16(cat, &ashort);
-           }
-           break;
-       case 'S':
-#if SHORTSIZE != SIZE16
-           if (natint) {
-               unsigned short aushort;
-
-               while (len-- > 0) {
-                   fromstr = NEXTFROM;
-                   aushort = SvUV(fromstr);
-                   sv_catpvn(cat, (char *)&aushort, sizeof(unsigned short));
-               }
-           }
-           else
-#endif
-            {
-               U16 aushort;
-
-               while (len-- > 0) {
-                   fromstr = NEXTFROM;
-                   aushort = (U16)SvUV(fromstr);
-                   CAT16(cat, &aushort);
-               }
-
-           }
-           break;
-       case 's':
-#if SHORTSIZE != SIZE16
-           if (natint) {
-               short ashort;
-
-               while (len-- > 0) {
-                   fromstr = NEXTFROM;
-                   ashort = SvIV(fromstr);
-                   sv_catpvn(cat, (char *)&ashort, sizeof(short));
-               }
-           }
-           else
-#endif
-            {
-               while (len-- > 0) {
-                   fromstr = NEXTFROM;
-                   ashort = (I16)SvIV(fromstr);
-                   CAT16(cat, &ashort);
-               }
-           }
-           break;
-       case 'I':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               auint = SvUV(fromstr);
-               sv_catpvn(cat, (char*)&auint, sizeof(unsigned int));
-           }
-           break;
-       case 'w':
-            while (len-- > 0) {
-               fromstr = NEXTFROM;
-               adouble = Perl_floor(SvNV(fromstr));
-
-               if (adouble < 0)
-                   DIE(aTHX_ "Cannot compress negative numbers");
-
-               if (
-#if UVSIZE > 4 && UVSIZE >= NVSIZE
-                   adouble <= 0xffffffff
-#else
-#   ifdef CXUX_BROKEN_CONSTANT_CONVERT
-                   adouble <= UV_MAX_cxux
-#   else
-                   adouble <= UV_MAX
-#   endif
-#endif
-                   )
-               {
-                   char   buf[1 + sizeof(UV)];
-                   char  *in = buf + sizeof(buf);
-                   UV     auv = U_V(adouble);
-
-                   do {
-                       *--in = (auv & 0x7f) | 0x80;
-                       auv >>= 7;
-                   } while (auv);
-                   buf[sizeof(buf) - 1] &= 0x7f; /* clear continue bit */
-                   sv_catpvn(cat, in, (buf + sizeof(buf)) - in);
-               }
-               else if (SvPOKp(fromstr)) {  /* decimal string arithmetics */
-                   char           *from, *result, *in;
-                   SV             *norm;
-                   STRLEN          len;
-                   bool            done;
-
-                   /* Copy string and check for compliance */
-                   from = SvPV(fromstr, len);
-                   if ((norm = is_an_int(from, len)) == NULL)
-                       DIE(aTHX_ "can compress only unsigned integer");
-
-                   New('w', result, len, char);
-                   in = result + len;
-                   done = FALSE;
-                   while (!done)
-                       *--in = div128(norm, &done) | 0x80;
-                   result[len - 1] &= 0x7F; /* clear continue bit */
-                   sv_catpvn(cat, in, (result + len) - in);
-                   Safefree(result);
-                   SvREFCNT_dec(norm); /* free norm */
-                }
-               else if (SvNOKp(fromstr)) {
-                   char   buf[sizeof(double) * 2];     /* 8/7 <= 2 */
-                   char  *in = buf + sizeof(buf);
-
-                   do {
-                       double next = floor(adouble / 128);
-                       *--in = (unsigned char)(adouble - (next * 128)) | 0x80;
-                       if (in <= buf)  /* this cannot happen ;-) */
-                           DIE(aTHX_ "Cannot compress integer");
-                       in--;
-                       adouble = next;
-                   } while (adouble > 0);
-                   buf[sizeof(buf) - 1] &= 0x7f; /* clear continue bit */
-                   sv_catpvn(cat, in, (buf + sizeof(buf)) - in);
-               }
-               else
-                   DIE(aTHX_ "Cannot compress non integer");
-           }
-            break;
-       case 'i':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               aint = SvIV(fromstr);
-               sv_catpvn(cat, (char*)&aint, sizeof(int));
-           }
-           break;
-       case 'N':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               aulong = SvUV(fromstr);
-#ifdef HAS_HTONL
-               aulong = PerlSock_htonl(aulong);
-#endif
-               CAT32(cat, &aulong);
-           }
-           break;
-       case 'V':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               aulong = SvUV(fromstr);
-#ifdef HAS_HTOVL
-               aulong = htovl(aulong);
-#endif
-               CAT32(cat, &aulong);
-           }
-           break;
-       case 'L':
-#if LONGSIZE != SIZE32
-           if (natint) {
-               unsigned long aulong;
-
-               while (len-- > 0) {
-                   fromstr = NEXTFROM;
-                   aulong = SvUV(fromstr);
-                   sv_catpvn(cat, (char *)&aulong, sizeof(unsigned long));
-               }
-           }
-           else
-#endif
-            {
-               while (len-- > 0) {
-                   fromstr = NEXTFROM;
-                   aulong = SvUV(fromstr);
-                   CAT32(cat, &aulong);
-               }
-           }
-           break;
-       case 'l':
-#if LONGSIZE != SIZE32
-           if (natint) {
-               long along;
-
-               while (len-- > 0) {
-                   fromstr = NEXTFROM;
-                   along = SvIV(fromstr);
-                   sv_catpvn(cat, (char *)&along, sizeof(long));
-               }
-           }
-           else
-#endif
-            {
-               while (len-- > 0) {
-                   fromstr = NEXTFROM;
-                   along = SvIV(fromstr);
-                   CAT32(cat, &along);
-               }
-           }
-           break;
-#ifdef HAS_QUAD
-       case 'Q':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               auquad = (Uquad_t)SvUV(fromstr);
-               sv_catpvn(cat, (char*)&auquad, sizeof(Uquad_t));
-           }
-           break;
-       case 'q':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               aquad = (Quad_t)SvIV(fromstr);
-               sv_catpvn(cat, (char*)&aquad, sizeof(Quad_t));
-           }
-           break;
-#endif
-       case 'P':
-           len = 1;            /* assume SV is correct length */
-           /* FALL THROUGH */
-       case 'p':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               if (fromstr == &PL_sv_undef)
-                   aptr = NULL;
-               else {
-                   STRLEN n_a;
-                   /* XXX better yet, could spirit away the string to
-                    * a safe spot and hang on to it until the result
-                    * of pack() (and all copies of the result) are
-                    * gone.
-                    */
-                   if (ckWARN(WARN_PACK) && (SvTEMP(fromstr)
-                                               || (SvPADTMP(fromstr)
-                                                   && !SvREADONLY(fromstr))))
-                   {
-                       Perl_warner(aTHX_ WARN_PACK,
-                               "Attempt to pack pointer to temporary value");
-                   }
-                   if (SvPOK(fromstr) || SvNIOK(fromstr))
-                       aptr = SvPV(fromstr,n_a);
-                   else
-                       aptr = SvPV_force(fromstr,n_a);
-               }
-               sv_catpvn(cat, (char*)&aptr, sizeof(char*));
-           }
-           break;
-       case 'u':
-           fromstr = NEXTFROM;
-           aptr = SvPV(fromstr, fromlen);
-           SvGROW(cat, fromlen * 4 / 3);
-           if (len <= 1)
-               len = 45;
-           else
-               len = len / 3 * 3;
-           while (fromlen > 0) {
-               I32 todo;
-
-               if (fromlen > len)
-                   todo = len;
-               else
-                   todo = fromlen;
-               doencodes(cat, aptr, todo);
-               fromlen -= todo;
-               aptr += todo;
-           }
-           break;
-       }
-    }
-    SvSETMAGIC(cat);
-    SP = ORIGMARK;
-    PUSHs(cat);
-    RETURN;
-}
-#undef NEXTFROM
-
-
-PP(pp_split)
-{
-    dSP; dTARG;
-    AV *ary;
-    register IV limit = POPi;                  /* note, negative is forever */
-    SV *sv = POPs;
-    STRLEN len;
-    register char *s = SvPV(sv, len);
-    bool do_utf8 = DO_UTF8(sv);
-    char *strend = s + len;
-    register PMOP *pm;
-    register REGEXP *rx;
-    register SV *dstr;
-    register char *m;
-    I32 iters = 0;
-    STRLEN slen = do_utf8 ? utf8_length((U8*)s, (U8*)strend) : (strend - s);
-    I32 maxiters = slen + 10;
-    I32 i;
-    char *orig;
-    I32 origlimit = limit;
-    I32 realarray = 0;
-    I32 base;
-    AV *oldstack = PL_curstack;
-    I32 gimme = GIMME_V;
-    I32 oldsave = PL_savestack_ix;
-    I32 make_mortal = 1;
-    MAGIC *mg = (MAGIC *) NULL;
-
-#ifdef DEBUGGING
-    Copy(&LvTARGOFF(POPs), &pm, 1, PMOP*);
-#else
-    pm = (PMOP*)POPs;
-#endif
-    if (!pm || !s)
-       DIE(aTHX_ "panic: pp_split");
-    rx = pm->op_pmregexp;
-
-    TAINT_IF((pm->op_pmflags & PMf_LOCALE) &&
-            (pm->op_pmflags & (PMf_WHITE | PMf_SKIPWHITE)));
-
-    if (pm->op_pmreplroot) {
-#ifdef USE_ITHREADS
-       ary = GvAVn((GV*)PL_curpad[(PADOFFSET)pm->op_pmreplroot]);
-#else
-       ary = GvAVn((GV*)pm->op_pmreplroot);
-#endif
-    }
-    else if (gimme != G_ARRAY)
-#ifdef USE_THREADS
-       ary = (AV*)PL_curpad[0];
-#else
-       ary = GvAVn(PL_defgv);
-#endif /* USE_THREADS */
-    else
-       ary = Nullav;
-    if (ary && (gimme != G_ARRAY || (pm->op_pmflags & PMf_ONCE))) {
-       realarray = 1;
-       PUTBACK;
-       av_extend(ary,0);
-       av_clear(ary);
-       SPAGAIN;
-       if ((mg = SvTIED_mg((SV*)ary, 'P'))) {
-           PUSHMARK(SP);
-           XPUSHs(SvTIED_obj((SV*)ary, mg));
-       }
-       else {
-           if (!AvREAL(ary)) {
-               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);
-           make_mortal = 0;
+           /* temporarily switch stacks */
+           SAVESWITCHSTACK(PL_curstack, ary);
+           make_mortal = 0;
        }
     }
     base = SP - PL_stack_base;
@@ -5871,9 +4568,8 @@ PP(pp_split)
                s++;
        }
     }
-    if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
-       SAVEINT(PL_multiline);
-       PL_multiline = pm->op_pmflags & PMf_MULTILINE;
+    if (pm->op_pmflags & PMf_MULTILINE) {
+       multiline = 1;
     }
 
     if (!limit)
@@ -5888,8 +4584,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)
@@ -5903,15 +4598,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)
@@ -5924,20 +4618,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)
@@ -5952,14 +4644,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)
@@ -5976,13 +4665,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;
@@ -5992,23 +4683,26 @@ 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) {
-               for (i = 1; i <= rx->nparens; i++) {
+               I32 i;
+               for (i = 1; i <= (I32)rx->nparens; i++) {
                    s = rx->startp[i] + orig;
                    m = rx->endp[i] + orig;
-                   if (m && s) {
-                       dstr = NEWSV(33, m-s);
-                       sv_setpvn(dstr, s, m-s);
+
+                   /* japhy (07/27/01) -- the (m && s) test doesn't catch
+                      parens that didn't match -- they should be set to
+                      undef, not the empty string */
+                   if (m >= orig && s >= orig) {
+                       dstr = newSVpvn(s, m-s);
                    }
                    else
-                       dstr = NEWSV(33, 0);
+                       dstr = &PL_sv_undef;  /* undef, not "" */
                    if (make_mortal)
                        sv_2mortal(dstr);
                    if (do_utf8)
@@ -6020,16 +4714,14 @@ PP(pp_split)
        }
     }
 
-    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)
@@ -6038,13 +4730,19 @@ PP(pp_split)
        iters++;
     }
     else if (!origlimit) {
-       while (iters > 0 && (!TOPs || !SvANY(TOPs) || SvCUR(TOPs) == 0))
-           iters--, SP--;
+       while (iters > 0 && (!TOPs || !SvANY(TOPs) || SvCUR(TOPs) == 0)) {
+           if (TOPs && !make_mortal)
+               sv_2mortal(TOPs);
+           iters--;
+           *SP-- = &PL_sv_undef;
+       }
     }
 
+    PUTBACK;
+    LEAVE_SCOPE(oldsave); /* may undo an earlier SWITCHSTACK */
+    SPAGAIN;
     if (realarray) {
        if (!mg) {
-           SWITCHSTACK(ary, oldstack);
            if (SvSMAGICAL(ary)) {
                PUTBACK;
                mg_set((SV*)ary);
@@ -6064,6 +4762,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++) {
@@ -6078,41 +4777,18 @@ PP(pp_split)
        if (gimme == G_ARRAY)
            RETURN;
     }
-    if (iters || !pm->op_pmreplroot) {
-       GETTARGET;
-       PUSHi(iters);
-       RETURN;
-    }
-    RETPUSHUNDEF;
-}
 
-#ifdef USE_THREADS
-void
-Perl_unlock_condpair(pTHX_ void *svv)
-{
-    MAGIC *mg = mg_find((SV*)svv, 'm');
-
-    if (!mg)
-       Perl_croak(aTHX_ "panic: unlock_condpair unlocking non-mutex");
-    MUTEX_LOCK(MgMUTEXP(mg));
-    if (MgOWNER(mg) != thr)
-       Perl_croak(aTHX_ "panic: unlock_condpair unlocking mutex that we don't own");
-    MgOWNER(mg) = 0;
-    COND_SIGNAL(MgOWNERCONDP(mg));
-    DEBUG_S(PerlIO_printf(Perl_debug_log, "0x%"UVxf": unlock 0x%"UVxf"\n",
-                         PTR2UV(thr), PTR2UV(svv));)
-    MUTEX_UNLOCK(MgMUTEXP(mg));
+    GETTARGET;
+    PUSHi(iters);
+    RETURN;
 }
-#endif /* USE_THREADS */
 
 PP(pp_lock)
 {
     dSP;
     dTOPss;
     SV *retsv = sv;
-#ifdef USE_THREADS
-    sv_lock(sv);
-#endif /* USE_THREADS */
+    SvLOCK(sv);
     if (SvTYPE(retsv) == SVt_PVAV || SvTYPE(retsv) == SVt_PVHV
        || SvTYPE(retsv) == SVt_PVCV) {
        retsv = refto(retsv);
@@ -6123,15 +4799,15 @@ PP(pp_lock)
 
 PP(pp_threadsv)
 {
-#ifdef USE_THREADS
-    dSP;
-    EXTEND(SP, 1);
-    if (PL_op->op_private & OPpLVAL_INTRO)
-       PUSHs(*save_threadsv(PL_op->op_targ));
-    else
-       PUSHs(THREADSV(PL_op->op_targ));
-    RETURN;
-#else
     DIE(aTHX_ "tried to access per-thread data in non-threaded perl");
-#endif /* USE_THREADS */
 }
+
+/*
+ * Local variables:
+ * c-indentation-style: bsd
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ *
+ * ex: set ts=8 sts=4 sw=4 noet:
+ */