This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix glob-assign for FORMAT
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index 96ef7c8..b408485 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -1,12 +1,22 @@
 /*    sv.c
  *
- *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, by Larry Wall and others
+ *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ *    2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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.
  *
- * "I wonder what the Entish is for 'yes' and 'no'," he thought.
+ */
+
+/*
+ * 'I wonder what the Entish is for "yes" and "no",' he thought.
+ *                                                      --Pippin
+ *
+ *     [p.480 of _The Lord of the Rings_, III/iv: "Treebeard"]
+ */
+
+/*
  *
  *
  * This file contains the code that creates, manipulates and destroys
@@ -147,7 +157,7 @@ Public API:
 
 =cut
 
-============================================================================ */
+ * ========================================================================= */
 
 /*
  * "A time to plant, and a time to uproot what was planted..."
@@ -173,14 +183,29 @@ Perl_offer_nice_chunk(pTHX_ void *const chunk, const U32 chunk_size)
     }
 }
 
+#ifdef PERL_MEM_LOG
+#  define MEM_LOG_NEW_SV(sv, file, line, func) \
+           Perl_mem_log_new_sv(sv, file, line, func)
+#  define MEM_LOG_DEL_SV(sv, file, line, func) \
+           Perl_mem_log_del_sv(sv, file, line, func)
+#else
+#  define MEM_LOG_NEW_SV(sv, file, line, func) NOOP
+#  define MEM_LOG_DEL_SV(sv, file, line, func) NOOP
+#endif
+
 #ifdef DEBUG_LEAKING_SCALARS
 #  define FREE_SV_DEBUG_FILE(sv) Safefree((sv)->sv_debug_file)
+#  define DEBUG_SV_SERIAL(sv)                                              \
+    DEBUG_m(PerlIO_printf(Perl_debug_log, "0x%"UVxf": (%05ld) del_SV\n",    \
+           PTR2UV(sv), (long)(sv)->sv_debug_serial))
 #else
 #  define FREE_SV_DEBUG_FILE(sv)
+#  define DEBUG_SV_SERIAL(sv)  NOOP
 #endif
 
 #ifdef PERL_POISON
 #  define SvARENA_CHAIN(sv)    ((sv)->sv_u.svu_rv)
+#  define SvARENA_CHAIN_SET(sv,val)    (sv)->sv_u.svu_rv = MUTABLE_SV((val))
 /* Whilst I'd love to do this, it seems that things like to check on
    unreferenced scalars
 #  define POSION_SV_HEAD(sv)   PoisonNew(sv, 1, struct STRUCT_SV)
@@ -189,23 +214,36 @@ Perl_offer_nice_chunk(pTHX_ void *const chunk, const U32 chunk_size)
                                PoisonNew(&SvREFCNT(sv), 1, U32)
 #else
 #  define SvARENA_CHAIN(sv)    SvANY(sv)
+#  define SvARENA_CHAIN_SET(sv,val)    SvANY(sv) = (void *)(val)
 #  define POSION_SV_HEAD(sv)
 #endif
 
+/* Mark an SV head as unused, and add to free list.
+ *
+ * If SVf_BREAK is set, skip adding it to the free list, as this SV had
+ * its refcount artificially decremented during global destruction, so
+ * there may be dangling pointers to it. The last thing we want in that
+ * case is for it to be reused. */
+
 #define plant_SV(p) \
     STMT_START {                                       \
+       const U32 old_flags = SvFLAGS(p);                       \
+       MEM_LOG_DEL_SV(p, __FILE__, __LINE__, FUNCTION__);  \
+       DEBUG_SV_SERIAL(p);                             \
        FREE_SV_DEBUG_FILE(p);                          \
        POSION_SV_HEAD(p);                              \
-       SvARENA_CHAIN(p) = (void *)PL_sv_root;          \
        SvFLAGS(p) = SVTYPEMASK;                        \
-       PL_sv_root = (p);                               \
+       if (!(old_flags & SVf_BREAK)) {         \
+           SvARENA_CHAIN_SET(p, PL_sv_root);   \
+           PL_sv_root = (p);                           \
+       }                                               \
        --PL_sv_count;                                  \
     } STMT_END
 
 #define uproot_SV(p) \
     STMT_START {                                       \
        (p) = PL_sv_root;                               \
-       PL_sv_root = (SV*)SvARENA_CHAIN(p);             \
+       PL_sv_root = MUTABLE_SV(SvARENA_CHAIN(p));              \
        ++PL_sv_count;                                  \
     } STMT_END
 
@@ -237,7 +275,7 @@ S_more_sv(pTHX)
 #ifdef DEBUG_LEAKING_SCALARS
 /* provide a real function for a debugger to play with */
 STATIC SV*
-S_new_SV(pTHX)
+S_new_SV(pTHX_ const char *file, int line, const char *func)
 {
     SV* sv;
 
@@ -249,20 +287,25 @@ S_new_SV(pTHX)
     SvREFCNT(sv) = 1;
     SvFLAGS(sv) = 0;
     sv->sv_debug_optype = PL_op ? PL_op->op_type : 0;
-    sv->sv_debug_line = (U16) (PL_parser
-           ?  PL_parser->copline == NOLINE
-               ?  PL_curcop
+    sv->sv_debug_line = (U16) (PL_parser && PL_parser->copline != NOLINE
+               ? PL_parser->copline
+               :  PL_curcop
                    ? CopLINE(PL_curcop)
                    : 0
-               : PL_parser->copline
-           : 0);
+           );
     sv->sv_debug_inpad = 0;
     sv->sv_debug_cloned = 0;
     sv->sv_debug_file = PL_curcop ? savepv(CopFILE(PL_curcop)): NULL;
-    
+
+    sv->sv_debug_serial = PL_sv_serial++;
+
+    MEM_LOG_NEW_SV(sv, file, line, func);
+    DEBUG_m(PerlIO_printf(Perl_debug_log, "0x%"UVxf": (%05ld) new_SV (from %s:%d [%s])\n",
+           PTR2UV(sv), (long)sv->sv_debug_serial, file, line, func));
+
     return sv;
 }
-#  define new_SV(p) (p)=S_new_SV(aTHX)
+#  define new_SV(p) (p)=S_new_SV(aTHX_ __FILE__, __LINE__, FUNCTION__)
 
 #else
 #  define new_SV(p) \
@@ -274,6 +317,7 @@ S_new_SV(pTHX)
        SvANY(p) = 0;                                   \
        SvREFCNT(p) = 1;                                \
        SvFLAGS(p) = 0;                                 \
+       MEM_LOG_NEW_SV(p, __FILE__, __LINE__, FUNCTION__);  \
     } STMT_END
 #endif
 
@@ -300,7 +344,7 @@ S_del_sv(pTHX_ SV *p)
     if (DEBUG_D_TEST) {
        SV* sva;
        bool ok = 0;
-       for (sva = PL_sv_arenaroot; sva; sva = (SV *) SvANY(sva)) {
+       for (sva = PL_sv_arenaroot; sva; sva = MUTABLE_SV(SvANY(sva))) {
            const SV * const sv = sva + 1;
            const SV * const svend = &sva[SvREFCNT(sva)];
            if (p >= sv && p < svend) {
@@ -337,11 +381,11 @@ and split it into a list of free SVs.
 =cut
 */
 
-void
-Perl_sv_add_arena(pTHX_ char *const ptr, const U32 size, const U32 flags)
+static void
+S_sv_add_arena(pTHX_ char *const ptr, const U32 size, const U32 flags)
 {
     dVAR;
-    SV* const sva = (SV*)ptr;
+    SV *const sva = MUTABLE_SV(ptr);
     register SV* sv;
     register SV* svend;
 
@@ -358,7 +402,7 @@ Perl_sv_add_arena(pTHX_ char *const ptr, const U32 size, const U32 flags)
     svend = &sva[SvREFCNT(sva) - 1];
     sv = sva + 1;
     while (sv < svend) {
-       SvARENA_CHAIN(sv) = (void *)(SV*)(sv + 1);
+       SvARENA_CHAIN_SET(sv, (sv + 1));
 #ifdef DEBUGGING
        SvREFCNT(sv) = 0;
 #endif
@@ -367,7 +411,7 @@ Perl_sv_add_arena(pTHX_ char *const ptr, const U32 size, const U32 flags)
        SvFLAGS(sv) = SVTYPEMASK;
        sv++;
     }
-    SvARENA_CHAIN(sv) = 0;
+    SvARENA_CHAIN_SET(sv, 0);
 #ifdef DEBUGGING
     SvREFCNT(sv) = 0;
 #endif
@@ -386,7 +430,7 @@ S_visit(pTHX_ SVFUNC_t f, const U32 flags, const U32 mask)
 
     PERL_ARGS_ASSERT_VISIT;
 
-    for (sva = PL_sv_arenaroot; sva; sva = (SV*)SvANY(sva)) {
+    for (sva = PL_sv_arenaroot; sva; sva = MUTABLE_SV(SvANY(sva))) {
        register const SV * const svend = &sva[SvREFCNT(sva)];
        register SV* sv;
        for (sv = sva + 1; sv < svend; ++sv) {
@@ -516,7 +560,7 @@ static void
 do_clean_all(pTHX_ SV *const sv)
 {
     dVAR;
-    if (sv == (SV*) PL_fdpid || sv == (SV *)PL_strtab) {
+    if (sv == (const SV *) PL_fdpid || sv == (const SV *)PL_strtab) {
        /* don't clean pid table and strtab */
        return;
     }
@@ -603,9 +647,9 @@ Perl_sv_free_arenas(pTHX)
        contiguity of the fake ones with the corresponding real ones.) */
 
     for (sva = PL_sv_arenaroot; sva; sva = svanext) {
-       svanext = (SV*) SvANY(sva);
+       svanext = MUTABLE_SV(SvANY(sva));
        while (svanext && SvFAKE(svanext))
-           svanext = (SV*) SvANY(svanext);
+           svanext = MUTABLE_SV(SvANY(svanext));
 
        if (!SvFAKE(sva))
            Safefree(sva);
@@ -883,7 +927,7 @@ struct xpv {
 
 #define copy_length(type, last_member) \
        STRUCT_OFFSET(type, last_member) \
-       + sizeof (((type*)SvANY((SV*)0))->last_member)
+       + sizeof (((type*)SvANY((const SV *)0))->last_member)
 
 static const struct body_details bodies_by_type[] = {
     { sizeof(HE), 0, 0, SVt_NULL,
@@ -1544,6 +1588,8 @@ Perl_sv_setiv(pTHX_ register SV *const sv, const IV i)
        break;
 
     case SVt_PVGV:
+       if (!isGV_with_GP(sv))
+           break;
     case SVt_PVAV:
     case SVt_PVHV:
     case SVt_PVCV:
@@ -1651,6 +1697,8 @@ Perl_sv_setnv(pTHX_ register SV *const sv, const NV num)
        break;
 
     case SVt_PVGV:
+       if (!isGV_with_GP(sv))
+           break;
     case SVt_PVAV:
     case SVt_PVHV:
     case SVt_PVCV:
@@ -1811,27 +1859,6 @@ S_glob_2number(pTHX_ GV * const gv)
     return TRUE;
 }
 
-STATIC char *
-S_glob_2pv(pTHX_ GV * const gv, STRLEN * const len)
-{
-    const U32 wasfake = SvFLAGS(gv) & SVf_FAKE;
-    SV *const buffer = sv_newmortal();
-
-    PERL_ARGS_ASSERT_GLOB_2PV;
-
-    /* FAKE globs can get coerced, so need to turn this off temporarily if it
-       is on.  */
-    SvFAKE_off(gv);
-    gv_efullname3(buffer, gv, "*");
-    SvFLAGS(gv) |= wasfake;
-
-    assert(SvPOK(buffer));
-    if (len) {
-       *len = SvCUR(buffer);
-    }
-    return SvPVX(buffer);
-}
-
 /* Actually, ISO C leaves conversion of UV to IV undefined, but
    until proven guilty, assume that things are not that bad... */
 
@@ -2226,7 +2253,7 @@ S_sv_2iuv_common(pTHX_ SV *const sv)
     }
     else  {
        if (isGV_with_GP(sv))
-           return glob_2number((GV *)sv);
+           return glob_2number(MUTABLE_GV(sv));
 
        if (!(SvFLAGS(sv) & SVs_PADTMP)) {
            if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
@@ -2597,7 +2624,7 @@ Perl_sv_2nv(pTHX_ register SV *const sv)
     }
     else  {
        if (isGV_with_GP(sv)) {
-           glob_2number((GV *)sv);
+           glob_2number(MUTABLE_GV(sv));
            return 0.0;
        }
 
@@ -2793,13 +2820,13 @@ Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags
                STRLEN len;
                char *retval;
                char *buffer;
-               const SV *const referent = (SV*)SvRV(sv);
+               SV *const referent = SvRV(sv);
 
                if (!referent) {
                    len = 7;
                    retval = buffer = savepvn("NULLREF", len);
                } else if (SvTYPE(referent) == SVt_REGEXP) {
-                   const REGEXP * const re = (REGEXP *)referent;
+                   REGEXP * const re = (REGEXP *)MUTABLE_PTR(referent);
                    I32 seen_evals = 0;
 
                    assert(re);
@@ -2911,7 +2938,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags
        *s = '\0';
     }
     else if (SvNOKp(sv)) {
-       const int olderrno = errno;
+       dSAVE_ERRNO;
        if (SvTYPE(sv) < SVt_PVNV)
            sv_upgrade(sv, SVt_PVNV);
        /* The +20 is pure guesswork.  Configure test needed. --jhi */
@@ -2925,7 +2952,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags
        {
            Gconvert(SvNVX(sv), NV_DIG, 0, s);
        }
-       errno = olderrno;
+       RESTORE_ERRNO;
 #ifdef FIXNEGATIVEZERO
         if (*s == '-' && s[1] == '0' && !s[2]) {
            s[0] = '0';
@@ -2939,8 +2966,23 @@ Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags
 #endif
     }
     else {
-       if (isGV_with_GP(sv))
-           return glob_2pv((GV *)sv, lp);
+       if (isGV_with_GP(sv)) {
+           GV *const gv = MUTABLE_GV(sv);
+           const U32 wasfake = SvFLAGS(gv) & SVf_FAKE;
+           SV *const buffer = sv_newmortal();
+
+           /* FAKE globs can get coerced, so need to turn this off temporarily
+              if it is on.  */
+           SvFAKE_off(gv);
+           gv_efullname3(buffer, gv, "*");
+           SvFLAGS(gv) |= wasfake;
+
+           assert(SvPOK(buffer));
+           if (lp) {
+               *lp = SvCUR(buffer);
+           }
+           return SvPVX(buffer);
+       }
 
        if (lp)
            *lp = 0;
@@ -3099,33 +3141,71 @@ Perl_sv_2bool(pTHX_ register SV *const sv)
 
 Converts the PV of an SV to its UTF-8-encoded form.
 Forces the SV to string form if it is not already.
+Will C<mg_get> on C<sv> if appropriate.
 Always sets the SvUTF8 flag to avoid future validity checks even
-if all the bytes have hibit clear.
+if the whole string is the same in UTF-8 as not.
+Returns the number of bytes in the converted string
 
 This is not as a general purpose byte encoding to Unicode interface:
 use the Encode extension for that.
 
+=for apidoc sv_utf8_upgrade_nomg
+
+Like sv_utf8_upgrade, but doesn't do magic on C<sv>
+
 =for apidoc sv_utf8_upgrade_flags
 
 Converts the PV of an SV to its UTF-8-encoded form.
 Forces the SV to string form if it is not already.
 Always sets the SvUTF8 flag to avoid future validity checks even
-if all the bytes have hibit clear. If C<flags> has C<SV_GMAGIC> bit set,
-will C<mg_get> on C<sv> if appropriate, else not. C<sv_utf8_upgrade> and
+if all the bytes are invariant in UTF-8. If C<flags> has C<SV_GMAGIC> bit set,
+will C<mg_get> on C<sv> if appropriate, else not.
+Returns the number of bytes in the converted string
+C<sv_utf8_upgrade> and
 C<sv_utf8_upgrade_nomg> are implemented in terms of this function.
 
 This is not as a general purpose byte encoding to Unicode interface:
 use the Encode extension for that.
 
 =cut
+
+The grow version is currently not externally documented.  It adds a parameter,
+extra, which is the number of unused bytes the string of 'sv' is guaranteed to
+have free after it upon return.  This allows the caller to reserve extra space
+that it intends to fill, to avoid extra grows.
+
+Also externally undocumented for the moment is the flag SV_FORCE_UTF8_UPGRADE,
+which can be used to tell this function to not first check to see if there are
+any characters that are different in UTF-8 (variant characters) which would
+force it to allocate a new string to sv, but to assume there are.  Typically
+this flag is used by a routine that has already parsed the string to find that
+there are such characters, and passes this information on so that the work
+doesn't have to be repeated.
+
+(One might think that the calling routine could pass in the position of the
+first such variant, so it wouldn't have to be found again.  But that is not the
+case, because typically when the caller is likely to use this flag, it won't be
+calling this routine unless it finds something that won't fit into a byte.
+Otherwise it tries to not upgrade and just use bytes.  But some things that
+do fit into a byte are variants in utf8, and the caller may not have been
+keeping track of these.)
+
+If the routine itself changes the string, it adds a trailing NUL.  Such a NUL
+isn't guaranteed due to having other routines do the work in some input cases,
+or if the input is already flagged as being in utf8.
+
+The speed of this could perhaps be improved for many cases if someone wanted to
+write a fast function that counts the number of variant characters in a string,
+especially if it could return the position of the first one.
+
 */
 
 STRLEN
-Perl_sv_utf8_upgrade_flags(pTHX_ register SV *const sv, const I32 flags)
+Perl_sv_utf8_upgrade_flags_grow(pTHX_ register SV *const sv, const I32 flags, STRLEN extra)
 {
     dVAR;
 
-    PERL_ARGS_ASSERT_SV_UTF8_UPGRADE_FLAGS;
+    PERL_ARGS_ASSERT_SV_UTF8_UPGRADE_FLAGS_GROW;
 
     if (sv == &PL_sv_undef)
        return 0;
@@ -3133,14 +3213,17 @@ Perl_sv_utf8_upgrade_flags(pTHX_ register SV *const sv, const I32 flags)
        STRLEN len = 0;
        if (SvREADONLY(sv) && (SvPOKp(sv) || SvIOKp(sv) || SvNOKp(sv))) {
            (void) sv_2pv_flags(sv,&len, flags);
-           if (SvUTF8(sv))
+           if (SvUTF8(sv)) {
+               if (extra) SvGROW(sv, SvCUR(sv) + extra);
                return len;
+           }
        } else {
            (void) SvPV_force(sv,len);
        }
     }
 
     if (SvUTF8(sv)) {
+       if (extra) SvGROW(sv, SvCUR(sv) + extra);
        return SvCUR(sv);
     }
 
@@ -3148,34 +3231,204 @@ Perl_sv_utf8_upgrade_flags(pTHX_ register SV *const sv, const I32 flags)
         sv_force_normal_flags(sv, 0);
     }
 
-    if (PL_encoding && !(flags & SV_UTF8_NO_ENCODING))
+    if (PL_encoding && !(flags & SV_UTF8_NO_ENCODING)) {
         sv_recode_to_utf8(sv, PL_encoding);
-    else { /* Assume Latin-1/EBCDIC */
+       if (extra) SvGROW(sv, SvCUR(sv) + extra);
+       return SvCUR(sv);
+    }
+
+    if (SvCUR(sv) > 0) { /* Assume Latin-1/EBCDIC */
        /* This function could be much more efficient if we
-        * had a FLAG in SVs to signal if there are any hibit
+        * had a FLAG in SVs to signal if there are any variant
         * chars in the PV.  Given that there isn't such a flag
-        * make the loop as fast as possible. */
-       const U8 * const s = (U8 *) SvPVX_const(sv);
-       const U8 * const e = (U8 *) SvEND(sv);
-       const U8 *t = s;
+        * make the loop as fast as possible (although there are certainly ways
+        * to speed this up, eg. through vectorization) */
+       U8 * s = (U8 *) SvPVX_const(sv);
+       U8 * e = (U8 *) SvEND(sv);
+       U8 *t = s;
+       STRLEN two_byte_count = 0;
        
+       if (flags & SV_FORCE_UTF8_UPGRADE) goto must_be_utf8;
+
+       /* See if really will need to convert to utf8.  We mustn't rely on our
+        * incoming SV being well formed and having a trailing '\0', as certain
+        * code in pp_formline can send us partially built SVs. */
+
        while (t < e) {
            const U8 ch = *t++;
-           /* Check for hi bit */
-           if (!NATIVE_IS_INVARIANT(ch)) {
-               STRLEN len = SvCUR(sv) + 1; /* Plus the \0 */
-               U8 * const recoded = bytes_to_utf8((U8*)s, &len);
-
-               SvPV_free(sv); /* No longer using what was there before. */
-               SvPV_set(sv, (char*)recoded);
-               SvCUR_set(sv, len - 1);
-               SvLEN_set(sv, len); /* No longer know the real size. */
-               break;
-           }
+           if (NATIVE_IS_INVARIANT(ch)) continue;
+
+           t--;    /* t already incremented; re-point to first variant */
+           two_byte_count = 1;
+           goto must_be_utf8;
        }
-       /* Mark as UTF-8 even if no hibit - saves scanning loop */
+
+       /* utf8 conversion not needed because all are invariants.  Mark as
+        * UTF-8 even if no variant - saves scanning loop */
        SvUTF8_on(sv);
+       return SvCUR(sv);
+
+must_be_utf8:
+
+       /* Here, the string should be converted to utf8, either because of an
+        * input flag (two_byte_count = 0), or because a character that
+        * requires 2 bytes was found (two_byte_count = 1).  t points either to
+        * the beginning of the string (if we didn't examine anything), or to
+        * the first variant.  In either case, everything from s to t - 1 will
+        * occupy only 1 byte each on output.
+        *
+        * There are two main ways to convert.  One is to create a new string
+        * and go through the input starting from the beginning, appending each
+        * converted value onto the new string as we go along.  It's probably
+        * best to allocate enough space in the string for the worst possible
+        * case rather than possibly running out of space and having to
+        * reallocate and then copy what we've done so far.  Since everything
+        * from s to t - 1 is invariant, the destination can be initialized
+        * with these using a fast memory copy
+        *
+        * The other way is to figure out exactly how big the string should be
+        * by parsing the entire input.  Then you don't have to make it big
+        * enough to handle the worst possible case, and more importantly, if
+        * the string you already have is large enough, you don't have to
+        * allocate a new string, you can copy the last character in the input
+        * string to the final position(s) that will be occupied by the
+        * converted string and go backwards, stopping at t, since everything
+        * before that is invariant.
+        *
+        * There are advantages and disadvantages to each method.
+        *
+        * In the first method, we can allocate a new string, do the memory
+        * copy from the s to t - 1, and then proceed through the rest of the
+        * string byte-by-byte.
+        *
+        * In the second method, we proceed through the rest of the input
+        * string just calculating how big the converted string will be.  Then
+        * there are two cases:
+        *  1)  if the string has enough extra space to handle the converted
+        *      value.  We go backwards through the string, converting until we
+        *      get to the position we are at now, and then stop.  If this
+        *      position is far enough along in the string, this method is
+        *      faster than the other method.  If the memory copy were the same
+        *      speed as the byte-by-byte loop, that position would be about
+        *      half-way, as at the half-way mark, parsing to the end and back
+        *      is one complete string's parse, the same amount as starting
+        *      over and going all the way through.  Actually, it would be
+        *      somewhat less than half-way, as it's faster to just count bytes
+        *      than to also copy, and we don't have the overhead of allocating
+        *      a new string, changing the scalar to use it, and freeing the
+        *      existing one.  But if the memory copy is fast, the break-even
+        *      point is somewhere after half way.  The counting loop could be
+        *      sped up by vectorization, etc, to move the break-even point
+        *      further towards the beginning.
+        *  2)  if the string doesn't have enough space to handle the converted
+        *      value.  A new string will have to be allocated, and one might
+        *      as well, given that, start from the beginning doing the first
+        *      method.  We've spent extra time parsing the string and in
+        *      exchange all we've gotten is that we know precisely how big to
+        *      make the new one.  Perl is more optimized for time than space,
+        *      so this case is a loser.
+        * So what I've decided to do is not use the 2nd method unless it is
+        * guaranteed that a new string won't have to be allocated, assuming
+        * the worst case.  I also decided not to put any more conditions on it
+        * than this, for now.  It seems likely that, since the worst case is
+        * twice as big as the unknown portion of the string (plus 1), we won't
+        * be guaranteed enough space, causing us to go to the first method,
+        * unless the string is short, or the first variant character is near
+        * the end of it.  In either of these cases, it seems best to use the
+        * 2nd method.  The only circumstance I can think of where this would
+        * be really slower is if the string had once had much more data in it
+        * than it does now, but there is still a substantial amount in it  */
+
+       {
+           STRLEN invariant_head = t - s;
+           STRLEN size = invariant_head + (e - t) * 2 + 1 + extra;
+           if (SvLEN(sv) < size) {
+
+               /* Here, have decided to allocate a new string */
+
+               U8 *dst;
+               U8 *d;
+
+               Newx(dst, size, U8);
+
+               /* If no known invariants at the beginning of the input string,
+                * set so starts from there.  Otherwise, can use memory copy to
+                * get up to where we are now, and then start from here */
+
+               if (invariant_head <= 0) {
+                   d = dst;
+               } else {
+                   Copy(s, dst, invariant_head, char);
+                   d = dst + invariant_head;
+               }
+
+               while (t < e) {
+                   const UV uv = NATIVE8_TO_UNI(*t++);
+                   if (UNI_IS_INVARIANT(uv))
+                       *d++ = (U8)UNI_TO_NATIVE(uv);
+                   else {
+                       *d++ = (U8)UTF8_EIGHT_BIT_HI(uv);
+                       *d++ = (U8)UTF8_EIGHT_BIT_LO(uv);
+                   }
+               }
+               *d = '\0';
+               SvPV_free(sv); /* No longer using pre-existing string */
+               SvPV_set(sv, (char*)dst);
+               SvCUR_set(sv, d - dst);
+               SvLEN_set(sv, size);
+           } else {
+
+               /* Here, have decided to get the exact size of the string.
+                * Currently this happens only when we know that there is
+                * guaranteed enough space to fit the converted string, so
+                * don't have to worry about growing.  If two_byte_count is 0,
+                * then t points to the first byte of the string which hasn't
+                * been examined yet.  Otherwise two_byte_count is 1, and t
+                * points to the first byte in the string that will expand to
+                * two.  Depending on this, start examining at t or 1 after t.
+                * */
+
+               U8 *d = t + two_byte_count;
+
+
+               /* Count up the remaining bytes that expand to two */
+
+               while (d < e) {
+                   const U8 chr = *d++;
+                   if (! NATIVE_IS_INVARIANT(chr)) two_byte_count++;
+               }
+
+               /* The string will expand by just the number of bytes that
+                * occupy two positions.  But we are one afterwards because of
+                * the increment just above.  This is the place to put the
+                * trailing NUL, and to set the length before we decrement */
+
+               d += two_byte_count;
+               SvCUR_set(sv, d - s);
+               *d-- = '\0';
+
+
+               /* Having decremented d, it points to the position to put the
+                * very last byte of the expanded string.  Go backwards through
+                * the string, copying and expanding as we go, stopping when we
+                * get to the part that is invariant the rest of the way down */
+
+               e--;
+               while (e >= t) {
+                   const U8 ch = NATIVE8_TO_UNI(*e--);
+                   if (UNI_IS_INVARIANT(ch)) {
+                       *d-- = UNI_TO_NATIVE(ch);
+                   } else {
+                       *d-- = (U8)UTF8_EIGHT_BIT_LO(ch);
+                       *d-- = (U8)UTF8_EIGHT_BIT_HI(ch);
+                   }
+               }
+           }
+       }
     }
+
+    /* Mark as UTF-8 even if no variant - saves scanning loop */
+    SvUTF8_on(sv);
     return SvCUR(sv);
 }
 
@@ -3183,7 +3436,8 @@ Perl_sv_utf8_upgrade_flags(pTHX_ register SV *const sv, const I32 flags)
 =for apidoc sv_utf8_downgrade
 
 Attempts to convert the PV of an SV from characters to bytes.
-If the PV contains a character beyond byte, this conversion will fail;
+If the PV contains a character that cannot fit
+in a byte, this conversion will fail;
 in this case, either returns false or, if C<fail_ok> is not
 true, croaks.
 
@@ -3245,7 +3499,7 @@ Perl_sv_utf8_encode(pTHX_ register SV *const sv)
         sv_force_normal_flags(sv, 0);
     }
     if (SvREADONLY(sv)) {
-       Perl_croak(aTHX_ PL_no_modify);
+       Perl_croak(aTHX_ "%s", PL_no_modify);
     }
     (void) sv_utf8_upgrade(sv);
     SvUTF8_off(sv);
@@ -3356,18 +3610,12 @@ S_glob_assign_glob(pTHX_ SV *const dstr, SV *const sstr, const int dtype)
        }
        GvSTASH(dstr) = GvSTASH(sstr);
        if (GvSTASH(dstr))
-           Perl_sv_add_backref(aTHX_ (SV*)GvSTASH(dstr), dstr);
-       gv_name_set((GV *)dstr, name, len, GV_ADD);
+           Perl_sv_add_backref(aTHX_ MUTABLE_SV(GvSTASH(dstr)), dstr);
+       gv_name_set(MUTABLE_GV(dstr), name, len, GV_ADD);
        SvFAKE_on(dstr);        /* can coerce to non-glob */
     }
 
-#ifdef GV_UNIQUE_CHECK
-    if (GvUNIQUE((GV*)dstr)) {
-       Perl_croak(aTHX_ PL_no_modify);
-    }
-#endif
-
-    if(GvGP((GV*)sstr)) {
+    if(GvGP(MUTABLE_GV(sstr))) {
         /* If source has method cache entry, clear it */
         if(GvCVGEN(sstr)) {
             SvREFCNT_dec(GvCV(sstr));
@@ -3376,20 +3624,20 @@ S_glob_assign_glob(pTHX_ SV *const dstr, SV *const sstr, const int dtype)
         }
         /* If source has a real method, then a method is
            going to change */
-        else if(GvCV((GV*)sstr)) {
+        else if(GvCV((const GV *)sstr)) {
             mro_changes = 1;
         }
     }
 
     /* If dest already had a real method, that's a change as well */
-    if(!mro_changes && GvGP((GV*)dstr) && GvCVu((GV*)dstr)) {
+    if(!mro_changes && GvGP(MUTABLE_GV(dstr)) && GvCVu((const GV *)dstr)) {
         mro_changes = 1;
     }
 
-    if(strEQ(GvNAME((GV*)dstr),"ISA"))
+    if(strEQ(GvNAME((const GV *)dstr),"ISA"))
         mro_changes = 2;
 
-    gp_free((GV*)dstr);
+    gp_free(MUTABLE_GV(dstr));
     isGV_with_GP_off(dstr);
     (void)SvOK_off(dstr);
     isGV_with_GP_on(dstr);
@@ -3420,16 +3668,10 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
 
     PERL_ARGS_ASSERT_GLOB_ASSIGN_REF;
 
-#ifdef GV_UNIQUE_CHECK
-    if (GvUNIQUE((GV*)dstr)) {
-       Perl_croak(aTHX_ PL_no_modify);
-    }
-#endif
-
     if (intro) {
        GvINTRO_off(dstr);      /* one-shot flag */
        GvLINE(dstr) = CopLINE(PL_curcop);
-       GvEGV(dstr) = (GV*)dstr;
+       GvEGV(dstr) = MUTABLE_GV(dstr);
     }
     GvMULTI_on(dstr);
     switch (stype) {
@@ -3450,13 +3692,14 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
        goto common;
     case SVt_PVFM:
        location = (SV **) &GvFORM(dstr);
+       goto common;
     default:
        location = &GvSV(dstr);
        import_flag = GVf_IMPORTED_SV;
     common:
        if (intro) {
            if (stype == SVt_PVCV) {
-               /*if (GvCVGEN(dstr) && (GvCV(dstr) != (CV*)sref || GvCVGEN(dstr))) {*/
+               /*if (GvCVGEN(dstr) && (GvCV(dstr) != (const CV *)sref || GvCVGEN(dstr))) {*/
                if (GvCVGEN(dstr)) {
                    SvREFCNT_dec(GvCV(dstr));
                    GvCV(dstr) = NULL;
@@ -3468,15 +3711,16 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
        else
            dref = *location;
        if (stype == SVt_PVCV && (*location != sref || GvCVGEN(dstr))) {
-           CV* const cv = (CV*)*location;
+           CV* const cv = MUTABLE_CV(*location);
            if (cv) {
-               if (!GvCVGEN((GV*)dstr) &&
+               if (!GvCVGEN((const GV *)dstr) &&
                    (CvROOT(cv) || CvXSUB(cv)))
                    {
                        /* Redefining a sub - warning is mandatory if
                           it was a const and its value changed. */
-                       if (CvCONST(cv) && CvCONST((CV*)sref)
-                           && cv_const_sv(cv) == cv_const_sv((CV*)sref)) {
+                       if (CvCONST(cv) && CvCONST((const CV *)sref)
+                           && cv_const_sv(cv)
+                           == cv_const_sv((const CV *)sref)) {
                            NOOP;
                            /* They are 2 constant subroutines generated from
                               the same constant. This probably means that
@@ -3487,20 +3731,21 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
                        }
                        else if (ckWARN(WARN_REDEFINE)
                                 || (CvCONST(cv)
-                                    && (!CvCONST((CV*)sref)
+                                    && (!CvCONST((const CV *)sref)
                                         || sv_cmp(cv_const_sv(cv),
-                                                  cv_const_sv((CV*)sref))))) {
+                                                  cv_const_sv((const CV *)
+                                                              sref))))) {
                            Perl_warner(aTHX_ packWARN(WARN_REDEFINE),
                                        (const char *)
                                        (CvCONST(cv)
                                         ? "Constant subroutine %s::%s redefined"
                                         : "Subroutine %s::%s redefined"),
-                                       HvNAME_get(GvSTASH((GV*)dstr)),
-                                       GvENAME((GV*)dstr));
+                                       HvNAME_get(GvSTASH((const GV *)dstr)),
+                                       GvENAME(MUTABLE_GV(dstr)));
                        }
                    }
                if (!intro)
-                   cv_ckproto_len(cv, (GV*)dstr,
+                   cv_ckproto_len(cv, (const GV *)dstr,
                                   SvPOK(sref) ? SvPVX_const(sref) : NULL,
                                   SvPOK(sref) ? SvCUR(sref) : 0);
            }
@@ -3553,7 +3798,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
     {
        /* need to nuke the magic */
        mg_free(dstr);
-       SvRMAGICAL_off(dstr);
     }
 
     /* There's a lot of redundancy below but we're going for speed here */
@@ -3707,7 +3951,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
            Perl_croak(aTHX_ "Cannot copy to %s", type);
     } else if (sflags & SVf_ROK) {
        if (isGV_with_GP(dstr) && dtype == SVt_PVGV
-           && SvTYPE(SvRV(sstr)) == SVt_PVGV) {
+           && SvTYPE(SvRV(sstr)) == SVt_PVGV && isGV_with_GP(SvRV(sstr))) {
            sstr = SvRV(sstr);
            if (sstr == dstr) {
                if (GvIMPORTED(dstr) != GVf_IMPORTED
@@ -3749,9 +3993,9 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
        }
        else {
            GV *gv = gv_fetchsv(sstr, GV_ADD, SVt_PVGV);
-           if (dstr != (SV*)gv) {
+           if (dstr != (const SV *)gv) {
                if (GvGP(dstr))
-                   gp_free((GV*)dstr);
+                   gp_free(MUTABLE_GV(dstr));
                GvGP(dstr) = gp_ref(GvGP(gv));
            }
        }
@@ -3813,7 +4057,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
             && ((flags & SV_COW_SHARED_HASH_KEYS)
                ? (!((sflags & CAN_COW_MASK) == CAN_COW_FLAGS
                     && (SvFLAGS(dstr) & CAN_COW_MASK) == CAN_COW_FLAGS
-                    && SvTYPE(sstr) >= SVt_PVIV))
+                    && SvTYPE(sstr) >= SVt_PVIV && SvTYPE(sstr) != SVt_PVFM))
                : 1)
 #endif
             ) {
@@ -3836,12 +4080,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
             }
 #ifdef PERL_OLD_COPY_ON_WRITE
             if (!isSwipe) {
-                /* I believe I should acquire a global SV mutex if
-                   it's a COW sv (not a shared hash key) to stop
-                   it going un copy-on-write.
-                   If the source SV has gone un copy on write between up there
-                   and down here, then (assert() that) it is of the correct
-                   form to make it copy on write again */
                 if ((sflags & (SVf_FAKE | SVf_READONLY))
                     != (SVf_FAKE | SVf_READONLY)) {
                     SvREADONLY_on(sstr);
@@ -3884,7 +4122,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
                 SvCUR_set(dstr, cur);
                 SvREADONLY_on(dstr);
                 SvFAKE_on(dstr);
-                /* Relesase a global SV mutex.  */
             }
             else
                 {      /* Passes the swipe test.  */
@@ -3940,7 +4177,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
            /* FAKE globs can get coerced, so need to turn this off
               temporarily if it is on.  */
            SvFAKE_off(sstr);
-           gv_efullname3(dstr, (GV *)sstr, "*");
+           gv_efullname3(dstr, MUTABLE_GV(sstr), "*");
            SvFLAGS(sstr) |= wasfake;
        }
        else
@@ -4288,7 +4525,6 @@ Perl_sv_force_normal_flags(pTHX_ register SV *const sv, const U32 flags)
 
 #ifdef PERL_OLD_COPY_ON_WRITE
     if (SvREADONLY(sv)) {
-        /* At this point I believe I should acquire a global SV mutex.  */
        if (SvFAKE(sv)) {
            const char * const pvx = SvPVX_const(sv);
            const STRLEN len = SvLEN(sv);
@@ -4328,8 +4564,7 @@ Perl_sv_force_normal_flags(pTHX_ register SV *const sv, const U32 flags)
             }
        }
        else if (IN_PERL_RUNTIME)
-           Perl_croak(aTHX_ PL_no_modify);
-        /* At this point I believe that I can drop the global SV mutex.  */
+           Perl_croak(aTHX_ "%s", PL_no_modify);
     }
 #else
     if (SvREADONLY(sv)) {
@@ -4346,7 +4581,7 @@ Perl_sv_force_normal_flags(pTHX_ register SV *const sv, const U32 flags)
            unshare_hek(SvSHARED_HEK_FROM_PV(pvx));
        }
        else if (IN_PERL_RUNTIME)
-           Perl_croak(aTHX_ PL_no_modify);
+           Perl_croak(aTHX_ "%s", PL_no_modify);
     }
 #endif
     if (SvROK(sv))
@@ -4377,6 +4612,7 @@ Perl_sv_chop(pTHX_ register SV *const sv, register const char *const ptr)
 #ifdef DEBUGGING
     const U8 *real_start;
 #endif
+    STRLEN max_delta;
 
     PERL_ARGS_ASSERT_SV_CHOP;
 
@@ -4387,8 +4623,17 @@ Perl_sv_chop(pTHX_ register SV *const sv, register const char *const ptr)
        /* Nothing to do.  */
        return;
     }
-    assert(ptr > SvPVX_const(sv));
+    /* SvPVX(sv) may move in SV_CHECK_THINKFIRST(sv), but after this line,
+       nothing uses the value of ptr any more.  */
+    max_delta = SvLEN(sv) ? SvLEN(sv) : SvCUR(sv);
+    if (ptr <= SvPVX_const(sv))
+       Perl_croak(aTHX_ "panic: sv_chop ptr=%p, start=%p, end=%p",
+                  ptr, SvPVX_const(sv), SvPVX_const(sv) + max_delta);
     SV_CHECK_THINKFIRST(sv);
+    if (delta > max_delta)
+       Perl_croak(aTHX_ "panic: sv_chop ptr=%p (was %p), start=%p, end=%p",
+                  SvPVX_const(sv) + delta, ptr, SvPVX_const(sv),
+                  SvPVX_const(sv) + max_delta);
 
     if (!SvOOK(sv)) {
        if (!SvLEN(sv)) { /* make copy of shared string */
@@ -4525,7 +4770,8 @@ Perl_sv_catsv_flags(pTHX_ SV *const dsv, register SV *const ssv, const I32 flags
                    spv = SvPV_const(csv, slen);
                }
                else
-                   sv_utf8_upgrade_nomg(dsv);
+                   /* Leave enough space for the cat that's about to happen */
+                   sv_utf8_upgrade_flags_grow(dsv, 0, slen);
            }
            sv_catpvn_nomg(dsv, spv, slen);
        }
@@ -4659,9 +4905,9 @@ Perl_sv_magicext(pTHX_ SV *const sv, SV *const obj, const int how,
        how == PERL_MAGIC_arylen ||
        how == PERL_MAGIC_symtab ||
        (SvTYPE(obj) == SVt_PVGV &&
-           (GvSV(obj) == sv || GvHV(obj) == (HV*)sv || GvAV(obj) == (AV*)sv ||
-           GvCV(obj) == (CV*)sv || GvIOp(obj) == (IO*)sv ||
-           GvFORM(obj) == (CV*)sv)))
+           (GvSV(obj) == sv || GvHV(obj) == (const HV *)sv
+            || GvAV(obj) == (const AV *)sv || GvCV(obj) == (const CV *)sv
+            || GvIOp(obj) == (const IO *)sv || GvFORM(obj) == (const CV *)sv)))
     {
        mg->mg_obj = obj;
     }
@@ -4679,7 +4925,7 @@ Perl_sv_magicext(pTHX_ SV *const sv, SV *const obj, const int how,
     */
 
     if (how == PERL_MAGIC_tiedscalar && SvTYPE(sv) == SVt_PVIO &&
-        obj && SvROK(obj) && GvIO(SvRV(obj)) == (IO*)sv)
+        obj && SvROK(obj) && GvIO(SvRV(obj)) == (const IO *)sv)
     {
       sv_rvweaken(obj);
     }
@@ -4689,9 +4935,13 @@ Perl_sv_magicext(pTHX_ SV *const sv, SV *const obj, const int how,
     if (name) {
        if (namlen > 0)
            mg->mg_ptr = savepvn(name, namlen);
-       else if (namlen == HEf_SVKEY)
-           mg->mg_ptr = (char*)SvREFCNT_inc_simple_NN((SV*)name);
-       else
+       else if (namlen == HEf_SVKEY) {
+           /* Yes, this is casting away const. This is only for the case of
+              HEf_SVKEY. I think we need to document this abberation of the
+              constness of the API, rather than making name non-const, as
+              that change propagating outwards a long way.  */
+           mg->mg_ptr = (char*)SvREFCNT_inc_simple_NN((SV *)name);
+       } else
            mg->mg_ptr = (char *) name;
     }
     mg->mg_virtual = (MGVTBL *) vtable;
@@ -4745,7 +4995,7 @@ Perl_sv_magic(pTHX_ register SV *const sv, SV *const obj, const int how,
            && how != PERL_MAGIC_backref
           )
        {
-           Perl_croak(aTHX_ PL_no_modify);
+           Perl_croak(aTHX_ "%s", PL_no_modify);
        }
     }
     if (SvMAGICAL(sv) || (how == PERL_MAGIC_taint && SvTYPE(sv) >= SVt_PVMG)) {
@@ -4926,7 +5176,7 @@ Perl_sv_unmagic(pTHX_ SV *const sv, const int type)
                if (mg->mg_len > 0)
                    Safefree(mg->mg_ptr);
                else if (mg->mg_len == HEf_SVKEY)
-                   SvREFCNT_dec((SV*)mg->mg_ptr);
+                   SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr));
                else if (mg->mg_type == PERL_MAGIC_utf8)
                    Safefree(mg->mg_ptr);
             }
@@ -4985,6 +5235,24 @@ Perl_sv_rvweaken(pTHX_ SV *const sv)
  * back-reference to sv onto the array associated with the backref magic.
  */
 
+/* A discussion about the backreferences array and its refcount:
+ *
+ * The AV holding the backreferences is pointed to either as the mg_obj of
+ * PERL_MAGIC_backref, or in the specific case of a HV that has the hv_aux
+ * structure, from the xhv_backreferences field. (A HV without hv_aux will
+ * have the standard magic instead.) The array is created with a refcount
+ * of 2. This means that if during global destruction the array gets
+ * picked on first to have its refcount decremented by the random zapper,
+ * it won't actually be freed, meaning it's still theere for when its
+ * parent gets freed.
+ * When the parent SV is freed, in the case of magic, the magic is freed,
+ * Perl_magic_killbackrefs is called which decrements one refcount, then
+ * mg_obj is freed which kills the second count.
+ * In the vase of a HV being freed, one ref is removed by
+ * Perl_hv_kill_backrefs, the other by Perl_sv_kill_backrefs, which it
+ * calls.
+ */
+
 void
 Perl_sv_add_backref(pTHX_ SV *const tsv, SV *const sv)
 {
@@ -4994,7 +5262,7 @@ Perl_sv_add_backref(pTHX_ SV *const tsv, SV *const sv)
     PERL_ARGS_ASSERT_SV_ADD_BACKREF;
 
     if (SvTYPE(tsv) == SVt_PVHV) {
-       AV **const avp = Perl_hv_backreferences_p(aTHX_ (HV*)tsv);
+       AV **const avp = Perl_hv_backreferences_p(aTHX_ MUTABLE_HV(tsv));
 
        av = *avp;
        if (!av) {
@@ -5003,7 +5271,7 @@ Perl_sv_add_backref(pTHX_ SV *const tsv, SV *const sv)
 
            if (mg) {
                /* Aha. They've got it stowed in magic.  Bring it back.  */
-               av = (AV*)mg->mg_obj;
+               av = MUTABLE_AV(mg->mg_obj);
                /* Stop mg_free decreasing the refernce count.  */
                mg->mg_obj = NULL;
                /* Stop mg_free even calling the destructor, given that
@@ -5013,7 +5281,7 @@ Perl_sv_add_backref(pTHX_ SV *const tsv, SV *const sv)
            } else {
                av = newAV();
                AvREAL_off(av);
-               SvREFCNT_inc_simple_void(av);
+               SvREFCNT_inc_simple_void(av); /* see discussion above */
            }
            *avp = av;
        }
@@ -5021,14 +5289,12 @@ Perl_sv_add_backref(pTHX_ SV *const tsv, SV *const sv)
        const MAGIC *const mg
            = SvMAGICAL(tsv) ? mg_find(tsv, PERL_MAGIC_backref) : NULL;
        if (mg)
-           av = (AV*)mg->mg_obj;
+           av = MUTABLE_AV(mg->mg_obj);
        else {
            av = newAV();
            AvREAL_off(av);
-           sv_magic(tsv, (SV*)av, PERL_MAGIC_backref, NULL, 0);
-           /* av now has a refcnt of 2, which avoids it getting freed
-            * before us during global cleanup. The extra ref is removed
-            * by magic_killbackrefs() when tsv is being freed */
+           sv_magic(tsv, MUTABLE_SV(av), PERL_MAGIC_backref, NULL, 0);
+           /* av now has a refcnt of 2; see discussion above */
        }
     }
     if (AvFILLp(av) >= AvMAX(av)) {
@@ -5052,7 +5318,7 @@ S_sv_del_backref(pTHX_ SV *const tsv, SV *const sv)
     PERL_ARGS_ASSERT_SV_DEL_BACKREF;
 
     if (SvTYPE(tsv) == SVt_PVHV && SvOOK(tsv)) {
-       av = *Perl_hv_backreferences_p(aTHX_ (HV*)tsv);
+       av = *Perl_hv_backreferences_p(aTHX_ MUTABLE_HV(tsv));
        /* We mustn't attempt to "fix up" the hash here by moving the
           backreference array back to the hv_aux structure, as that is stored
           in the main HvARRAY(), and hfreentries assumes that no-one
@@ -5062,16 +5328,13 @@ S_sv_del_backref(pTHX_ SV *const tsv, SV *const sv)
        const MAGIC *const mg
            = SvMAGICAL(tsv) ? mg_find(tsv, PERL_MAGIC_backref) : NULL;
        if (mg)
-           av = (AV *)mg->mg_obj;
+           av = MUTABLE_AV(mg->mg_obj);
     }
-    if (!av) {
-       if (PL_in_clean_all)
-           return;
+
+    if (!av)
        Perl_croak(aTHX_ "panic: del_backref");
-    }
 
-    if (SvIS_FREED(av))
-       return;
+    assert(!SvIS_FREED(av));
 
     svp = AvARRAY(av);
     /* We shouldn't be in here more than once, but for paranoia reasons lets
@@ -5101,9 +5364,8 @@ Perl_sv_kill_backrefs(pTHX_ SV *const sv, AV *const av)
     PERL_ARGS_ASSERT_SV_KILL_BACKREFS;
     PERL_UNUSED_ARG(sv);
 
-    /* Not sure why the av can get freed ahead of its sv, but somehow it does
-       in ext/B/t/bytecode.t test 15 (involving print <DATA>)  */
-    if (svp && !SvIS_FREED(av)) {
+    assert(!svp || !SvIS_FREED(av));
+    if (svp) {
        SV *const *const last = svp + AvFILLp(av);
 
        while (svp <= last) {
@@ -5119,7 +5381,7 @@ Perl_sv_kill_backrefs(pTHX_ SV *const sv, AV *const av)
                           SvTYPE(referrer) == SVt_PVLV) {
                    /* You lookin' at me?  */
                    assert(GvSTASH(referrer));
-                   assert(GvSTASH(referrer) == (HV*)sv);
+                   assert(GvSTASH(referrer) == (const HV *)sv);
                    GvSTASH(referrer) = 0;
                } else {
                    Perl_croak(aTHX_
@@ -5367,7 +5629,14 @@ Perl_sv_clear(pTHX_ register SV *const sv)
                CV* destructor;
                stash = SvSTASH(sv);
                destructor = StashHANDLER(stash,DESTROY);
-               if (destructor) {
+               if (destructor
+                       /* A constant subroutine can have no side effects, so
+                          don't bother calling it.  */
+                       && !CvCONST(destructor)
+                       /* Don't bother calling an empty destructor */
+                       && (CvISXSUB(destructor)
+                       || CvSTART(destructor)->op_next->op_type != OP_LEAVESUB))
+               {
                    SV* const tmpref = newRV(sv);
                    SvREADONLY_on(tmpref);   /* DESTROY() could be naughty */
                    ENTER;
@@ -5376,7 +5645,7 @@ Perl_sv_clear(pTHX_ register SV *const sv)
                    PUSHMARK(SP);
                    PUSHs(tmpref);
                    PUTBACK;
-                   call_sv((SV*)destructor, G_DISCARD|G_EVAL|G_KEEPERR|G_VOID);
+                   call_sv(MUTABLE_SV(destructor), G_DISCARD|G_EVAL|G_KEEPERR|G_VOID);
                
                
                    POPSTACK;
@@ -5425,7 +5694,7 @@ Perl_sv_clear(pTHX_ register SV *const sv)
            IoIFP(sv) != PerlIO_stdout() &&
            IoIFP(sv) != PerlIO_stderr())
        {
-           io_close((IO*)sv, FALSE);
+           io_close(MUTABLE_IO(sv), FALSE);
        }
        if (IoDIRP(sv) && !(IoFLAGS(sv) & IOf_FAKE_DIRP))
            PerlDir_close(IoDIRP(sv));
@@ -5440,18 +5709,21 @@ Perl_sv_clear(pTHX_ register SV *const sv)
        goto freescalar;
     case SVt_PVCV:
     case SVt_PVFM:
-       cv_undef((CV*)sv);
+       cv_undef(MUTABLE_CV(sv));
        goto freescalar;
     case SVt_PVHV:
-       Perl_hv_kill_backrefs(aTHX_ (HV*)sv);
-       hv_undef((HV*)sv);
+       if (PL_last_swash_hv == (const HV *)sv) {
+           PL_last_swash_hv = NULL;
+       }
+       Perl_hv_kill_backrefs(aTHX_ MUTABLE_HV(sv));
+       hv_undef(MUTABLE_HV(sv));
        break;
     case SVt_PVAV:
-       if (PL_comppad == (AV*)sv) {
+       if (PL_comppad == MUTABLE_AV(sv)) {
            PL_comppad = NULL;
            PL_curpad = NULL;
        }
-       av_undef((AV*)sv);
+       av_undef(MUTABLE_AV(sv));
        break;
     case SVt_PVLV:
        if (LvTYPE(sv) == 'T') { /* for tie: return HE to pool */
@@ -5463,20 +5735,21 @@ Perl_sv_clear(pTHX_ register SV *const sv)
            SvREFCNT_dec(LvTARG(sv));
     case SVt_PVGV:
        if (isGV_with_GP(sv)) {
-            if(GvCVu((GV*)sv) && (stash = GvSTASH((GV*)sv)) && HvNAME_get(stash))
+            if(GvCVu((const GV *)sv) && (stash = GvSTASH(MUTABLE_GV(sv)))
+              && HvNAME_get(stash))
                 mro_method_changed_in(stash);
-           gp_free((GV*)sv);
+           gp_free(MUTABLE_GV(sv));
            if (GvNAME_HEK(sv))
                unshare_hek(GvNAME_HEK(sv));
            /* If we're in a stash, we don't own a reference to it. However it does
               have a back reference to us, which needs to be cleared.  */
            if (!SvVALID(sv) && (stash = GvSTASH(sv)))
-                   sv_del_backref((SV*)stash, sv);
+                   sv_del_backref(MUTABLE_SV(stash), sv);
        }
        /* FIXME. There are probably more unreferenced pointers to SVs in the
           interpreter struct that we should check and tidy in a similar
           fashion to this:  */
-       if ((GV*)sv == PL_last_in_gv)
+       if ((const GV *)sv == PL_last_in_gv)
            PL_last_in_gv = NULL;
     case SVt_PVMG:
     case SVt_PVNV:
@@ -5500,8 +5773,6 @@ Perl_sv_clear(pTHX_ register SV *const sv)
 #ifdef PERL_OLD_COPY_ON_WRITE
        else if (SvPVX_const(sv)) {
             if (SvIsCOW(sv)) {
-                /* I believe I need to grab the global SV mutex here and
-                   then recheck the COW status.  */
                 if (DEBUG_C_TEST) {
                     PerlIO_printf(Perl_debug_log, "Copy on write: clear\n");
                     sv_dump(sv);
@@ -5512,7 +5783,6 @@ Perl_sv_clear(pTHX_ register SV *const sv)
                    unshare_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sv)));
                }
 
-                /* And drop it here.  */
                 SvFAKE_off(sv);
             } else if (SvLEN(sv)) {
                 Safefree(SvPVX_const(sv));
@@ -5680,7 +5950,7 @@ UTF-8 bytes as a single character. Handles magic and type coercion.
 */
 
 /*
- * The length is cached in PERL_UTF8_magic, in the mg_len field.  Also the
+ * The length is cached in PERL_MAGIC_utf8, in the mg_len field.  Also the
  * mg_ptr is used, by sv_pos_u2b() and sv_pos_b2u() - see the comments below.
  * (Note that the mg_len is not the length of the mg_ptr field.
  * This allows the cache to store the character length of the string without
@@ -5909,7 +6179,7 @@ type coercion.
 
 /*
  * sv_pos_u2b() uses, like sv_pos_b2u(), the mg_ptr of the potential
- * PERL_UTF8_magic of the sv to store the mapping between UTF-8 and
+ * PERL_MAGIC_utf8 of the sv to store the mapping between UTF-8 and
  * byte offsets.  See also the comments of S_utf8_mg_pos_cache_update().
  *
  */
@@ -6152,7 +6422,7 @@ Handles magic and type coercion.
 
 /*
  * sv_pos_b2u() uses, like sv_pos_u2b(), the mg_ptr of the potential
- * PERL_UTF8_magic of the sv to store the mapping between UTF-8 and
+ * PERL_MAGIC_utf8 of the sv to store the mapping between UTF-8 and
  * byte offsets.
  *
  */
@@ -6636,6 +6906,9 @@ Perl_sv_gets(pTHX_ register SV *const sv, register PerlIO *const fp, I32 append)
       I32 bytesread;
       char *buffer;
       U32 recsize;
+#ifdef VMS
+      int fd;
+#endif
 
       /* Grab the size of the record we're getting */
       recsize = SvUV(SvRV(PL_rs)); /* RsRECORD() guarantees > 0. */
@@ -6647,13 +6920,19 @@ Perl_sv_gets(pTHX_ register SV *const sv, register PerlIO *const fp, I32 append)
       /* doing, but we've got no other real choice - except avoid stdio
          as implementation - perhaps write a :vms layer ?
        */
-      bytesread = PerlLIO_read(PerlIO_fileno(fp), buffer, recsize);
+      fd = PerlIO_fileno(fp);
+      if (fd == -1) { /* in-memory file from PerlIO::Scalar */
+          bytesread = PerlIO_read(fp, buffer, recsize);
+      }
+      else {
+          bytesread = PerlLIO_read(fd, buffer, recsize);
+      }
 #else
       bytesread = PerlIO_read(fp, buffer, recsize);
 #endif
       if (bytesread < 0)
          bytesread = 0;
-      SvCUR_set(sv, bytesread += append);
+      SvCUR_set(sv, bytesread + append);
       buffer[bytesread] = '\0';
       goto return_string_or_null;
     }
@@ -6938,7 +7217,7 @@ Perl_sv_inc(pTHX_ register SV *const sv)
            sv_force_normal_flags(sv, 0);
        if (SvREADONLY(sv)) {
            if (IN_PERL_RUNTIME)
-               Perl_croak(aTHX_ PL_no_modify);
+               Perl_croak(aTHX_ "%s", PL_no_modify);
        }
        if (SvROK(sv)) {
            IV i;
@@ -7101,7 +7380,7 @@ Perl_sv_dec(pTHX_ register SV *const sv)
            sv_force_normal_flags(sv, 0);
        if (SvREADONLY(sv)) {
            if (IN_PERL_RUNTIME)
-               Perl_croak(aTHX_ PL_no_modify);
+               Perl_croak(aTHX_ "%s", PL_no_modify);
        }
        if (SvROK(sv)) {
            IV i;
@@ -7461,6 +7740,8 @@ Perl_newSVpvn_share(pTHX_ const char *src, I32 len, U32 hash)
     if (!hash)
        PERL_HASH(hash, src, len);
     new_SV(sv);
+    /* The logic for this is inlined in S_mro_get_linear_isa_dfs(), so if it
+       changes here, update it there too.  */
     sv_upgrade(sv, SVt_PV);
     SvPV_set(sv, sharepvn(src, is_utf8?-len:len, hash));
     SvCUR_set(sv, len);
@@ -7704,7 +7985,7 @@ Perl_sv_reset(pTHX_ register const char *s, HV *const stash)
        return;
 
     if (!*s) {         /* reset ?? searches */
-       MAGIC * const mg = mg_find((SV *)stash, PERL_MAGIC_symtab);
+       MAGIC * const mg = mg_find((const SV *)stash, PERL_MAGIC_symtab);
        if (mg) {
            const U32 count = mg->mg_len / sizeof(PMOP**);
            PMOP **pmp = (PMOP**) mg->mg_ptr;
@@ -7749,7 +8030,7 @@ Perl_sv_reset(pTHX_ register const char *s, HV *const stash)
 
                if (!todo[(U8)*HeKEY(entry)])
                    continue;
-               gv = (GV*)HeVAL(entry);
+               gv = MUTABLE_GV(HeVAL(entry));
                sv = GvSV(gv);
                if (sv) {
                    if (SvTHINKFIRST(sv)) {
@@ -7806,14 +8087,17 @@ Perl_sv_2io(pTHX_ SV *const sv)
 
     switch (SvTYPE(sv)) {
     case SVt_PVIO:
-       io = (IO*)sv;
+       io = MUTABLE_IO(sv);
        break;
     case SVt_PVGV:
-       gv = (GV*)sv;
-       io = GvIO(gv);
-       if (!io)
-           Perl_croak(aTHX_ "Bad filehandle: %s", GvNAME(gv));
-       break;
+       if (isGV_with_GP(sv)) {
+           gv = MUTABLE_GV(sv);
+           io = GvIO(gv);
+           if (!io)
+               Perl_croak(aTHX_ "Bad filehandle: %s", GvNAME(gv));
+           break;
+       }
+       /* FALL THROUGH */
     default:
        if (!SvOK(sv))
            Perl_croak(aTHX_ PL_no_usym, "filehandle");
@@ -7859,47 +8143,52 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **const st, GV **const gvp, const I32 lref)
     case SVt_PVCV:
        *st = CvSTASH(sv);
        *gvp = NULL;
-       return (CV*)sv;
+       return MUTABLE_CV(sv);
     case SVt_PVHV:
     case SVt_PVAV:
        *st = NULL;
        *gvp = NULL;
        return NULL;
     case SVt_PVGV:
-       gv = (GV*)sv;
-       *gvp = gv;
-       *st = GvESTASH(gv);
-       goto fix_gv;
+       if (isGV_with_GP(sv)) {
+           gv = MUTABLE_GV(sv);
+           *gvp = gv;
+           *st = GvESTASH(gv);
+           goto fix_gv;
+       }
+       /* FALL THROUGH */
 
     default:
-       SvGETMAGIC(sv);
        if (SvROK(sv)) {
            SV * const *sp = &sv;       /* Used in tryAMAGICunDEREF macro. */
+           SvGETMAGIC(sv);
            tryAMAGICunDEREF(to_cv);
 
            sv = SvRV(sv);
            if (SvTYPE(sv) == SVt_PVCV) {
-               cv = (CV*)sv;
+               cv = MUTABLE_CV(sv);
                *gvp = NULL;
                *st = CvSTASH(cv);
                return cv;
            }
-           else if(isGV(sv))
-               gv = (GV*)sv;
+           else if(isGV_with_GP(sv))
+               gv = MUTABLE_GV(sv);
            else
                Perl_croak(aTHX_ "Not a subroutine reference");
        }
-       else if (isGV(sv))
-           gv = (GV*)sv;
+       else if (isGV_with_GP(sv)) {
+           SvGETMAGIC(sv);
+           gv = MUTABLE_GV(sv);
+       }
        else
-           gv = gv_fetchsv(sv, lref, SVt_PVCV);
+           gv = gv_fetchsv(sv, lref, SVt_PVCV); /* Calls get magic */
        *gvp = gv;
        if (!gv) {
            *st = NULL;
            return NULL;
        }
        /* Some flags to gv_fetchsv mean don't really create the GV  */
-       if (SvTYPE(gv) != SVt_PVGV) {
+       if (!isGV_with_GP(gv)) {
            *st = NULL;
            return NULL;
        }
@@ -8114,7 +8403,8 @@ Perl_sv_reftype(pTHX_ const SV *const sv, const int ob)
        case SVt_PVAV:          return "ARRAY";
        case SVt_PVHV:          return "HASH";
        case SVt_PVCV:          return "CODE";
-       case SVt_PVGV:          return "GLOB";
+       case SVt_PVGV:          return (char *) (isGV_with_GP(sv)
+                                   ? "GLOB" : "SCALAR");
        case SVt_PVFM:          return "FORMAT";
        case SVt_PVIO:          return "IO";
        case SVt_BIND:          return "BIND";
@@ -8142,7 +8432,7 @@ Perl_sv_isobject(pTHX_ SV *sv)
     SvGETMAGIC(sv);
     if (!SvROK(sv))
        return 0;
-    sv = (SV*)SvRV(sv);
+    sv = SvRV(sv);
     if (!SvOBJECT(sv))
        return 0;
     return 1;
@@ -8170,7 +8460,7 @@ Perl_sv_isa(pTHX_ SV *sv, const char *const name)
     SvGETMAGIC(sv);
     if (!SvROK(sv))
        return 0;
-    sv = (SV*)SvRV(sv);
+    sv = SvRV(sv);
     if (!SvOBJECT(sv))
        return 0;
     hvname = HvNAME_get(SvSTASH(sv));
@@ -8376,7 +8666,7 @@ Perl_sv_bless(pTHX_ SV *const sv, HV *const stash)
        if (SvIsCOW(tmpRef))
            sv_force_normal_flags(tmpRef, 0);
        if (SvREADONLY(tmpRef))
-           Perl_croak(aTHX_ PL_no_modify);
+           Perl_croak(aTHX_ "%s", PL_no_modify);
        if (SvOBJECT(tmpRef)) {
            if (SvTYPE(tmpRef) != SVt_PVIO)
                --PL_sv_objcount;
@@ -8387,7 +8677,7 @@ Perl_sv_bless(pTHX_ SV *const sv, HV *const stash)
     if (SvTYPE(tmpRef) != SVt_PVIO)
        ++PL_sv_objcount;
     SvUPGRADE(tmpRef, SVt_PVMG);
-    SvSTASH_set(tmpRef, (HV*)SvREFCNT_inc_simple(stash));
+    SvSTASH_set(tmpRef, MUTABLE_HV(SvREFCNT_inc_simple(stash)));
 
     if (Gv_AMG(stash))
        SvAMAGIC_on(sv);
@@ -8418,15 +8708,16 @@ S_sv_unglob(pTHX_ SV *const sv)
 
     assert(SvTYPE(sv) == SVt_PVGV);
     SvFAKE_off(sv);
-    gv_efullname3(temp, (GV *) sv, "*");
+    gv_efullname3(temp, MUTABLE_GV(sv), "*");
 
     if (GvGP(sv)) {
-        if(GvCVu((GV*)sv) && (stash = GvSTASH((GV*)sv)) && HvNAME_get(stash))
+        if(GvCVu((const GV *)sv) && (stash = GvSTASH(MUTABLE_GV(sv)))
+          && HvNAME_get(stash))
             mro_method_changed_in(stash);
-       gp_free((GV*)sv);
+       gp_free(MUTABLE_GV(sv));
     }
     if (GvSTASH(sv)) {
-       sv_del_backref((SV*)GvSTASH(sv), sv);
+       sv_del_backref(MUTABLE_SV(GvSTASH(sv)), sv);
        GvSTASH(sv) = NULL;
     }
     GvMULTI_off(sv);
@@ -8820,7 +9111,7 @@ Perl_sv_vsetpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
 {
     PERL_ARGS_ASSERT_SV_VSETPVFN;
 
-    sv_setpvn(sv, "", 0);
+    sv_setpvs(sv, "");
     sv_vcatpvfn(sv, pat, patlen, args, svargs, svmax, maybe_tainted);
 }
 
@@ -8940,7 +9231,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
     }
     if (args && patlen == 3 && pat[0] == '%' &&
                pat[1] == '-' && pat[2] == 'p') {
-       argsv = (SV*)va_arg(*args, void*);
+       argsv = MUTABLE_SV(va_arg(*args, void*));
        sv_catsv(sv, argsv);
        return;
     }
@@ -9015,6 +9306,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
        STRLEN esignlen = 0;
 
        const char *eptr = NULL;
+       const char *fmtstart;
        STRLEN elen = 0;
        SV *vecsv = NULL;
        const U8 *vecstr = NULL;
@@ -9055,6 +9347,8 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
        if (q++ >= patend)
            break;
 
+       fmtstart = q;
+
 /*
     We allow format specification elements in this order:
        \d+\$              explicit format parameter index
@@ -9097,7 +9391,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
                        precis = n;
                        has_precis = TRUE;
                    }
-                   argsv = (SV*)va_arg(*args, void*);
+                   argsv = MUTABLE_SV(va_arg(*args, void*));
                    eptr = SvPV_const(argsv, elen);
                    if (DO_UTF8(argsv))
                        is_utf8 = TRUE;
@@ -9217,7 +9511,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
                 */
                if (sv_derived_from(vecsv, "version")) {
                    char *version = savesvpv(vecsv);
-                   if ( hv_exists((HV*)SvRV(vecsv), "alpha", 5 ) ) {
+                   if ( hv_exists(MUTABLE_HV(SvRV(vecsv)), "alpha", 5 ) ) {
                        Perl_warner(aTHX_ packWARN(WARN_INTERNAL),
                        "vector argument not supported with alpha versions");
                        goto unknown;
@@ -9371,12 +9665,6 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
            if (args) {
                eptr = va_arg(*args, char*);
                if (eptr)
-#ifdef MACOS_TRADITIONAL
-                 /* On MacOS, %#s format is used for Pascal strings */
-                 if (alt)
-                   elen = *eptr++;
-                 else
-#endif
                    elen = strlen(eptr);
                else {
                    eptr = (char *)nullstr;
@@ -9450,8 +9738,11 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
                case 'l':       iv = va_arg(*args, long); break;
                case 'V':       iv = va_arg(*args, IV); break;
                default:        iv = va_arg(*args, int); break;
+               case 'q':
 #ifdef HAS_QUAD
-               case 'q':       iv = va_arg(*args, Quad_t); break;
+                               iv = va_arg(*args, Quad_t); break;
+#else
+                               goto unknown;
 #endif
                }
            }
@@ -9462,8 +9753,11 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
                case 'l':       iv = (long)tiv; break;
                case 'V':
                default:        iv = tiv; break;
+               case 'q':
 #ifdef HAS_QUAD
-               case 'q':       iv = (Quad_t)tiv; break;
+                               iv = (Quad_t)tiv; break;
+#else
+                               goto unknown;
 #endif
                }
            }
@@ -9535,8 +9829,11 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
                case 'l':  uv = va_arg(*args, unsigned long); break;
                case 'V':  uv = va_arg(*args, UV); break;
                default:   uv = va_arg(*args, unsigned); break;
+               case 'q':
 #ifdef HAS_QUAD
-               case 'q':  uv = va_arg(*args, Uquad_t); break;
+                          uv = va_arg(*args, Uquad_t); break;
+#else
+                          goto unknown;
 #endif
                }
            }
@@ -9547,8 +9844,11 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
                case 'l':       uv = (unsigned long)tuv; break;
                case 'V':
                default:        uv = tuv; break;
+               case 'q':
 #ifdef HAS_QUAD
-               case 'q':       uv = (Uquad_t)tuv; break;
+                               uv = (Uquad_t)tuv; break;
+#else
+                               goto unknown;
 #endif
                }
            }
@@ -9834,8 +10134,11 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
                default:        *(va_arg(*args, int*)) = i; break;
                case 'l':       *(va_arg(*args, long*)) = i; break;
                case 'V':       *(va_arg(*args, IV*)) = i; break;
+               case 'q':
 #ifdef HAS_QUAD
-               case 'q':       *(va_arg(*args, Quad_t*)) = i; break;
+                               *(va_arg(*args, Quad_t*)) = i; break;
+#else
+                               goto unknown;
 #endif
                }
            }
@@ -9854,16 +10157,22 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
                SV * const msg = sv_newmortal();
                Perl_sv_setpvf(aTHX_ msg, "Invalid conversion in %sprintf: ",
                          (PL_op->op_type == OP_PRTF) ? "" : "s");
-               if (c) {
-                   if (isPRINT(c))
-                       Perl_sv_catpvf(aTHX_ msg,
-                                      "\"%%%c\"", c & 0xFF);
-                   else
-                       Perl_sv_catpvf(aTHX_ msg,
-                                      "\"%%\\%03"UVof"\"",
-                                      (UV)c & 0xFF);
-               } else
+               if (fmtstart < patend) {
+                   const char * const fmtend = q < patend ? q : patend;
+                   const char * f;
+                   sv_catpvs(msg, "\"%");
+                   for (f = fmtstart; f < fmtend; f++) {
+                       if (isPRINT(*f)) {
+                           sv_catpvn(msg, f, 1);
+                       } else {
+                           Perl_sv_catpvf(aTHX_ msg,
+                                          "\\%03"UVof, (UV)*f & 0xFF);
+                       }
+                   }
+                   sv_catpvs(msg, "\"");
+               } else {
                    sv_catpvs(msg, "end of string");
+               }
                Perl_warner(aTHX_ packWARN(WARN_PRINTF), "%"SVf, SVfARG(msg)); /* yes, this is reentrant */
            }
 
@@ -9905,13 +10214,13 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
 
        have = esignlen + zeros + elen;
        if (have < zeros)
-           Perl_croak_nocontext(PL_memory_wrap);
+           Perl_croak_nocontext("%s", PL_memory_wrap);
 
        need = (have > width ? have : width);
        gap = need - have;
 
        if (need >= (((STRLEN)~0) - SvCUR(sv) - dotstrlen - 1))
-           Perl_croak_nocontext(PL_memory_wrap);
+           Perl_croak_nocontext("%s", PL_memory_wrap);
        SvGROW(sv, SvCUR(sv) + need + dotstrlen + 1);
        p = SvEND(sv);
        if (esignlen && fill == '0') {
@@ -9976,7 +10285,7 @@ ptr_table_* functions.
 
 =cut
 
-============================================================================*/
+ * =========================================================================*/
 
 
 #if defined(USE_ITHREADS)
@@ -9989,19 +10298,20 @@ ptr_table_* functions.
 
 /* Certain cases in Perl_ss_dup have been merged, by relying on the fact
    that currently av_dup, gv_dup and hv_dup are the same as sv_dup.
-   If this changes, please unmerge ss_dup.  */
+   If this changes, please unmerge ss_dup.
+   Likewise, sv_dup_inc_multiple() relies on this fact.  */
 #define sv_dup_inc(s,t)        SvREFCNT_inc(sv_dup(s,t))
 #define sv_dup_inc_NN(s,t)     SvREFCNT_inc_NN(sv_dup(s,t))
-#define av_dup(s,t)    (AV*)sv_dup((SV*)s,t)
-#define av_dup_inc(s,t)        (AV*)SvREFCNT_inc(sv_dup((SV*)s,t))
-#define hv_dup(s,t)    (HV*)sv_dup((SV*)s,t)
-#define hv_dup_inc(s,t)        (HV*)SvREFCNT_inc(sv_dup((SV*)s,t))
-#define cv_dup(s,t)    (CV*)sv_dup((SV*)s,t)
-#define cv_dup_inc(s,t)        (CV*)SvREFCNT_inc(sv_dup((SV*)s,t))
-#define io_dup(s,t)    (IO*)sv_dup((SV*)s,t)
-#define io_dup_inc(s,t)        (IO*)SvREFCNT_inc(sv_dup((SV*)s,t))
-#define gv_dup(s,t)    (GV*)sv_dup((SV*)s,t)
-#define gv_dup_inc(s,t)        (GV*)SvREFCNT_inc(sv_dup((SV*)s,t))
+#define av_dup(s,t)    MUTABLE_AV(sv_dup((const SV *)s,t))
+#define av_dup_inc(s,t)        MUTABLE_AV(SvREFCNT_inc(sv_dup((const SV *)s,t)))
+#define hv_dup(s,t)    MUTABLE_HV(sv_dup((const SV *)s,t))
+#define hv_dup_inc(s,t)        MUTABLE_HV(SvREFCNT_inc(sv_dup((const SV *)s,t)))
+#define cv_dup(s,t)    MUTABLE_CV(sv_dup((const SV *)s,t))
+#define cv_dup_inc(s,t)        MUTABLE_CV(SvREFCNT_inc(sv_dup((const SV *)s,t)))
+#define io_dup(s,t)    MUTABLE_IO(sv_dup((const SV *)s,t))
+#define io_dup_inc(s,t)        MUTABLE_IO(SvREFCNT_inc(sv_dup((const SV *)s,t)))
+#define gv_dup(s,t)    MUTABLE_GV(sv_dup((const SV *)s,t))
+#define gv_dup_inc(s,t)        MUTABLE_GV(SvREFCNT_inc(sv_dup((const SV *)s,t)))
 #define SAVEPV(p)      ((p) ? savepv(p) : NULL)
 #define SAVEPVN(p,n)   ((p) ? savepvn(p,n) : NULL)
 
@@ -10181,7 +10491,8 @@ Perl_gp_dup(pTHX_ GP *const gp, CLONE_PARAMS *const param)
     ptr_table_store(PL_ptr_table, gp, ret);
 
     /* clone */
-    ret->gp_refcnt     = 0;                    /* must be before any other dups! */
+    /* ret->gp_refcnt must be 0 before any other dups are called. We're relying
+       on Newxz() to do this for us.  */
     ret->gp_sv         = sv_dup_inc(gp->gp_sv, param);
     ret->gp_io         = io_dup_inc(gp->gp_io, param);
     ret->gp_form       = cv_dup_inc(gp->gp_form, param);
@@ -10200,68 +10511,59 @@ Perl_gp_dup(pTHX_ GP *const gp, CLONE_PARAMS *const param)
 MAGIC *
 Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *const param)
 {
-    MAGIC *mgprev = (MAGIC*)NULL;
-    MAGIC *mgret;
+    MAGIC *mgret = NULL;
+    MAGIC **mgprev_p = &mgret;
 
     PERL_ARGS_ASSERT_MG_DUP;
 
-    if (!mg)
-       return (MAGIC*)NULL;
-    /* look for it in the table first */
-    mgret = (MAGIC*)ptr_table_fetch(PL_ptr_table, mg);
-    if (mgret)
-       return mgret;
-
     for (; mg; mg = mg->mg_moremagic) {
        MAGIC *nmg;
-       Newxz(nmg, 1, MAGIC);
-       if (mgprev)
-           mgprev->mg_moremagic = nmg;
-       else
-           mgret = nmg;
-       nmg->mg_virtual = mg->mg_virtual;       /* XXX copy dynamic vtable? */
-       nmg->mg_private = mg->mg_private;
-       nmg->mg_type    = mg->mg_type;
-       nmg->mg_flags   = mg->mg_flags;
+       Newx(nmg, 1, MAGIC);
+       *mgprev_p = nmg;
+       mgprev_p = &(nmg->mg_moremagic);
+
+       /* There was a comment "XXX copy dynamic vtable?" but as we don't have
+          dynamic vtables, I'm not sure why Sarathy wrote it. The comment dates
+          from the original commit adding Perl_mg_dup() - revision 4538.
+          Similarly there is the annotation "XXX random ptr?" next to the
+          assignment to nmg->mg_ptr.  */
+       *nmg = *mg;
+
        /* FIXME for plugins
-       if (mg->mg_type == PERL_MAGIC_qr) {
-           nmg->mg_obj = (SV*)CALLREGDUPE((REGEXP*)mg->mg_obj, param);
+       if (nmg->mg_type == PERL_MAGIC_qr) {
+           nmg->mg_obj = MUTABLE_SV(CALLREGDUPE((REGEXP*)nmg->mg_obj, param));
        }
        else
        */
-       if(mg->mg_type == PERL_MAGIC_backref) {
+       if(nmg->mg_type == PERL_MAGIC_backref) {
            /* The backref AV has its reference count deliberately bumped by
               1.  */
-           nmg->mg_obj = SvREFCNT_inc(av_dup_inc((AV*) mg->mg_obj, param));
+           nmg->mg_obj
+               = SvREFCNT_inc(av_dup_inc((const AV *) nmg->mg_obj, param));
        }
        else {
-           nmg->mg_obj = (mg->mg_flags & MGf_REFCOUNTED)
-                             ? sv_dup_inc(mg->mg_obj, param)
-                             : sv_dup(mg->mg_obj, param);
-       }
-       nmg->mg_len     = mg->mg_len;
-       nmg->mg_ptr     = mg->mg_ptr;   /* XXX random ptr? */
-       if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
-           if (mg->mg_len > 0) {
-               nmg->mg_ptr     = SAVEPVN(mg->mg_ptr, mg->mg_len);
-               if (mg->mg_type == PERL_MAGIC_overload_table &&
-                       AMT_AMAGIC((AMT*)mg->mg_ptr))
+           nmg->mg_obj = (nmg->mg_flags & MGf_REFCOUNTED)
+                             ? sv_dup_inc(nmg->mg_obj, param)
+                             : sv_dup(nmg->mg_obj, param);
+       }
+
+       if (nmg->mg_ptr && nmg->mg_type != PERL_MAGIC_regex_global) {
+           if (nmg->mg_len > 0) {
+               nmg->mg_ptr     = SAVEPVN(nmg->mg_ptr, nmg->mg_len);
+               if (nmg->mg_type == PERL_MAGIC_overload_table &&
+                       AMT_AMAGIC((AMT*)nmg->mg_ptr))
                {
-                   const AMT * const amtp = (AMT*)mg->mg_ptr;
                    AMT * const namtp = (AMT*)nmg->mg_ptr;
-                   I32 i;
-                   for (i = 1; i < NofAMmeth; i++) {
-                       namtp->table[i] = cv_dup_inc(amtp->table[i], param);
-                   }
+                   sv_dup_inc_multiple((SV**)(namtp->table),
+                                       (SV**)(namtp->table), NofAMmeth, param);
                }
            }
-           else if (mg->mg_len == HEf_SVKEY)
-               nmg->mg_ptr     = (char*)sv_dup_inc((SV*)mg->mg_ptr, param);
+           else if (nmg->mg_len == HEf_SVKEY)
+               nmg->mg_ptr = (char*)sv_dup_inc((const SV *)nmg->mg_ptr, param);
        }
-       if ((mg->mg_flags & MGf_DUP) && mg->mg_virtual && mg->mg_virtual->svt_dup) {
+       if ((nmg->mg_flags & MGf_DUP) && nmg->mg_virtual && nmg->mg_virtual->svt_dup) {
            CALL_FPTR(nmg->mg_virtual->svt_dup)(aTHX_ nmg, param);
        }
-       mgprev = nmg;
     }
     return mgret;
 }
@@ -10276,7 +10578,7 @@ Perl_ptr_table_new(pTHX)
     PTR_TBL_t *tbl;
     PERL_UNUSED_CONTEXT;
 
-    Newxz(tbl, 1, PTR_TBL_t);
+    Newx(tbl, 1, PTR_TBL_t);
     tbl->tbl_max       = 511;
     tbl->tbl_items     = 0;
     Newxz(tbl->tbl_ary, tbl->tbl_max + 1, PTR_TBL_ENT_t*);
@@ -10430,8 +10732,8 @@ Perl_rvpv_dup(pTHX_ SV *const dstr, const SV *const sstr, CLONE_PARAMS *const pa
 
     if (SvROK(sstr)) {
        SvRV_set(dstr, SvWEAKREF(sstr)
-                      ? sv_dup(SvRV(sstr), param)
-                      : sv_dup_inc(SvRV(sstr), param));
+                      ? sv_dup(SvRV_const(sstr), param)
+                      : sv_dup_inc(SvRV_const(sstr), param));
 
     }
     else if (SvPVX_const(sstr)) {
@@ -10459,7 +10761,7 @@ Perl_rvpv_dup(pTHX_ SV *const dstr, const SV *const sstr, CLONE_PARAMS *const pa
            }
            else {
                /* Some other special case - random pointer */
-               SvPV_set(dstr, SvPVX(sstr));            
+               SvPV_set(dstr, (char *) SvPVX_const(sstr));             
            }
        }
     }
@@ -10469,6 +10771,20 @@ Perl_rvpv_dup(pTHX_ SV *const dstr, const SV *const sstr, CLONE_PARAMS *const pa
     }
 }
 
+/* duplicate a list of SVs. source and dest may point to the same memory.  */
+static SV **
+S_sv_dup_inc_multiple(pTHX_ SV *const *source, SV **dest,
+                     SSize_t items, CLONE_PARAMS *const param)
+{
+    PERL_ARGS_ASSERT_SV_DUP_INC_MULTIPLE;
+
+    while (items-- > 0) {
+       *dest++ = sv_dup_inc(*source++, param);
+    }
+
+    return dest;
+}
+
 /* duplicate an SV of any type (including AV, HV etc) */
 
 SV *
@@ -10488,7 +10804,7 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
        return NULL;
     }
     /* look for it in the table first */
-    dstr = (SV*)ptr_table_fetch(PL_ptr_table, sstr);
+    dstr = MUTABLE_SV(ptr_table_fetch(PL_ptr_table, sstr));
     if (dstr)
        return dstr;
 
@@ -10499,7 +10815,7 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
            const HEK * const hvname = HvNAME_HEK(sstr);
            if (hvname)
                /** don't clone stashes if they already exist **/
-               return (SV*)gv_stashpvn(HEK_KEY(hvname), HEK_LEN(hvname), 0);
+               return MUTABLE_SV(gv_stashpvn(HEK_KEY(hvname), HEK_LEN(hvname), 0));
         }
     }
 
@@ -10564,9 +10880,6 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                break;
 
            case SVt_PVGV:
-               if (GvUNIQUE((GV*)sstr)) {
-                   NOOP;   /* Do sharing here, and fall through */
-               }
            case SVt_PVIO:
            case SVt_PVFM:
            case SVt_PVHV:
@@ -10637,13 +10950,12 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                if (LvTYPE(dstr) == 't') /* for tie: unrefcnted fake (SV**) */
                    LvTARG(dstr) = dstr;
                else if (LvTYPE(dstr) == 'T') /* for tie: fake HE */
-                   LvTARG(dstr) = (SV*)he_dup((HE*)LvTARG(dstr), 0, param);
+                   LvTARG(dstr) = MUTABLE_SV(he_dup((HE*)LvTARG(dstr), 0, param));
                else
                    LvTARG(dstr) = sv_dup_inc(LvTARG(dstr), param);
            case SVt_PVGV:
                if(isGV_with_GP(sstr)) {
-                   if (GvNAME_HEK(dstr))
-                       GvNAME_HEK(dstr) = hek_dup(GvNAME_HEK(dstr), param);
+                   GvNAME_HEK(dstr) = hek_dup(GvNAME_HEK(dstr), param);
                    /* Don't call sv_add_backref here as it's going to be
                       created as part of the magic cloning of the symbol
                       table.  */
@@ -10685,35 +10997,38 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                IoBOTTOM_NAME(dstr)     = SAVEPV(IoBOTTOM_NAME(dstr));
                break;
            case SVt_PVAV:
-               if (AvARRAY((AV*)sstr)) {
+               /* avoid cloning an empty array */
+               if (AvARRAY((const AV *)sstr) && AvFILLp((const AV *)sstr) >= 0) {
                    SV **dst_ary, **src_ary;
-                   SSize_t items = AvFILLp((AV*)sstr) + 1;
+                   SSize_t items = AvFILLp((const AV *)sstr) + 1;
 
-                   src_ary = AvARRAY((AV*)sstr);
-                   Newxz(dst_ary, AvMAX((AV*)sstr)+1, SV*);
+                   src_ary = AvARRAY((const AV *)sstr);
+                   Newxz(dst_ary, AvMAX((const AV *)sstr)+1, SV*);
                    ptr_table_store(PL_ptr_table, src_ary, dst_ary);
-                   AvARRAY((AV*)dstr) = dst_ary;
-                   AvALLOC((AV*)dstr) = dst_ary;
-                   if (AvREAL((AV*)sstr)) {
-                       while (items-- > 0)
-                           *dst_ary++ = sv_dup_inc(*src_ary++, param);
+                   AvARRAY(MUTABLE_AV(dstr)) = dst_ary;
+                   AvALLOC((const AV *)dstr) = dst_ary;
+                   if (AvREAL((const AV *)sstr)) {
+                       dst_ary = sv_dup_inc_multiple(src_ary, dst_ary, items,
+                                                     param);
                    }
                    else {
                        while (items-- > 0)
                            *dst_ary++ = sv_dup(*src_ary++, param);
                    }
-                   items = AvMAX((AV*)sstr) - AvFILLp((AV*)sstr);
+                   items = AvMAX((const AV *)sstr) - AvFILLp((const AV *)sstr);
                    while (items-- > 0) {
                        *dst_ary++ = &PL_sv_undef;
                    }
                }
                else {
-                   AvARRAY((AV*)dstr)  = NULL;
-                   AvALLOC((AV*)dstr)  = (SV**)NULL;
+                   AvARRAY(MUTABLE_AV(dstr))   = NULL;
+                   AvALLOC((const AV *)dstr)   = (SV**)NULL;
+                   AvMAX(  (const AV *)dstr)   = -1;
+                   AvFILLp((const AV *)dstr)   = -1;
                }
                break;
            case SVt_PVHV:
-               if (HvARRAY((HV*)sstr)) {
+               if (HvARRAY((const HV *)sstr)) {
                    STRLEN i = 0;
                    const bool sharekeys = !!HvSHAREKEYS(sstr);
                    XPVHV * const dxhv = (XPVHV*)SvANY(dstr);
@@ -10738,16 +11053,17 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                        SvFLAGS(dstr) |= SVf_OOK;
 
                        hvname = saux->xhv_name;
-                       daux->xhv_name = hvname ? hek_dup(hvname, param) : hvname;
+                       daux->xhv_name = hek_dup(hvname, param);
 
                        daux->xhv_riter = saux->xhv_riter;
                        daux->xhv_eiter = saux->xhv_eiter
                            ? he_dup(saux->xhv_eiter,
                                        (bool)!!HvSHAREKEYS(sstr), param) : 0;
+                       /* backref array needs refcnt=2; see sv_add_backref */
                        daux->xhv_backreferences =
                            saux->xhv_backreferences
-                               ? (AV*) SvREFCNT_inc(
-                                       sv_dup((SV*)saux->xhv_backreferences, param))
+                           ? MUTABLE_AV(SvREFCNT_inc(
+                                                     sv_dup_inc((const SV *)saux->xhv_backreferences, param)))
                                : 0;
 
                         daux->xhv_mro_meta = saux->xhv_mro_meta
@@ -10760,7 +11076,7 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                    }
                }
                else
-                   HvARRAY((HV*)dstr) = NULL;
+                   HvARRAY(MUTABLE_HV(dstr)) = NULL;
                break;
            case SVt_PVCV:
                if (!(param->flags & CLONEf_COPY_STACKS)) {
@@ -10774,9 +11090,8 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                    CvROOT(dstr) = OpREFCNT_inc(CvROOT(dstr));
                OP_REFCNT_UNLOCK;
                if (CvCONST(dstr) && CvISXSUB(dstr)) {
-                   CvXSUBANY(dstr).any_ptr = GvUNIQUE(CvGV(dstr)) ?
-                       SvREFCNT_inc(CvXSUBANY(dstr).any_ptr) :
-                       sv_dup_inc((SV *)CvXSUBANY(dstr).any_ptr, param);
+                   CvXSUBANY(dstr).any_ptr =
+                       sv_dup_inc((const SV *)CvXSUBANY(dstr).any_ptr, param);
                }
                /* don't dup if copying back - CvGV isn't refcounted, so the
                 * duped GV may never be freed. A bit of a hack! DAPM */
@@ -10867,7 +11182,8 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max, CLONE_PARAMS* param)
                                                ncx->blk_loop.oldcomppad);
                } else {
                    ncx->blk_loop.oldcomppad
-                       = (PAD*)gv_dup((GV*)ncx->blk_loop.oldcomppad, param);
+                       = (PAD*)gv_dup((const GV *)ncx->blk_loop.oldcomppad,
+                                      param);
                }
                break;
            case CXt_FORMAT:
@@ -10978,10 +11294,10 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
     const I32 max      = proto_perl->Isavestack_max;
     I32 ix             = proto_perl->Isavestack_ix;
     ANY *nss;
-    SV *sv;
-    GV *gv;
-    AV *av;
-    HV *hv;
+    const SV *sv;
+    const GV *gv;
+    const AV *av;
+    const HV *hv;
     void* ptr;
     int intval;
     long longval;
@@ -11001,17 +11317,17 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
        TOPINT(nss,ix) = type;
        switch (type) {
        case SAVEt_HELEM:               /* hash element */
-           sv = (SV*)POPPTR(ss,ix);
+           sv = (const SV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
            /* fall through */
        case SAVEt_ITEM:                        /* normal string */
         case SAVEt_SV:                         /* scalar reference */
-           sv = (SV*)POPPTR(ss,ix);
+           sv = (const SV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
            /* fall through */
        case SAVEt_FREESV:
        case SAVEt_MORTALIZESV:
-           sv = (SV*)POPPTR(ss,ix);
+           sv = (const SV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
            break;
        case SAVEt_SHARED_PVREF:                /* char* in shared space */
@@ -11022,19 +11338,19 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            break;
         case SAVEt_GENERIC_SVREF:              /* generic sv */
         case SAVEt_SVREF:                      /* scalar reference */
-           sv = (SV*)POPPTR(ss,ix);
+           sv = (const SV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = svp_dup_inc((SV**)ptr, proto_perl);/* XXXXX */
            break;
         case SAVEt_HV:                         /* hash reference */
         case SAVEt_AV:                         /* array reference */
-           sv = (SV*) POPPTR(ss,ix);
+           sv = (const SV *) POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
            /* fall through */
        case SAVEt_COMPPAD:
        case SAVEt_NSTAB:
-           sv = (SV*) POPPTR(ss,ix);
+           sv = (const SV *) POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup(sv, param);
            break;
        case SAVEt_INT:                         /* int reference */
@@ -11071,7 +11387,7 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
        case SAVEt_SPTR:                        /* SV* reference */
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           sv = (SV*)POPPTR(ss,ix);
+           sv = (const SV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup(sv, param);
            break;
        case SAVEt_VPTR:                        /* random* reference */
@@ -11091,7 +11407,7 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            gp = (GP*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = gp = gp_dup(gp, param);
            (void)GpREFCNT_inc(gp);
-           gv = (GV*)POPPTR(ss,ix);
+           gv = (const GV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = gv_dup_inc(gv, param);
             break;
        case SAVEt_FREEOP:
@@ -11120,16 +11436,16 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            else
                TOPPTR(nss,ix) = NULL;
            break;
-       case SAVEt_FREEPV:
-           c = (char*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = pv_dup_inc(c);
-           break;
        case SAVEt_DELETE:
-           hv = (HV*)POPPTR(ss,ix);
+           hv = (const HV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = hv_dup_inc(hv, param);
+           i = POPINT(ss,ix);
+           TOPINT(nss,ix) = i;
+           /* Fall through */
+       case SAVEt_FREEPV:
            c = (char*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = pv_dup_inc(c);
-           /* fall through */
+           break;
        case SAVEt_STACK_POS:           /* Position on Perl stack */
            i = POPINT(ss,ix);
            TOPINT(nss,ix) = i;
@@ -11157,11 +11473,11 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            ix -= i;
            break;
        case SAVEt_AELEM:               /* array element */
-           sv = (SV*)POPPTR(ss,ix);
+           sv = (const SV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
            i = POPINT(ss,ix);
            TOPINT(nss,ix) = i;
-           av = (AV*)POPPTR(ss,ix);
+           av = (const AV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = av_dup_inc(av, param);
            break;
        case SAVEt_OP:
@@ -11169,8 +11485,6 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            TOPPTR(nss,ix) = ptr;
            break;
        case SAVEt_HINTS:
-           i = POPINT(ss,ix);
-           TOPINT(nss,ix) = i;
            ptr = POPPTR(ss,ix);
            if (ptr) {
                HINTS_REFCNT_LOCK;
@@ -11178,8 +11492,10 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
                HINTS_REFCNT_UNLOCK;
            }
            TOPPTR(nss,ix) = ptr;
+           i = POPINT(ss,ix);
+           TOPINT(nss,ix) = i;
            if (i & HINT_LOCALIZE_HH) {
-               hv = (HV*)POPPTR(ss,ix);
+               hv = (const HV *)POPPTR(ss,ix);
                TOPPTR(nss,ix) = hv_dup_inc(hv, param);
            }
            break;
@@ -11188,7 +11504,7 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            TOPLONG(nss,ix) = longval;
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           sv = (SV*)POPPTR(ss,ix);
+           sv = (const SV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
            break;
        case SAVEt_BOOL:
@@ -11202,7 +11518,7 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            TOPINT(nss,ix) = i;
            i = POPINT(ss,ix);
            TOPINT(nss,ix) = i;
-           sv = (SV*)POPPTR(ss,ix);
+           sv = (const SV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup(sv, param);
            break;
        case SAVEt_RE_STATE:
@@ -11291,9 +11607,9 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
 static void
 do_mark_cloneable_stash(pTHX_ SV *const sv)
 {
-    const HEK * const hvname = HvNAME_HEK((HV*)sv);
+    const HEK * const hvname = HvNAME_HEK((const HV *)sv);
     if (hvname) {
-       GV* const cloner = gv_fetchmethod_autoload((HV*)sv, "CLONE_SKIP", 0);
+       GV* const cloner = gv_fetchmethod_autoload(MUTABLE_HV(sv), "CLONE_SKIP", 0);
        SvFLAGS(sv) |= SVphv_CLONEABLE; /* clone objects by default */
        if (cloner && GvCV(cloner)) {
            dSP;
@@ -11304,7 +11620,7 @@ do_mark_cloneable_stash(pTHX_ SV *const sv)
            PUSHMARK(SP);
            mXPUSHs(newSVhek(hvname));
            PUTBACK;
-           call_sv((SV*)GvCV(cloner), G_SCALAR);
+           call_sv(MUTABLE_SV(GvCV(cloner)), G_SCALAR);
            SPAGAIN;
            status = POPu;
            PUTBACK;
@@ -11608,9 +11924,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 #endif
     PL_encoding                = sv_dup(proto_perl->Iencoding, param);
 
-    sv_setpvn(PERL_DEBUG_PAD(0), "", 0);       /* For regex debugging. */
-    sv_setpvn(PERL_DEBUG_PAD(1), "", 0);       /* ext/re needs these */
-    sv_setpvn(PERL_DEBUG_PAD(2), "", 0);       /* even without DEBUGGING. */
+    sv_setpvs(PERL_DEBUG_PAD(0), "");  /* For regex debugging. */
+    sv_setpvs(PERL_DEBUG_PAD(1), "");  /* ext/re needs these */
+    sv_setpvs(PERL_DEBUG_PAD(2), "");  /* even without DEBUGGING. */
 
    
     /* RE engine related */
@@ -11627,6 +11943,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_regex_pad = AvARRAY(PL_regex_padav);
 
     /* shortcuts to various I/O objects */
+    PL_ofsgv            = gv_dup(proto_perl->Iofsgv, param);
     PL_stdingv         = gv_dup(proto_perl->Istdingv, param);
     PL_stderrgv                = gv_dup(proto_perl->Istderrgv, param);
     PL_defgv           = gv_dup(proto_perl->Idefgv, param);
@@ -11860,7 +12177,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     PL_glob_index      = proto_perl->Iglob_index;
     PL_srand_called    = proto_perl->Isrand_called;
-    PL_bitcount                = NULL; /* reinits on demand */
 
     if (proto_perl->Ipsig_pend) {
        Newxz(PL_psig_pend, SIG_SIZE, int);
@@ -11870,12 +12186,12 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     }
 
     if (proto_perl->Ipsig_ptr) {
-       Newxz(PL_psig_ptr,  SIG_SIZE, SV*);
-       Newxz(PL_psig_name, SIG_SIZE, SV*);
-       for (i = 1; i < SIG_SIZE; i++) {
-           PL_psig_ptr[i]  = sv_dup_inc(proto_perl->Ipsig_ptr[i], param);
-           PL_psig_name[i] = sv_dup_inc(proto_perl->Ipsig_name[i], param);
-       }
+       Newx(PL_psig_ptr,  SIG_SIZE, SV*);
+       Newx(PL_psig_name, SIG_SIZE, SV*);
+       sv_dup_inc_multiple(proto_perl->Ipsig_ptr, PL_psig_ptr, SIG_SIZE,
+                           param);
+       sv_dup_inc_multiple(proto_perl->Ipsig_name, PL_psig_name, SIG_SIZE,
+                           param);
     }
     else {
        PL_psig_ptr     = (SV**)NULL;
@@ -11889,12 +12205,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        PL_tmps_ix              = proto_perl->Itmps_ix;
        PL_tmps_max             = proto_perl->Itmps_max;
        PL_tmps_floor           = proto_perl->Itmps_floor;
-       Newxz(PL_tmps_stack, PL_tmps_max, SV*);
-       i = 0;
-       while (i <= PL_tmps_ix) {
-           PL_tmps_stack[i]    = sv_dup_inc(proto_perl->Itmps_stack[i], param);
-           ++i;
-       }
+       Newx(PL_tmps_stack, PL_tmps_max, SV*);
+       sv_dup_inc_multiple(proto_perl->Itmps_stack, PL_tmps_stack, PL_tmps_ix,
+                           param);
 
        /* next PUSHMARK() sets *(PL_markstack_ptr+1) */
        i = proto_perl->Imarkstack_max - proto_perl->Imarkstack;
@@ -11943,8 +12256,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
         * orphaned
         */
        for (i = 0; i<= proto_perl->Itmps_ix; i++) {
-           SV * const nsv = (SV*)ptr_table_fetch(PL_ptr_table,
-                   proto_perl->Itmps_stack[i]);
+           SV * const nsv = MUTABLE_SV(ptr_table_fetch(PL_ptr_table,
+                   proto_perl->Itmps_stack[i]));
            if (nsv && !SvREFCNT(nsv)) {
                EXTEND_MORTAL(1);
                PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple(nsv);
@@ -11973,7 +12286,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_curpm           = proto_perl->Icurpm;   /* XXX No PMOP ref count */
     PL_rs              = sv_dup_inc(proto_perl->Irs, param);
     PL_last_in_gv      = gv_dup(proto_perl->Ilast_in_gv, param);
-    PL_ofs_sv          = sv_dup_inc(proto_perl->Iofs_sv, param);
     PL_defoutgv                = gv_dup_inc(proto_perl->Idefoutgv, param);
     PL_chopset         = proto_perl->Ichopset; /* XXX never deallocated */
     PL_toptarget       = sv_dup_inc(proto_perl->Itoptarget, param);
@@ -12028,6 +12340,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
          PTR2UV(PL_watchok));
     }
 
+    PL_registered_mros  = hv_dup_inc(proto_perl->Iregistered_mros, param);
+
     if (!(flags & CLONEf_KEEP_PTR_TABLE)) {
         ptr_table_free(PL_ptr_table);
         PL_ptr_table = NULL;
@@ -12037,7 +12351,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        identified by sv_dup() above.
     */
     while(av_len(param->stashes) != -1) {
-       HV* const stash = (HV*) av_shift(param->stashes);
+       HV* const stash = MUTABLE_HV(av_shift(param->stashes));
        GV* const cloner = gv_fetchmethod_autoload(stash, "CLONE", 0);
        if (cloner && GvCV(cloner)) {
            dSP;
@@ -12046,7 +12360,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
            PUSHMARK(SP);
            mXPUSHs(newSVhek(HvNAME_HEK(stash)));
            PUTBACK;
-           call_sv((SV*)GvCV(cloner), G_DISCARD);
+           call_sv(MUTABLE_SV(GvCV(cloner)), G_DISCARD);
            FREETMPS;
            LEAVE;
        }
@@ -12198,7 +12512,7 @@ Perl_sv_cat_decode(pTHX_ SV *dsv, SV *encoding,
  * If so, return a mortal copy of the key. */
 
 STATIC SV*
-S_find_hash_subscript(pTHX_ HV *hv, SV* val)
+S_find_hash_subscript(pTHX_ const HV *const hv, const SV *const val)
 {
     dVAR;
     register HE **array;
@@ -12234,7 +12548,7 @@ S_find_hash_subscript(pTHX_ HV *hv, SV* val)
  * If so, return the index, otherwise return -1. */
 
 STATIC I32
-S_find_array_subscript(pTHX_ AV *av, SV* val)
+S_find_array_subscript(pTHX_ const AV *const av, const SV *const val)
 {
     dVAR;
 
@@ -12267,8 +12581,8 @@ S_find_array_subscript(pTHX_ AV *av, SV* val)
 #define FUV_SUBSCRIPT_WITHIN   4       /* "within @foo"   */
 
 STATIC SV*
-S_varname(pTHX_ GV *gv, const char gvtype, PADOFFSET targ,
-       SV* keyname, I32 aindex, int subscript_type)
+S_varname(pTHX_ const GV *const gv, const char gvtype, PADOFFSET targ,
+       const SV *const keyname, I32 aindex, int subscript_type)
 {
 
     SV * const name = sv_newmortal();
@@ -12297,7 +12611,7 @@ S_varname(pTHX_ GV *gv, const char gvtype, PADOFFSET targ,
 
        if (!cv || !CvPADLIST(cv))
            return NULL;
-       av = (AV*)(*av_fetch(CvPADLIST(cv), 0, FALSE));
+       av = MUTABLE_AV((*av_fetch(CvPADLIST(cv), 0, FALSE)));
        sv = *av_fetch(av, targ, FALSE);
        sv_setpvn(name, SvPV_nolen_const(sv), SvCUR(sv));
     }
@@ -12343,13 +12657,13 @@ PL_comppad/PL_curpad points to the currently executing pad.
 */
 
 STATIC SV *
-S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
+S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
+                 bool match)
 {
     dVAR;
     SV *sv;
-    AV *av;
-    GV *gv;
-    OP *o, *o2, *kid;
+    const GV *gv;
+    const OP *o, *o2, *kid;
 
     if (!obase || (match && (!uninit_sv || uninit_sv == &PL_sv_undef ||
                            uninit_sv == &PL_sv_placeholder)))
@@ -12378,7 +12692,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
                gv = cGVOPx_gv(cUNOPx(obase)->op_first);
                if (!gv)
                    break;
-               sv = hash ? (SV*)GvHV(gv): (SV*)GvAV(gv);
+               sv = hash ? MUTABLE_SV(GvHV(gv)): MUTABLE_SV(GvAV(gv));
            }
            else /* @{expr}, %{expr} */
                return find_uninit_var(cUNOPx(obase)->op_first,
@@ -12387,12 +12701,12 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
 
        /* attempt to find a match within the aggregate */
        if (hash) {
-           keysv = find_hash_subscript((HV*)sv, uninit_sv);
+           keysv = find_hash_subscript((const HV*)sv, uninit_sv);
            if (keysv)
                subscript_type = FUV_SUBSCRIPT_HASH;
        }
        else {
-           index = find_array_subscript((AV*)sv, uninit_sv);
+           index = find_array_subscript((const AV *)sv, uninit_sv);
            if (index >= 0)
                subscript_type = FUV_SUBSCRIPT_ARRAY;
        }
@@ -12420,7 +12734,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
        if (obase->op_flags & OPf_SPECIAL) { /* lexical array */
            if (match) {
                SV **svp;
-               av = (AV*)PAD_SV(obase->op_targ);
+               AV *av = MUTABLE_AV(PAD_SV(obase->op_targ));
                if (!av || SvRMAGICAL(av))
                    break;
                svp = av_fetch(av, (I32)obase->op_private, FALSE);
@@ -12436,7 +12750,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
                break;
            if (match) {
                SV **svp;
-               av = GvAV(gv);
+               AV *const av = GvAV(gv);
                if (!av || SvRMAGICAL(av))
                    break;
                svp = av_fetch(av, (I32)obase->op_private, FALSE);
@@ -12476,7 +12790,8 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
            gv = cGVOPx_gv(cUNOPo->op_first);
            if (!gv)
                break;
-           sv = o->op_type == OP_RV2HV ? (SV*)GvHV(gv) : (SV*)GvAV(gv);
+           sv = o->op_type
+               == OP_RV2HV ? MUTABLE_SV(GvHV(gv)) : MUTABLE_SV(GvAV(gv));
        }
        if (!sv)
            break;
@@ -12487,12 +12802,12 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
                if (SvMAGICAL(sv))
                    break;
                if (obase->op_type == OP_HELEM) {
-                   HE* he = hv_fetch_ent((HV*)sv, cSVOPx_sv(kid), 0, 0);
+                   HE* he = hv_fetch_ent(MUTABLE_HV(sv), cSVOPx_sv(kid), 0, 0);
                    if (!he || HeVAL(he) != uninit_sv)
                        break;
                }
                else {
-                   SV * const * const svp = av_fetch((AV*)sv, SvIV(cSVOPx_sv(kid)), FALSE);
+                   SV * const * const svp = av_fetch(MUTABLE_AV(sv), SvIV(cSVOPx_sv(kid)), FALSE);
                    if (!svp || *svp != uninit_sv)
                        break;
                }
@@ -12508,13 +12823,14 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
            /* index is an expression;
             * attempt to find a match within the aggregate */
            if (obase->op_type == OP_HELEM) {
-               SV * const keysv = find_hash_subscript((HV*)sv, uninit_sv);
+               SV * const keysv = find_hash_subscript((const HV*)sv, uninit_sv);
                if (keysv)
                    return varname(gv, '%', o->op_targ,
                                                keysv, 0, FUV_SUBSCRIPT_HASH);
            }
            else {
-               const I32 index = find_array_subscript((AV*)sv, uninit_sv);
+               const I32 index
+                   = find_array_subscript((const AV *)sv, uninit_sv);
                if (index >= 0)
                    return varname(gv, '@', o->op_targ,
                                        NULL, index, FUV_SUBSCRIPT_ARRAY);
@@ -12565,7 +12881,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
                                 : DEFSV))
            {
                sv = sv_newmortal();
-               sv_setpvn(sv, "$_", 2);
+               sv_setpvs(sv, "$_");
                return sv;
            }
        }
@@ -12574,6 +12890,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
     case OP_PRTF:
     case OP_PRINT:
     case OP_SAY:
+       match = 1; /* print etc can return undef on defined args */
        /* skip filehandle as it can't produce 'undef' warning  */
        o = cUNOPx(obase)->op_first;
        if ((obase->op_flags & OPf_STACKED) && o->op_type == OP_PUSHMARK)
@@ -12583,8 +12900,81 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
 
     case OP_ENTEREVAL: /* could be eval $undef or $x='$undef'; eval $x */
     case OP_RV2SV:
-    case OP_CUSTOM:
-       match = 1; /* XS or custom code could trigger random warnings */
+    case OP_CUSTOM: /* XS or custom code could trigger random warnings */
+
+       /* the following ops are capable of returning PL_sv_undef even for
+        * defined arg(s) */
+
+    case OP_BACKTICK:
+    case OP_PIPE_OP:
+    case OP_FILENO:
+    case OP_BINMODE:
+    case OP_TIED:
+    case OP_GETC:
+    case OP_SYSREAD:
+    case OP_SEND:
+    case OP_IOCTL:
+    case OP_SOCKET:
+    case OP_SOCKPAIR:
+    case OP_BIND:
+    case OP_CONNECT:
+    case OP_LISTEN:
+    case OP_ACCEPT:
+    case OP_SHUTDOWN:
+    case OP_SSOCKOPT:
+    case OP_GETPEERNAME:
+    case OP_FTRREAD:
+    case OP_FTRWRITE:
+    case OP_FTREXEC:
+    case OP_FTROWNED:
+    case OP_FTEREAD:
+    case OP_FTEWRITE:
+    case OP_FTEEXEC:
+    case OP_FTEOWNED:
+    case OP_FTIS:
+    case OP_FTZERO:
+    case OP_FTSIZE:
+    case OP_FTFILE:
+    case OP_FTDIR:
+    case OP_FTLINK:
+    case OP_FTPIPE:
+    case OP_FTSOCK:
+    case OP_FTBLK:
+    case OP_FTCHR:
+    case OP_FTTTY:
+    case OP_FTSUID:
+    case OP_FTSGID:
+    case OP_FTSVTX:
+    case OP_FTTEXT:
+    case OP_FTBINARY:
+    case OP_FTMTIME:
+    case OP_FTATIME:
+    case OP_FTCTIME:
+    case OP_READLINK:
+    case OP_OPEN_DIR:
+    case OP_READDIR:
+    case OP_TELLDIR:
+    case OP_SEEKDIR:
+    case OP_REWINDDIR:
+    case OP_CLOSEDIR:
+    case OP_GMTIME:
+    case OP_ALARM:
+    case OP_SEMGET:
+    case OP_GETLOGIN:
+    case OP_UNDEF:
+    case OP_SUBSTR:
+    case OP_AEACH:
+    case OP_EACH:
+    case OP_SORT:
+    case OP_CALLER:
+    case OP_DOFILE:
+    case OP_PROTOTYPE:
+    case OP_NCMP:
+    case OP_SMARTMATCH:
+    case OP_UNPACK:
+    case OP_SYSOPEN:
+    case OP_SYSSEEK:
+       match = 1;
        goto do_op;
 
     case OP_ENTERSUB:
@@ -12596,6 +12986,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
          Need a better fix at dome point. DAPM 11/2007 */
        break;
 
+
     case OP_POS:
        /* def-ness of rval pos() is independent of the def-ness of its arg */
        if ( !(obase->op_flags & OPf_MOD))
@@ -12660,7 +13051,7 @@ Print appropriate "Use of uninitialized variable" warning
 */
 
 void
-Perl_report_uninit(pTHX_ SV* uninit_sv)
+Perl_report_uninit(pTHX_ const SV *uninit_sv)
 {
     dVAR;
     if (PL_op) {