This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
For SAVEHINTS(), re-order the savestack to be (?:PTR, )? INT, PTR.
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index f387d6c..2a4c581 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -1,12 +1,21 @@
 /*    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 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
@@ -154,11 +163,14 @@ Public API:
  */
 
 void
-Perl_offer_nice_chunk(pTHX_ void *chunk, U32 chunk_size)
+Perl_offer_nice_chunk(pTHX_ void *const chunk, const U32 chunk_size)
 {
     dVAR;
     void *new_chunk;
     U32 new_chunk_size;
+
+    PERL_ARGS_ASSERT_OFFER_NICE_CHUNK;
+
     new_chunk = (void *)(chunk);
     new_chunk_size = (chunk_size);
     if (new_chunk_size > PL_nice_chunk_size) {
@@ -170,14 +182,29 @@ Perl_offer_nice_chunk(pTHX_ void *chunk, 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)
@@ -186,23 +213,36 @@ Perl_offer_nice_chunk(pTHX_ void *chunk, 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
 
@@ -234,7 +274,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;
 
@@ -246,20 +286,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) \
@@ -271,6 +316,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
 
@@ -291,10 +337,13 @@ STATIC void
 S_del_sv(pTHX_ SV *p)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_DEL_SV;
+
     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) {
@@ -331,14 +380,16 @@ and split it into a list of free SVs.
 =cut
 */
 
-void
-Perl_sv_add_arena(pTHX_ char *ptr, U32 size, 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;
 
+    PERL_ARGS_ASSERT_SV_ADD_ARENA;
+
     /* The first SV in an arena isn't an SV. */
     SvANY(sva) = (void *) PL_sv_arenaroot;             /* ptr to next arena */
     SvREFCNT(sva) = size / sizeof(SV);         /* number of SV slots */
@@ -350,7 +401,7 @@ Perl_sv_add_arena(pTHX_ char *ptr, U32 size, 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
@@ -359,7 +410,7 @@ Perl_sv_add_arena(pTHX_ char *ptr, U32 size, U32 flags)
        SvFLAGS(sv) = SVTYPEMASK;
        sv++;
     }
-    SvARENA_CHAIN(sv) = 0;
+    SvARENA_CHAIN_SET(sv, 0);
 #ifdef DEBUGGING
     SvREFCNT(sv) = 0;
 #endif
@@ -370,13 +421,15 @@ Perl_sv_add_arena(pTHX_ char *ptr, U32 size, U32 flags)
  * whose flags field matches the flags/mask args. */
 
 STATIC I32
-S_visit(pTHX_ SVFUNC_t f, U32 flags, U32 mask)
+S_visit(pTHX_ SVFUNC_t f, const U32 flags, const U32 mask)
 {
     dVAR;
     SV* sva;
     I32 visited = 0;
 
-    for (sva = PL_sv_arenaroot; sva; sva = (SV*)SvANY(sva)) {
+    PERL_ARGS_ASSERT_VISIT;
+
+    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) {
@@ -397,7 +450,7 @@ S_visit(pTHX_ SVFUNC_t f, U32 flags, U32 mask)
 /* called by sv_report_used() for each live SV */
 
 static void
-do_report_used(pTHX_ SV *sv)
+do_report_used(pTHX_ SV *const sv)
 {
     if (SvTYPE(sv) != SVTYPEMASK) {
        PerlIO_printf(Perl_debug_log, "****\n");
@@ -427,7 +480,7 @@ Perl_sv_report_used(pTHX)
 /* called by sv_clean_objs() for each live SV */
 
 static void
-do_clean_objs(pTHX_ SV *ref)
+do_clean_objs(pTHX_ SV *const ref)
 {
     dVAR;
     assert (SvROK(ref));
@@ -454,7 +507,7 @@ do_clean_objs(pTHX_ SV *ref)
 
 #ifndef DISABLE_DESTRUCTOR_KLUDGE
 static void
-do_clean_named_objs(pTHX_ SV *sv)
+do_clean_named_objs(pTHX_ SV *const sv)
 {
     dVAR;
     assert(SvTYPE(sv) == SVt_PVGV);
@@ -503,9 +556,13 @@ Perl_sv_clean_objs(pTHX)
 /* called by sv_clean_all() for each live SV */
 
 static void
-do_clean_all(pTHX_ SV *sv)
+do_clean_all(pTHX_ SV *const sv)
 {
     dVAR;
+    if (sv == (const SV *) PL_fdpid || sv == (const SV *)PL_strtab) {
+       /* don't clean pid table and strtab */
+       return;
+    }
     DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning loops: SV at 0x%"UVxf"\n", PTR2UV(sv)) ));
     SvFLAGS(sv) |= SVf_BREAK;
     SvREFCNT_dec(sv);
@@ -589,9 +646,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);
@@ -663,7 +720,7 @@ Perl_sv_free_arenas(pTHX)
    TBD: export properly for hv.c: S_more_he().
 */
 void*
-Perl_get_arena(pTHX_ size_t arena_size, U32 misc)
+Perl_get_arena(pTHX_ const size_t arena_size, const U32 misc)
 {
     dVAR;
     struct arena_desc* adesc;
@@ -869,7 +926,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,
@@ -953,8 +1010,9 @@ static const struct body_details bodies_by_type[] = {
       SVt_PVFM, TRUE, NONV, NOARENA, FIT_ARENA(20, sizeof(xpvfm_allocated)) },
 
     /* XPVIO is 84 bytes, fits 48x */
-    { sizeof(XPVIO), sizeof(XPVIO), 0, SVt_PVIO, TRUE, HADNV,
-      HASARENA, FIT_ARENA(24, sizeof(XPVIO)) },
+    { sizeof(xpvio_allocated), sizeof(xpvio_allocated),
+      + relative_STRUCT_OFFSET(xpvio_allocated, XPVIO, xpv_cur),
+      SVt_PVIO, TRUE, NONV, HASARENA, FIT_ARENA(24, sizeof(xpvio_allocated)) },
 };
 
 #define new_body_type(sv_type)         \
@@ -1026,7 +1084,7 @@ static const struct body_details bodies_by_type[] = {
        my_safecalloc((details)->body_size + (details)->offset)
 
 STATIC void *
-S_more_bodies (pTHX_ svtype sv_type)
+S_more_bodies (pTHX_ const svtype sv_type)
 {
     dVAR;
     void ** const root = &PL_body_roots[sv_type];
@@ -1034,6 +1092,7 @@ S_more_bodies (pTHX_ svtype sv_type)
     const size_t body_size = bdp->body_size;
     char *start;
     const char *end;
+    const size_t arena_size = Perl_malloc_good_size(bdp->arena_size);
 #if defined(DEBUGGING) && !defined(PERL_GLOBAL_STRUCT_PRIVATE)
     static bool done_sanity_check;
 
@@ -1051,20 +1110,28 @@ S_more_bodies (pTHX_ svtype sv_type)
 
     assert(bdp->arena_size);
 
-    start = (char*) Perl_get_arena(aTHX_ bdp->arena_size, sv_type);
+    start = (char*) Perl_get_arena(aTHX_ arena_size, sv_type);
 
-    end = start + bdp->arena_size - body_size;
+    end = start + arena_size - 2 * body_size;
 
     /* computed count doesnt reflect the 1st slot reservation */
+#if defined(MYMALLOC) || defined(HAS_MALLOC_GOOD_SIZE)
+    DEBUG_m(PerlIO_printf(Perl_debug_log,
+                         "arena %p end %p arena-size %d (from %d) type %d "
+                         "size %d ct %d\n",
+                         (void*)start, (void*)end, (int)arena_size,
+                         (int)bdp->arena_size, sv_type, (int)body_size,
+                         (int)arena_size / (int)body_size));
+#else
     DEBUG_m(PerlIO_printf(Perl_debug_log,
                          "arena %p end %p arena-size %d type %d size %d ct %d\n",
                          (void*)start, (void*)end,
                          (int)bdp->arena_size, sv_type, (int)body_size,
                          (int)bdp->arena_size / (int)body_size));
-
+#endif
     *root = (void *)start;
 
-    while (start < end) {
+    while (start <= end) {
        char * const next = start + body_size;
        *(void**) start = (void *)next;
        start = next;
@@ -1089,7 +1156,7 @@ S_more_bodies (pTHX_ svtype sv_type)
 #ifndef PURIFY
 
 STATIC void *
-S_new_body(pTHX_ svtype sv_type)
+S_new_body(pTHX_ const svtype sv_type)
 {
     dVAR;
     void *xpv;
@@ -1113,7 +1180,7 @@ You generally want to use the C<SvUPGRADE> macro wrapper. See also C<svtype>.
 */
 
 void
-Perl_sv_upgrade(pTHX_ register SV *sv, svtype new_type)
+Perl_sv_upgrade(pTHX_ register SV *const sv, svtype new_type)
 {
     dVAR;
     void*      old_body;
@@ -1124,6 +1191,8 @@ Perl_sv_upgrade(pTHX_ register SV *sv, svtype new_type)
        = bodies_by_type + old_type;
     SV *referant = NULL;
 
+    PERL_ARGS_ASSERT_SV_UPGRADE;
+
     if (new_type != SVt_PV && SvIsCOW(sv)) {
        sv_force_normal_flags(sv, 0);
     }
@@ -1397,11 +1466,14 @@ wrapper instead.
 */
 
 int
-Perl_sv_backoff(pTHX_ register SV *sv)
+Perl_sv_backoff(pTHX_ register SV *const sv)
 {
     STRLEN delta;
     const char * const s = SvPVX_const(sv);
+
+    PERL_ARGS_ASSERT_SV_BACKOFF;
     PERL_UNUSED_CONTEXT;
+
     assert(SvOOK(sv));
     assert(SvTYPE(sv) != SVt_PVHV);
     assert(SvTYPE(sv) != SVt_PVAV);
@@ -1426,10 +1498,12 @@ Use the C<SvGROW> wrapper instead.
 */
 
 char *
-Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
+Perl_sv_grow(pTHX_ register SV *const sv, register STRLEN newlen)
 {
     register char *s;
 
+    PERL_ARGS_ASSERT_SV_GROW;
+
     if (PL_madskills && newlen >= 0x100000) {
        PerlIO_printf(Perl_debug_log,
                      "Allocation too large: %"UVxf"\n", (UV)newlen);
@@ -1461,15 +1535,10 @@ Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
        s = SvPVX_mutable(sv);
 
     if (newlen > SvLEN(sv)) {          /* need more room? */
+#ifndef Perl_safesysmalloc_size
        newlen = PERL_STRLEN_ROUNDUP(newlen);
-       if (SvLEN(sv) && s) {
-#ifdef MYMALLOC
-           const STRLEN l = malloced_size((void*)SvPVX_const(sv));
-           if (newlen <= l) {
-               SvLEN_set(sv, l);
-               return s;
-           } else
 #endif
+       if (SvLEN(sv) && s) {
            s = (char*)saferealloc(s, newlen);
        }
        else {
@@ -1479,7 +1548,14 @@ Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
            }
        }
        SvPV_set(sv, s);
+#ifdef Perl_safesysmalloc_size
+       /* Do this here, do it once, do it right, and then we will never get
+          called back into sv_grow() unless there really is some growing
+          needed.  */
+       SvLEN_set(sv, Perl_safesysmalloc_size(s));
+#else
         SvLEN_set(sv, newlen);
+#endif
     }
     return s;
 }
@@ -1494,9 +1570,12 @@ Does not handle 'set' magic.  See also C<sv_setiv_mg>.
 */
 
 void
-Perl_sv_setiv(pTHX_ register SV *sv, IV i)
+Perl_sv_setiv(pTHX_ register SV *const sv, const IV i)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_SV_SETIV;
+
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     switch (SvTYPE(sv)) {
     case SVt_NULL:
@@ -1508,6 +1587,8 @@ Perl_sv_setiv(pTHX_ register SV *sv, IV i)
        break;
 
     case SVt_PVGV:
+       if (!isGV_with_GP(sv))
+           break;
     case SVt_PVAV:
     case SVt_PVHV:
     case SVt_PVCV:
@@ -1531,8 +1612,10 @@ Like C<sv_setiv>, but also handles 'set' magic.
 */
 
 void
-Perl_sv_setiv_mg(pTHX_ register SV *sv, IV i)
+Perl_sv_setiv_mg(pTHX_ register SV *const sv, const IV i)
 {
+    PERL_ARGS_ASSERT_SV_SETIV_MG;
+
     sv_setiv(sv,i);
     SvSETMAGIC(sv);
 }
@@ -1547,8 +1630,10 @@ Does not handle 'set' magic.  See also C<sv_setuv_mg>.
 */
 
 void
-Perl_sv_setuv(pTHX_ register SV *sv, UV u)
+Perl_sv_setuv(pTHX_ register SV *const sv, const UV u)
 {
+    PERL_ARGS_ASSERT_SV_SETUV;
+
     /* With these two if statements:
        u=1.49  s=0.52  cu=72.49  cs=10.64  scripts=270  tests=20865
 
@@ -1575,8 +1660,10 @@ Like C<sv_setuv>, but also handles 'set' magic.
 */
 
 void
-Perl_sv_setuv_mg(pTHX_ register SV *sv, UV u)
+Perl_sv_setuv_mg(pTHX_ register SV *const sv, const UV u)
 {
+    PERL_ARGS_ASSERT_SV_SETUV_MG;
+
     sv_setuv(sv,u);
     SvSETMAGIC(sv);
 }
@@ -1591,9 +1678,12 @@ Does not handle 'set' magic.  See also C<sv_setnv_mg>.
 */
 
 void
-Perl_sv_setnv(pTHX_ register SV *sv, NV num)
+Perl_sv_setnv(pTHX_ register SV *const sv, const NV num)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_SV_SETNV;
+
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     switch (SvTYPE(sv)) {
     case SVt_NULL:
@@ -1606,6 +1696,8 @@ Perl_sv_setnv(pTHX_ register SV *sv, NV num)
        break;
 
     case SVt_PVGV:
+       if (!isGV_with_GP(sv))
+           break;
     case SVt_PVAV:
     case SVt_PVHV:
     case SVt_PVCV:
@@ -1629,8 +1721,10 @@ Like C<sv_setnv>, but also handles 'set' magic.
 */
 
 void
-Perl_sv_setnv_mg(pTHX_ register SV *sv, NV num)
+Perl_sv_setnv_mg(pTHX_ register SV *const sv, const NV num)
 {
+    PERL_ARGS_ASSERT_SV_SETNV_MG;
+
     sv_setnv(sv,num);
     SvSETMAGIC(sv);
 }
@@ -1640,13 +1734,15 @@ Perl_sv_setnv_mg(pTHX_ register SV *sv, NV num)
  */
 
 STATIC void
-S_not_a_number(pTHX_ SV *sv)
+S_not_a_number(pTHX_ SV *const sv)
 {
      dVAR;
      SV *dsv;
      char tmpbuf[64];
      const char *pv;
 
+     PERL_ARGS_ASSERT_NOT_A_NUMBER;
+
      if (DO_UTF8(sv)) {
           dsv = newSVpvs_flags("", SVs_TEMP);
           pv = sv_uni_display(dsv, sv, 10, 0);
@@ -1721,11 +1817,13 @@ non-numeric warning), even if your atof() doesn't grok them.
 */
 
 I32
-Perl_looks_like_number(pTHX_ SV *sv)
+Perl_looks_like_number(pTHX_ SV *const sv)
 {
     register const char *sbegin;
     STRLEN len;
 
+    PERL_ARGS_ASSERT_LOOKS_LIKE_NUMBER;
+
     if (SvPOK(sv)) {
        sbegin = SvPVX_const(sv);
        len = SvCUR(sv);
@@ -1743,6 +1841,8 @@ S_glob_2number(pTHX_ GV * const gv)
     const U32 wasfake = SvFLAGS(gv) & SVf_FAKE;
     SV *const buffer = sv_newmortal();
 
+    PERL_ARGS_ASSERT_GLOB_2NUMBER;
+
     /* FAKE globs can get coerced, so need to turn this off temporarily if it
        is on.  */
     SvFAKE_off(gv);
@@ -1764,6 +1864,8 @@ 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);
@@ -1862,10 +1964,16 @@ S_glob_2pv(pTHX_ GV * const gv, STRLEN * const len)
 
 /* For sv_2nv these three cases are "SvNOK and don't bother casting"  */
 STATIC int
-S_sv_2iuv_non_preserve(pTHX_ register SV *sv, I32 numtype)
+S_sv_2iuv_non_preserve(pTHX_ register SV *const sv
+#  ifdef DEBUGGING
+                      , I32 numtype
+#  endif
+                      )
 {
     dVAR;
-    PERL_UNUSED_ARG(numtype); /* Used only under DEBUGGING? */
+
+    PERL_ARGS_ASSERT_SV_2IUV_NON_PRESERVE;
+
     DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_2iuv_non '%s', IV=0x%"UVxf" NV=%"NVgf" inttype=%"UVXf"\n", SvPVX_const(sv), SvIVX(sv), SvNVX(sv), (UV)numtype));
     if (SvNVX(sv) < (NV)IV_MIN) {
        (void)SvIOKp_on(sv);
@@ -1911,8 +2019,12 @@ S_sv_2iuv_non_preserve(pTHX_ register SV *sv, I32 numtype)
 #endif /* !NV_PRESERVES_UV*/
 
 STATIC bool
-S_sv_2iuv_common(pTHX_ SV *sv) {
+S_sv_2iuv_common(pTHX_ SV *const sv)
+{
     dVAR;
+
+    PERL_ARGS_ASSERT_SV_2IUV_COMMON;
+
     if (SvNOKp(sv)) {
        /* erm. not sure. *should* never get NOKp (without NOK) from sv_2nv
         * without also getting a cached IV/UV from it at the same time
@@ -2143,7 +2255,11 @@ S_sv_2iuv_common(pTHX_ SV *sv) {
                          1      1       already read UV.
                        so there's no point in sv_2iuv_non_preserve() attempting
                        to use atol, strtol, strtoul etc.  */
+#  ifdef DEBUGGING
                     sv_2iuv_non_preserve (sv, numtype);
+#  else
+                    sv_2iuv_non_preserve (sv);
+#  endif
                 }
             }
 #endif /* NV_PRESERVES_UV */
@@ -2157,7 +2273,7 @@ S_sv_2iuv_common(pTHX_ SV *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))
@@ -2183,7 +2299,7 @@ Normally used via the C<SvIV(sv)> and C<SvIVx(sv)> macros.
 */
 
 IV
-Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
+Perl_sv_2iv_flags(pTHX_ register SV *const sv, const I32 flags)
 {
     dVAR;
     if (!sv)
@@ -2267,7 +2383,7 @@ Normally used via the C<SvUV(sv)> and C<SvUVx(sv)> macros.
 */
 
 UV
-Perl_sv_2uv_flags(pTHX_ register SV *sv, I32 flags)
+Perl_sv_2uv_flags(pTHX_ register SV *const sv, const I32 flags)
 {
     dVAR;
     if (!sv)
@@ -2344,7 +2460,7 @@ macros.
 */
 
 NV
-Perl_sv_2nv(pTHX_ register SV *sv)
+Perl_sv_2nv(pTHX_ register SV *const sv)
 {
     dVAR;
     if (!sv)
@@ -2528,7 +2644,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
     }
     else  {
        if (isGV_with_GP(sv)) {
-           glob_2number((GV *)sv);
+           glob_2number(MUTABLE_GV(sv));
            return 0.0;
        }
 
@@ -2569,8 +2685,10 @@ access this function.
 */
 
 SV *
-Perl_sv_2num(pTHX_ register SV *sv)
+Perl_sv_2num(pTHX_ register SV *const sv)
 {
+    PERL_ARGS_ASSERT_SV_2NUM;
+
     if (!SvROK(sv))
        return sv;
     if (SvAMAGIC(sv)) {
@@ -2589,12 +2707,14 @@ Perl_sv_2num(pTHX_ register SV *sv)
  */
 
 static char *
-S_uiv_2buf(char *buf, IV iv, UV uv, int is_uv, char **peob)
+S_uiv_2buf(char *const buf, const IV iv, UV uv, const int is_uv, char **const peob)
 {
     char *ptr = buf + TYPE_CHARS(UV);
     char * const ebuf = ptr;
     int sign;
 
+    PERL_ARGS_ASSERT_UIV_2BUF;
+
     if (is_uv)
        sign = 0;
     else if (iv >= 0) {
@@ -2626,7 +2746,7 @@ usually end up here too.
 */
 
 char *
-Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
+Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags)
 {
     dVAR;
     register char *s;
@@ -2720,13 +2840,13 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, 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);
@@ -2810,10 +2930,12 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
            }
        }
        if (SvREADONLY(sv) && !SvOK(sv)) {
-           if (ckWARN(WARN_UNINITIALIZED))
-               report_uninit(sv);
            if (lp)
                *lp = 0;
+           if (flags & SV_UNDEF_RETURNS_NULL)
+               return NULL;
+           if (ckWARN(WARN_UNINITIALIZED))
+               report_uninit(sv);
            return (char *)"";
        }
     }
@@ -2865,12 +2987,14 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
     }
     else {
        if (isGV_with_GP(sv))
-           return glob_2pv((GV *)sv, lp);
+           return glob_2pv(MUTABLE_GV(sv), lp);
 
-       if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
-           report_uninit(sv);
        if (lp)
            *lp = 0;
+       if (flags & SV_UNDEF_RETURNS_NULL)
+           return NULL;
+       if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
+           report_uninit(sv);
        if (SvTYPE(sv) < SVt_PV)
            /* Typically the caller expects that sv_any is not NULL now.  */
            sv_upgrade(sv, SVt_PV);
@@ -2907,10 +3031,13 @@ would lose the UTF-8'ness of the PV.
 */
 
 void
-Perl_sv_copypv(pTHX_ SV *dsv, register SV *ssv)
+Perl_sv_copypv(pTHX_ SV *const dsv, register SV *const ssv)
 {
     STRLEN len;
     const char * const s = SvPV_const(ssv,len);
+
+    PERL_ARGS_ASSERT_SV_COPYPV;
+
     sv_setpvn(dsv,s,len);
     if (SvUTF8(ssv))
        SvUTF8_on(dsv);
@@ -2931,8 +3058,10 @@ Usually accessed via the C<SvPVbyte> macro.
 */
 
 char *
-Perl_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
+Perl_sv_2pvbyte(pTHX_ register SV *const sv, STRLEN *const lp)
 {
+    PERL_ARGS_ASSERT_SV_2PVBYTE;
+
     sv_utf8_downgrade(sv,0);
     return lp ? SvPV(sv,*lp) : SvPV_nolen(sv);
 }
@@ -2949,8 +3078,10 @@ Usually accessed via the C<SvPVutf8> macro.
 */
 
 char *
-Perl_sv_2pvutf8(pTHX_ register SV *sv, STRLEN *lp)
+Perl_sv_2pvutf8(pTHX_ register SV *const sv, STRLEN *const lp)
 {
+    PERL_ARGS_ASSERT_SV_2PVUTF8;
+
     sv_utf8_upgrade(sv);
     return lp ? SvPV(sv,*lp) : SvPV_nolen(sv);
 }
@@ -2966,9 +3097,12 @@ sv_true() or its macro equivalent.
 */
 
 bool
-Perl_sv_2bool(pTHX_ register SV *sv)
+Perl_sv_2bool(pTHX_ register SV *const sv)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_SV_2BOOL;
+
     SvGETMAGIC(sv);
 
     if (!SvOK(sv))
@@ -3034,9 +3168,12 @@ use the Encode extension for that.
 */
 
 STRLEN
-Perl_sv_utf8_upgrade_flags(pTHX_ register SV *sv, I32 flags)
+Perl_sv_utf8_upgrade_flags(pTHX_ register SV *const sv, const I32 flags)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_SV_UTF8_UPGRADE_FLAGS;
+
     if (sv == &PL_sv_undef)
        return 0;
     if (!SvPOK(sv)) {
@@ -3073,13 +3210,21 @@ Perl_sv_utf8_upgrade_flags(pTHX_ register SV *sv, I32 flags)
            const U8 ch = *t++;
            /* Check for hi bit */
            if (!NATIVE_IS_INVARIANT(ch)) {
-               STRLEN len = SvCUR(sv) + 1; /* Plus the \0 */
+               STRLEN len = SvCUR(sv);
+               /* *Currently* bytes_to_utf8() adds a '\0' after every string
+                  it converts. This isn't documented. It's not clear if it's
+                  a bad thing to be doing, and should be changed to do exactly
+                  what the documentation says. If so, this code will have to
+                  be changed.
+                  As is, 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. */
                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. */
+               SvCUR_set(sv, len);
+               SvLEN_set(sv, len + 1); /* No longer know the real size. */
                break;
            }
        }
@@ -3104,9 +3249,12 @@ use the Encode extension for that.
 */
 
 bool
-Perl_sv_utf8_downgrade(pTHX_ register SV* sv, bool fail_ok)
+Perl_sv_utf8_downgrade(pTHX_ register SV *const sv, const bool fail_ok)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_SV_UTF8_DOWNGRADE;
+
     if (SvPOKp(sv) && SvUTF8(sv)) {
         if (SvCUR(sv)) {
            U8 *s;
@@ -3144,13 +3292,15 @@ flag off so that it looks like octets again.
 */
 
 void
-Perl_sv_utf8_encode(pTHX_ register SV *sv)
+Perl_sv_utf8_encode(pTHX_ register SV *const sv)
 {
+    PERL_ARGS_ASSERT_SV_UTF8_ENCODE;
+
     if (SvIsCOW(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);
@@ -3169,8 +3319,10 @@ Scans PV for validity and returns false if the PV is invalid UTF-8.
 */
 
 bool
-Perl_sv_utf8_decode(pTHX_ register SV *sv)
+Perl_sv_utf8_decode(pTHX_ register SV *const sv)
 {
+    PERL_ARGS_ASSERT_SV_UTF8_DECODE;
+
     if (SvPOKp(sv)) {
         const U8 *c;
         const U8 *e;
@@ -3235,10 +3387,12 @@ copy-ish functions and macros use this underneath.
 */
 
 static void
-S_glob_assign_glob(pTHX_ SV *dstr, SV *sstr, const int dtype)
+S_glob_assign_glob(pTHX_ SV *const dstr, SV *const sstr, const int dtype)
 {
     I32 mro_changes = 0; /* 1 = method, 2 = isa */
 
+    PERL_ARGS_ASSERT_GLOB_ASSIGN_GLOB;
+
     if (dtype != SVt_PVGV) {
        const char * const name = GvNAME(sstr);
        const STRLEN len = GvNAMELEN(sstr);
@@ -3257,18 +3411,18 @@ S_glob_assign_glob(pTHX_ SV *dstr, SV *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);
+    if (GvUNIQUE((const GV *)dstr)) {
+       Perl_croak(aTHX_ "%s", 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));
@@ -3277,20 +3431,20 @@ S_glob_assign_glob(pTHX_ SV *dstr, SV *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);
@@ -3310,7 +3464,8 @@ S_glob_assign_glob(pTHX_ SV *dstr, SV *sstr, const int dtype)
 }
 
 static void
-S_glob_assign_ref(pTHX_ SV *dstr, SV *sstr) {
+S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
+{
     SV * const sref = SvREFCNT_inc(SvRV(sstr));
     SV *dref = NULL;
     const int intro = GvINTRO(dstr);
@@ -3318,17 +3473,18 @@ S_glob_assign_ref(pTHX_ SV *dstr, SV *sstr) {
     U8 import_flag = 0;
     const U32 stype = SvTYPE(sref);
 
+    PERL_ARGS_ASSERT_GLOB_ASSIGN_REF;
 
 #ifdef GV_UNIQUE_CHECK
-    if (GvUNIQUE((GV*)dstr)) {
-       Perl_croak(aTHX_ PL_no_modify);
+    if (GvUNIQUE((const GV *)dstr)) {
+       Perl_croak(aTHX_ "%s", 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) {
@@ -3355,7 +3511,7 @@ S_glob_assign_ref(pTHX_ SV *dstr, SV *sstr) {
     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;
@@ -3367,15 +3523,16 @@ S_glob_assign_ref(pTHX_ SV *dstr, SV *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
@@ -3386,20 +3543,21 @@ S_glob_assign_ref(pTHX_ SV *dstr, SV *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);
            }
@@ -3421,13 +3579,15 @@ S_glob_assign_ref(pTHX_ SV *dstr, SV *sstr) {
 }
 
 void
-Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
+Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
 {
     dVAR;
     register U32 sflags;
     register int dtype;
     register svtype stype;
 
+    PERL_ARGS_ASSERT_SV_SETSV_FLAGS;
+
     if (sstr == dstr)
        return;
 
@@ -3450,7 +3610,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, 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 */
@@ -3604,7 +3763,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, 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
@@ -3646,9 +3805,9 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, 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));
            }
        }
@@ -3837,7 +3996,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, 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
@@ -3856,8 +4015,10 @@ Like C<sv_setsv>, but also handles 'set' magic.
 */
 
 void
-Perl_sv_setsv_mg(pTHX_ SV *dstr, register SV *sstr)
+Perl_sv_setsv_mg(pTHX_ SV *const dstr, register SV *const sstr)
 {
+    PERL_ARGS_ASSERT_SV_SETSV_MG;
+
     sv_setsv(dstr,sstr);
     SvSETMAGIC(dstr);
 }
@@ -3870,6 +4031,8 @@ Perl_sv_setsv_cow(pTHX_ SV *dstr, SV *sstr)
     STRLEN len = SvLEN(sstr);
     register char *new_pv;
 
+    PERL_ARGS_ASSERT_SV_SETSV_COW;
+
     if (DEBUG_C_TEST) {
        PerlIO_printf(Perl_debug_log, "Fast copy on write: %p -> %p\n",
                      (void*)sstr, (void*)dstr);
@@ -3942,11 +4105,13 @@ undefined.  Does not handle 'set' magic.  See C<sv_setpvn_mg>.
 */
 
 void
-Perl_sv_setpvn(pTHX_ register SV *sv, register const char *ptr, register STRLEN len)
+Perl_sv_setpvn(pTHX_ register SV *const sv, register const char *const ptr, register const STRLEN len)
 {
     dVAR;
     register char *dptr;
 
+    PERL_ARGS_ASSERT_SV_SETPVN;
+
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     if (!ptr) {
        (void)SvOK_off(sv);
@@ -3977,8 +4142,10 @@ Like C<sv_setpvn>, but also handles 'set' magic.
 */
 
 void
-Perl_sv_setpvn_mg(pTHX_ register SV *sv, register const char *ptr, register STRLEN len)
+Perl_sv_setpvn_mg(pTHX_ register SV *const sv, register const char *const ptr, register const STRLEN len)
 {
+    PERL_ARGS_ASSERT_SV_SETPVN_MG;
+
     sv_setpvn(sv,ptr,len);
     SvSETMAGIC(sv);
 }
@@ -3993,11 +4160,13 @@ handle 'set' magic.  See C<sv_setpv_mg>.
 */
 
 void
-Perl_sv_setpv(pTHX_ register SV *sv, register const char *ptr)
+Perl_sv_setpv(pTHX_ register SV *const sv, register const char *const ptr)
 {
     dVAR;
     register STRLEN len;
 
+    PERL_ARGS_ASSERT_SV_SETPV;
+
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     if (!ptr) {
        (void)SvOK_off(sv);
@@ -4022,8 +4191,10 @@ Like C<sv_setpv>, but also handles 'set' magic.
 */
 
 void
-Perl_sv_setpv_mg(pTHX_ register SV *sv, register const char *ptr)
+Perl_sv_setpv_mg(pTHX_ register SV *const sv, register const char *const ptr)
 {
+    PERL_ARGS_ASSERT_SV_SETPV_MG;
+
     sv_setpv(sv,ptr);
     SvSETMAGIC(sv);
 }
@@ -4049,10 +4220,13 @@ C<len>, and already meets the requirements for storing in C<SvPVX>)
 */
 
 void
-Perl_sv_usepvn_flags(pTHX_ SV *sv, char *ptr, STRLEN len, U32 flags)
+Perl_sv_usepvn_flags(pTHX_ SV *const sv, char *ptr, const STRLEN len, const U32 flags)
 {
     dVAR;
     STRLEN allocate;
+
+    PERL_ARGS_ASSERT_SV_USEPVN_FLAGS;
+
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     SvUPGRADE(sv, SVt_PV);
     if (!ptr) {
@@ -4070,7 +4244,12 @@ Perl_sv_usepvn_flags(pTHX_ SV *sv, char *ptr, STRLEN len, U32 flags)
 #endif
 
     allocate = (flags & SV_HAS_TRAILING_NUL)
-       ? len + 1: PERL_STRLEN_ROUNDUP(len + 1);
+       ? len + 1 :
+#ifdef Perl_safesysmalloc_size
+       len + 1;
+#else 
+       PERL_STRLEN_ROUNDUP(len + 1);
+#endif
     if (flags & SV_HAS_TRAILING_NUL) {
        /* It's long enough - do nothing.
           Specfically Perl_newCONSTSUB is relying on this.  */
@@ -4086,9 +4265,13 @@ Perl_sv_usepvn_flags(pTHX_ SV *sv, char *ptr, STRLEN len, U32 flags)
        ptr = (char*) saferealloc (ptr, allocate);
 #endif
     }
-    SvPV_set(sv, ptr);
-    SvCUR_set(sv, len);
+#ifdef Perl_safesysmalloc_size
+    SvLEN_set(sv, Perl_safesysmalloc_size(ptr));
+#else
     SvLEN_set(sv, allocate);
+#endif
+    SvCUR_set(sv, len);
+    SvPV_set(sv, ptr);
     if (!(flags & SV_HAS_TRAILING_NUL)) {
        ptr[len] = '\0';
     }
@@ -4107,6 +4290,8 @@ Perl_sv_usepvn_flags(pTHX_ SV *sv, char *ptr, STRLEN len, U32 flags)
 STATIC void
 S_sv_release_COW(pTHX_ register SV *sv, const char *pvx, SV *after)
 {
+    PERL_ARGS_ASSERT_SV_RELEASE_COW;
+
     { /* this SV was SvIsCOW_normal(sv) */
          /* we need to find the SV pointing to us.  */
         SV *current = SV_COW_NEXT_SV(after);
@@ -4151,9 +4336,12 @@ with flags set to 0.
 */
 
 void
-Perl_sv_force_normal_flags(pTHX_ register SV *sv, U32 flags)
+Perl_sv_force_normal_flags(pTHX_ register SV *const sv, const U32 flags)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_SV_FORCE_NORMAL_FLAGS;
+
 #ifdef PERL_OLD_COPY_ON_WRITE
     if (SvREADONLY(sv)) {
         /* At this point I believe I should acquire a global SV mutex.  */
@@ -4196,7 +4384,7 @@ Perl_sv_force_normal_flags(pTHX_ register SV *sv, U32 flags)
             }
        }
        else if (IN_PERL_RUNTIME)
-           Perl_croak(aTHX_ PL_no_modify);
+           Perl_croak(aTHX_ "%s", PL_no_modify);
         /* At this point I believe that I can drop the global SV mutex.  */
     }
 #else
@@ -4214,7 +4402,7 @@ Perl_sv_force_normal_flags(pTHX_ register SV *sv, 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))
@@ -4237,7 +4425,7 @@ refer to the same chunk of data.
 */
 
 void
-Perl_sv_chop(pTHX_ register SV *sv, register const char *ptr)
+Perl_sv_chop(pTHX_ register SV *const sv, register const char *const ptr)
 {
     STRLEN delta;
     STRLEN old_delta;
@@ -4245,6 +4433,9 @@ Perl_sv_chop(pTHX_ register SV *sv, register const char *ptr)
 #ifdef DEBUGGING
     const U8 *real_start;
 #endif
+    STRLEN max_delta;
+
+    PERL_ARGS_ASSERT_SV_CHOP;
 
     if (!ptr || !SvPOKp(sv))
        return;
@@ -4253,8 +4444,17 @@ Perl_sv_chop(pTHX_ register SV *sv, register const char *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 */
@@ -4321,12 +4521,14 @@ in terms of this function.
 */
 
 void
-Perl_sv_catpvn_flags(pTHX_ register SV *dsv, register const char *sstr, register STRLEN slen, I32 flags)
+Perl_sv_catpvn_flags(pTHX_ register SV *const dsv, register const char *sstr, register const STRLEN slen, const I32 flags)
 {
     dVAR;
     STRLEN dlen;
     const char * const dstr = SvPV_force_flags(dsv, dlen, flags);
 
+    PERL_ARGS_ASSERT_SV_CATPVN_FLAGS;
+
     SvGROW(dsv, dlen + slen + 1);
     if (sstr == dstr)
        sstr = SvPVX_const(dsv);
@@ -4356,10 +4558,13 @@ and C<sv_catsv_nomg> are implemented in terms of this function.
 =cut */
 
 void
-Perl_sv_catsv_flags(pTHX_ SV *dsv, register SV *ssv, I32 flags)
+Perl_sv_catsv_flags(pTHX_ SV *const dsv, register SV *const ssv, const I32 flags)
 {
     dVAR;
-    if (ssv) {
+    PERL_ARGS_ASSERT_SV_CATSV_FLAGS;
+
+   if (ssv) {
        STRLEN slen;
        const char *spv = SvPV_const(ssv, slen);
        if (spv) {
@@ -4405,13 +4610,15 @@ valid UTF-8.  Handles 'get' magic, but not 'set' magic.  See C<sv_catpv_mg>.
 =cut */
 
 void
-Perl_sv_catpv(pTHX_ register SV *sv, register const char *ptr)
+Perl_sv_catpv(pTHX_ register SV *const sv, register const char *ptr)
 {
     dVAR;
     register STRLEN len;
     STRLEN tlen;
     char *junk;
 
+    PERL_ARGS_ASSERT_SV_CATPV;
+
     if (!ptr)
        return;
     junk = SvPV_force(sv, tlen);
@@ -4434,8 +4641,10 @@ Like C<sv_catpv>, but also handles 'set' magic.
 */
 
 void
-Perl_sv_catpv_mg(pTHX_ register SV *sv, register const char *ptr)
+Perl_sv_catpv_mg(pTHX_ register SV *const sv, register const char *const ptr)
 {
+    PERL_ARGS_ASSERT_SV_CATPV_MG;
+
     sv_catpv(sv,ptr);
     SvSETMAGIC(sv);
 }
@@ -4458,7 +4667,7 @@ modules supporting older perls.
 */
 
 SV *
-Perl_newSV(pTHX_ STRLEN len)
+Perl_newSV(pTHX_ const STRLEN len)
 {
     dVAR;
     register SV *sv;
@@ -4490,12 +4699,14 @@ to contain an C<SV*> and is stored as-is with its REFCNT incremented.
 =cut
 */
 MAGIC *        
-Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, const MGVTBL *vtable,
-                const char* name, I32 namlen)
+Perl_sv_magicext(pTHX_ SV *const sv, SV *const obj, const int how, 
+                const MGVTBL *const vtable, const char *const name, const I32 namlen)
 {
     dVAR;
     MAGIC* mg;
 
+    PERL_ARGS_ASSERT_SV_MAGICEXT;
+
     SvUPGRADE(sv, SVt_PVMG);
     Newxz(mg, 1, MAGIC);
     mg->mg_moremagic = SvMAGIC(sv);
@@ -4514,9 +4725,9 @@ Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, const MGVTBL *vtable,
        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;
     }
@@ -4534,7 +4745,7 @@ Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, const MGVTBL *vtable,
     */
 
     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);
     }
@@ -4544,9 +4755,13 @@ Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, const MGVTBL *vtable,
     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;
@@ -4573,12 +4788,15 @@ to add more than one instance of the same 'how'.
 */
 
 void
-Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 namlen)
+Perl_sv_magic(pTHX_ register SV *const sv, SV *const obj, const int how, 
+             const char *const name, const I32 namlen)
 {
     dVAR;
     const MGVTBL *vtable;
     MAGIC* mg;
 
+    PERL_ARGS_ASSERT_SV_MAGIC;
+
 #ifdef PERL_OLD_COPY_ON_WRITE
     if (SvIsCOW(sv))
         sv_force_normal_flags(sv, 0);
@@ -4597,7 +4815,7 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
            && 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)) {
@@ -4758,10 +4976,13 @@ Removes all magic of type C<type> from an SV.
 */
 
 int
-Perl_sv_unmagic(pTHX_ SV *sv, int type)
+Perl_sv_unmagic(pTHX_ SV *const sv, const int type)
 {
     MAGIC* mg;
     MAGIC** mgp;
+
+    PERL_ARGS_ASSERT_SV_UNMAGIC;
+
     if (SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv))
        return 0;
     mgp = &(((XPVMG*) SvANY(sv))->xmg_u.xmg_magic);
@@ -4775,7 +4996,7 @@ Perl_sv_unmagic(pTHX_ SV *sv, 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);
             }
@@ -4808,9 +5029,12 @@ called after the RV is cleared.
 */
 
 SV *
-Perl_sv_rvweaken(pTHX_ SV *sv)
+Perl_sv_rvweaken(pTHX_ SV *const sv)
 {
     SV *tsv;
+
+    PERL_ARGS_ASSERT_SV_RVWEAKEN;
+
     if (!SvOK(sv))  /* let undefs pass */
        return sv;
     if (!SvROK(sv))
@@ -4831,14 +5055,34 @@ Perl_sv_rvweaken(pTHX_ SV *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 *tsv, SV *sv)
+Perl_sv_add_backref(pTHX_ SV *const tsv, SV *const sv)
 {
     dVAR;
     AV *av;
 
+    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) {
@@ -4847,7 +5091,7 @@ Perl_sv_add_backref(pTHX_ SV *tsv, SV *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
@@ -4857,7 +5101,7 @@ Perl_sv_add_backref(pTHX_ SV *tsv, SV *sv)
            } else {
                av = newAV();
                AvREAL_off(av);
-               SvREFCNT_inc_simple_void(av);
+               SvREFCNT_inc_simple_void(av); /* see discussion above */
            }
            *avp = av;
        }
@@ -4865,14 +5109,12 @@ Perl_sv_add_backref(pTHX_ SV *tsv, SV *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)) {
@@ -4886,15 +5128,17 @@ Perl_sv_add_backref(pTHX_ SV *tsv, SV *sv)
  */
 
 STATIC void
-S_sv_del_backref(pTHX_ SV *tsv, SV *sv)
+S_sv_del_backref(pTHX_ SV *const tsv, SV *const sv)
 {
     dVAR;
     AV *av = NULL;
     SV **svp;
     I32 i;
 
+    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
@@ -4904,16 +5148,13 @@ S_sv_del_backref(pTHX_ SV *tsv, SV *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
@@ -4936,15 +5177,15 @@ S_sv_del_backref(pTHX_ SV *tsv, SV *sv)
 }
 
 int
-Perl_sv_kill_backrefs(pTHX_ SV *sv, AV *av)
+Perl_sv_kill_backrefs(pTHX_ SV *const sv, AV *const av)
 {
     SV **svp = AvARRAY(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) {
@@ -4960,7 +5201,7 @@ Perl_sv_kill_backrefs(pTHX_ SV *sv, AV *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_
@@ -4981,13 +5222,17 @@ Perl_sv_kill_backrefs(pTHX_ SV *sv, AV *av)
 =for apidoc sv_insert
 
 Inserts a string at the specified offset/length within the SV. Similar to
-the Perl substr() function.
+the Perl substr() function. Handles get magic.
+
+=for apidoc sv_insert_flags
+
+Same as C<sv_insert>, but the extra C<flags> are passed the C<SvPV_force_flags> that applies to C<bigstr>.
 
 =cut
 */
 
 void
-Perl_sv_insert(pTHX_ SV *bigstr, STRLEN offset, STRLEN len, const char *little, STRLEN littlelen)
+Perl_sv_insert_flags(pTHX_ SV *const bigstr, const STRLEN offset, const STRLEN len, const char *const little, const STRLEN littlelen, const U32 flags)
 {
     dVAR;
     register char *big;
@@ -4997,10 +5242,11 @@ Perl_sv_insert(pTHX_ SV *bigstr, STRLEN offset, STRLEN len, const char *little,
     register I32 i;
     STRLEN curlen;
 
+    PERL_ARGS_ASSERT_SV_INSERT_FLAGS;
 
     if (!bigstr)
        Perl_croak(aTHX_ "Can't modify non-existent substring");
-    SvPV_force(bigstr, curlen);
+    SvPV_force_flags(bigstr, curlen, flags);
     (void)SvPOK_only_UTF8(bigstr);
     if (offset + len > curlen) {
        SvGROW(bigstr, offset+len+1);
@@ -5083,10 +5329,13 @@ time you'll want to use C<sv_setsv> or one of its many macro front-ends.
 */
 
 void
-Perl_sv_replace(pTHX_ register SV *sv, register SV *nsv)
+Perl_sv_replace(pTHX_ register SV *const sv, register SV *const nsv)
 {
     dVAR;
     const U32 refcnt = SvREFCNT(sv);
+
+    PERL_ARGS_ASSERT_SV_REPLACE;
+
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     if (SvREFCNT(nsv) != 1) {
        Perl_croak(aTHX_ "panic: reference miscount on nsv in sv_replace() (%"
@@ -5162,7 +5411,7 @@ instead.
 */
 
 void
-Perl_sv_clear(pTHX_ register SV *sv)
+Perl_sv_clear(pTHX_ register SV *const sv)
 {
     dVAR;
     const U32 type = SvTYPE(sv);
@@ -5170,7 +5419,7 @@ Perl_sv_clear(pTHX_ register SV *sv)
        = bodies_by_type + type;
     HV *stash;
 
-    assert(sv);
+    PERL_ARGS_ASSERT_SV_CLEAR;
     assert(SvREFCNT(sv) == 0);
     assert(SvTYPE(sv) != SVTYPEMASK);
 
@@ -5209,7 +5458,7 @@ Perl_sv_clear(pTHX_ register SV *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;
@@ -5258,7 +5507,7 @@ Perl_sv_clear(pTHX_ register SV *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));
@@ -5273,18 +5522,21 @@ Perl_sv_clear(pTHX_ register SV *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 */
@@ -5296,20 +5548,21 @@ Perl_sv_clear(pTHX_ register SV *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:
@@ -5386,7 +5639,7 @@ instead.
 */
 
 SV *
-Perl_sv_newref(pTHX_ SV *sv)
+Perl_sv_newref(pTHX_ SV *const sv)
 {
     PERL_UNUSED_CONTEXT;
     if (sv)
@@ -5406,7 +5659,7 @@ Normally called via a wrapper macro C<SvREFCNT_dec>.
 */
 
 void
-Perl_sv_free(pTHX_ SV *sv)
+Perl_sv_free(pTHX_ SV *const sv)
 {
     dVAR;
     if (!sv)
@@ -5454,9 +5707,12 @@ Perl_sv_free(pTHX_ SV *sv)
 }
 
 void
-Perl_sv_free2(pTHX_ SV *sv)
+Perl_sv_free2(pTHX_ SV *const sv)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_SV_FREE2;
+
 #ifdef DEBUGGING
     if (SvTEMP(sv)) {
        if (ckWARN_d(WARN_DEBUGGING))
@@ -5486,7 +5742,7 @@ coercion.  See also C<SvCUR>, which gives raw access to the xpv_cur slot.
 */
 
 STRLEN
-Perl_sv_len(pTHX_ register SV *sv)
+Perl_sv_len(pTHX_ register SV *const sv)
 {
     STRLEN len;
 
@@ -5519,7 +5775,7 @@ UTF-8 bytes as a single character. Handles magic and type coercion.
  */
 
 STRLEN
-Perl_sv_len_utf8(pTHX_ register SV *sv)
+Perl_sv_len_utf8(pTHX_ register SV *const sv)
 {
     if (!sv)
        return 0;
@@ -5576,6 +5832,8 @@ S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send,
 {
     const U8 *s = start;
 
+    PERL_ARGS_ASSERT_SV_POS_U2B_FORWARDS;
+
     while (s < send && uoffset--)
        s += UTF8SKIP(s);
     if (s > send) {
@@ -5591,9 +5849,12 @@ S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send,
    the passed in UTF-8 offset.  */
 static STRLEN
 S_sv_pos_u2b_midway(const U8 *const start, const U8 *send,
-                     STRLEN uoffset, STRLEN uend)
+                     const STRLEN uoffset, const STRLEN uend)
 {
     STRLEN backw = uend - uoffset;
+
+    PERL_ARGS_ASSERT_SV_POS_U2B_MIDWAY;
+
     if (uoffset < 2 * backw) {
        /* The assumption is that going forwards is twice the speed of going
           forward (that's where the 2 * backw comes from).
@@ -5618,12 +5879,15 @@ S_sv_pos_u2b_midway(const U8 *const start, const U8 *send,
    will be used to reduce the amount of linear searching. The cache will be
    created if necessary, and the found value offered to it for update.  */
 static STRLEN
-S_sv_pos_u2b_cached(pTHX_ SV *sv, MAGIC **mgp, const U8 *const start,
-                   const U8 *const send, STRLEN uoffset,
-                   STRLEN uoffset0, STRLEN boffset0) {
+S_sv_pos_u2b_cached(pTHX_ SV *const sv, MAGIC **const mgp, const U8 *const start,
+                   const U8 *const send, const STRLEN uoffset,
+                   STRLEN uoffset0, STRLEN boffset0)
+{
     STRLEN boffset = 0; /* Actually always set, but let's keep gcc happy.  */
     bool found = FALSE;
 
+    PERL_ARGS_ASSERT_SV_POS_U2B_CACHED;
+
     assert (uoffset >= uoffset0);
 
     if (SvMAGICAL(sv) && !SvREADONLY(sv) && PL_utf8cache
@@ -5711,7 +5975,8 @@ S_sv_pos_u2b_cached(pTHX_ SV *sv, MAGIC **mgp, const U8 *const start,
        boffset = real_boffset;
     }
 
-    S_utf8_mg_pos_cache_update(aTHX_ sv, mgp, boffset, uoffset, send - start);
+    if (PL_utf8cache)
+       utf8_mg_pos_cache_update(sv, mgp, boffset, uoffset, send - start);
     return boffset;
 }
 
@@ -5736,11 +6001,13 @@ type coercion.
  */
 
 void
-Perl_sv_pos_u2b(pTHX_ register SV *sv, I32* offsetp, I32* lenp)
+Perl_sv_pos_u2b(pTHX_ register SV *const sv, I32 *const offsetp, I32 *const lenp)
 {
     const U8 *start;
     STRLEN len;
 
+    PERL_ARGS_ASSERT_SV_POS_U2B;
+
     if (!sv)
        return;
 
@@ -5797,10 +6064,13 @@ Perl_sv_pos_u2b(pTHX_ register SV *sv, I32* offsetp, I32* lenp)
    from.   
 */
 static void
-S_utf8_mg_pos_cache_update(pTHX_ SV *sv, MAGIC **mgp, STRLEN byte, STRLEN utf8,
-                          STRLEN blen)
+S_utf8_mg_pos_cache_update(pTHX_ SV *const sv, MAGIC **const mgp, const STRLEN byte,
+                           const STRLEN utf8, const STRLEN blen)
 {
     STRLEN *cache;
+
+    PERL_ARGS_ASSERT_UTF8_MG_POS_CACHE_UPDATE;
+
     if (SvREADONLY(sv))
        return;
 
@@ -5934,12 +6204,14 @@ S_utf8_mg_pos_cache_update(pTHX_ SV *sv, MAGIC **mgp, STRLEN byte, STRLEN utf8,
    assumption is made as in S_sv_pos_u2b_midway(), namely that walking
    backward is half the speed of walking forward. */
 static STRLEN
-S_sv_pos_b2u_midway(pTHX_ const U8 *s, const U8 *const target, const U8 *end,
-                   STRLEN endu)
+S_sv_pos_b2u_midway(pTHX_ const U8 *const s, const U8 *const target,
+                    const U8 *end, STRLEN endu)
 {
     const STRLEN forw = target - s;
     STRLEN backw = end - target;
 
+    PERL_ARGS_ASSERT_SV_POS_B2U_MIDWAY;
+
     if (forw < 2 * backw) {
        return utf8_length(s, target);
     }
@@ -5971,7 +6243,7 @@ Handles magic and type coercion.
  *
  */
 void
-Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
+Perl_sv_pos_b2u(pTHX_ register SV *const sv, I32 *const offsetp)
 {
     const U8* s;
     const STRLEN byte = *offsetp;
@@ -5981,6 +6253,8 @@ Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
     const U8* send;
     bool found = FALSE;
 
+    PERL_ARGS_ASSERT_SV_POS_B2U;
+
     if (!sv)
        return;
 
@@ -6057,7 +6331,8 @@ Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
     }
     *offsetp = len;
 
-    S_utf8_mg_pos_cache_update(aTHX_ sv, &mg, byte, len, blen);
+    if (PL_utf8cache)
+       utf8_mg_pos_cache_update(sv, &mg, byte, len, blen);
 }
 
 /*
@@ -6172,7 +6447,7 @@ coerce its args to strings if necessary.  See also C<sv_cmp_locale>.
 */
 
 I32
-Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
+Perl_sv_cmp(pTHX_ register SV *const sv1, register SV *const sv2)
 {
     dVAR;
     STRLEN cur1, cur2;
@@ -6248,13 +6523,13 @@ Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
 
 Compares the strings in two SVs in a locale-aware manner. Is UTF-8 and
 'use bytes' aware, handles get magic, and will coerce its args to strings
-if necessary.  See also C<sv_cmp_locale>.  See also C<sv_cmp>.
+if necessary.  See also C<sv_cmp>.
 
 =cut
 */
 
 I32
-Perl_sv_cmp_locale(pTHX_ register SV *sv1, register SV *sv2)
+Perl_sv_cmp_locale(pTHX_ register SV *const sv1, register SV *const sv2)
 {
     dVAR;
 #ifdef USE_LOCALE_COLLATE
@@ -6319,11 +6594,13 @@ settings.
 */
 
 char *
-Perl_sv_collxfrm(pTHX_ SV *sv, STRLEN *nxp)
+Perl_sv_collxfrm(pTHX_ SV *const sv, STRLEN *const nxp)
 {
     dVAR;
     MAGIC *mg;
 
+    PERL_ARGS_ASSERT_SV_COLLXFRM;
+
     mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_collxfrm) : (MAGIC *) NULL;
     if (!mg || !mg->mg_ptr || *(U32*)mg->mg_ptr != PL_collation_ix) {
        const char *s;
@@ -6334,11 +6611,6 @@ Perl_sv_collxfrm(pTHX_ SV *sv, STRLEN *nxp)
            Safefree(mg->mg_ptr);
        s = SvPV_const(sv, len);
        if ((xf = mem_collxfrm(s, len, &xlen))) {
-           if (SvREADONLY(sv)) {
-               SAVEFREEPV(xf);
-               *nxp = xlen;
-               return xf + sizeof(PL_collation_ix);
-           }
            if (! mg) {
 #ifdef PERL_OLD_COPY_ON_WRITE
                if (SvIsCOW(sv))
@@ -6380,7 +6652,7 @@ appending to the currently-stored string.
 */
 
 char *
-Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
+Perl_sv_gets(pTHX_ register SV *const sv, register PerlIO *const fp, I32 append)
 {
     dVAR;
     const char *rsptr;
@@ -6391,6 +6663,8 @@ Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
     I32 i = 0;
     I32 rspara = 0;
 
+    PERL_ARGS_ASSERT_SV_GETS;
+
     if (SvTHINKFIRST(sv))
        sv_force_normal_flags(sv, append ? 0 : SV_COW_DROP_PV);
     /* XXX. If you make this PVIV, then copy on write can copy scalars read
@@ -6448,6 +6722,9 @@ Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *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. */
@@ -6459,13 +6736,19 @@ Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *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;
     }
@@ -6736,7 +7019,7 @@ if necessary. Handles 'get' magic.
 */
 
 void
-Perl_sv_inc(pTHX_ register SV *sv)
+Perl_sv_inc(pTHX_ register SV *const sv)
 {
     dVAR;
     register char *d;
@@ -6750,7 +7033,7 @@ Perl_sv_inc(pTHX_ register SV *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;
@@ -6790,8 +7073,15 @@ Perl_sv_inc(pTHX_ register SV *sv)
        return;
     }
     if (flags & SVp_NOK) {
+       const NV was = SvNVX(sv);
+       if (NV_OVERFLOWS_INTEGERS_AT &&
+           was >= NV_OVERFLOWS_INTEGERS_AT && ckWARN(WARN_IMPRECISION)) {
+           Perl_warner(aTHX_ packWARN(WARN_IMPRECISION),
+                       "Lost precision when incrementing %" NVff " by 1",
+                       was);
+       }
        (void)SvNOK_only(sv);
-        SvNV_set(sv, SvNVX(sv) + 1.0);
+        SvNV_set(sv, was + 1.0);
        return;
     }
 
@@ -6893,7 +7183,7 @@ if necessary. Handles 'get' magic.
 */
 
 void
-Perl_sv_dec(pTHX_ register SV *sv)
+Perl_sv_dec(pTHX_ register SV *const sv)
 {
     dVAR;
     int flags;
@@ -6906,7 +7196,7 @@ Perl_sv_dec(pTHX_ register SV *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;
@@ -6935,8 +7225,10 @@ Perl_sv_dec(pTHX_ register SV *sv)
                SvUV_set(sv, SvUVX(sv) - 1);
            }   
        } else {
-           if (SvIVX(sv) == IV_MIN)
-               sv_setnv(sv, (NV)IV_MIN - 1.0);
+           if (SvIVX(sv) == IV_MIN) {
+               sv_setnv(sv, (NV)IV_MIN);
+               goto oops_its_num;
+           }
            else {
                (void)SvIOK_only(sv);
                SvIV_set(sv, SvIVX(sv) - 1);
@@ -6945,9 +7237,19 @@ Perl_sv_dec(pTHX_ register SV *sv)
        return;
     }
     if (flags & SVp_NOK) {
-        SvNV_set(sv, SvNVX(sv) - 1.0);
-       (void)SvNOK_only(sv);
-       return;
+    oops_its_num:
+       {
+           const NV was = SvNVX(sv);
+           if (NV_OVERFLOWS_INTEGERS_AT &&
+               was <= -NV_OVERFLOWS_INTEGERS_AT && ckWARN(WARN_IMPRECISION)) {
+               Perl_warner(aTHX_ packWARN(WARN_IMPRECISION),
+                           "Lost precision when decrementing %" NVff " by 1",
+                           was);
+           }
+           (void)SvNOK_only(sv);
+           SvNV_set(sv, was - 1.0);
+           return;
+       }
     }
     if (!(flags & SVp_POK)) {
        if ((flags & SVTYPEMASK) < SVt_PVIV)
@@ -7010,7 +7312,7 @@ statement boundaries.  See also C<sv_newmortal> and C<sv_2mortal>.
  * permanent location. */
 
 SV *
-Perl_sv_mortalcopy(pTHX_ SV *oldstr)
+Perl_sv_mortalcopy(pTHX_ SV *const oldstr)
 {
     dVAR;
     register SV *sv;
@@ -7067,7 +7369,7 @@ C<newSVpvn_utf8()> is a convenience wrapper for this function, defined as
 */
 
 SV *
-Perl_newSVpvn_flags(pTHX_ const char *s, STRLEN len, U32 flags)
+Perl_newSVpvn_flags(pTHX_ const char *const s, const STRLEN len, const U32 flags)
 {
     dVAR;
     register SV *sv;
@@ -7094,7 +7396,7 @@ and C<sv_mortalcopy>.
 */
 
 SV *
-Perl_sv_2mortal(pTHX_ register SV *sv)
+Perl_sv_2mortal(pTHX_ register SV *const sv)
 {
     dVAR;
     if (!sv)
@@ -7118,7 +7420,7 @@ strlen().  For efficiency, consider using C<newSVpvn> instead.
 */
 
 SV *
-Perl_newSVpv(pTHX_ const char *s, STRLEN len)
+Perl_newSVpv(pTHX_ const char *const s, const STRLEN len)
 {
     dVAR;
     register SV *sv;
@@ -7140,7 +7442,7 @@ C<len> bytes long.  If the C<s> argument is NULL the new SV will be undefined.
 */
 
 SV *
-Perl_newSVpvn(pTHX_ const char *s, STRLEN len)
+Perl_newSVpvn(pTHX_ const char *const s, const STRLEN len)
 {
     dVAR;
     register SV *sv;
@@ -7161,7 +7463,7 @@ SV if the hek is NULL.
 */
 
 SV *
-Perl_newSVhek(pTHX_ const HEK *hek)
+Perl_newSVhek(pTHX_ const HEK *const hek)
 {
     dVAR;
     if (!hek) {
@@ -7254,6 +7556,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);
@@ -7277,11 +7581,14 @@ Perl_newSVpvn_share(pTHX_ const char *src, I32 len, U32 hash)
  */
 
 SV *
-Perl_newSVpvf_nocontext(const char* pat, ...)
+Perl_newSVpvf_nocontext(const char *const pat, ...)
 {
     dTHX;
     register SV *sv;
     va_list args;
+
+    PERL_ARGS_ASSERT_NEWSVPVF_NOCONTEXT;
+
     va_start(args, pat);
     sv = vnewSVpvf(pat, &args);
     va_end(args);
@@ -7299,10 +7606,13 @@ C<sprintf>.
 */
 
 SV *
-Perl_newSVpvf(pTHX_ const char* pat, ...)
+Perl_newSVpvf(pTHX_ const char *const pat, ...)
 {
     register SV *sv;
     va_list args;
+
+    PERL_ARGS_ASSERT_NEWSVPVF;
+
     va_start(args, pat);
     sv = vnewSVpvf(pat, &args);
     va_end(args);
@@ -7312,10 +7622,13 @@ Perl_newSVpvf(pTHX_ const char* pat, ...)
 /* backend for newSVpvf() and newSVpvf_nocontext() */
 
 SV *
-Perl_vnewSVpvf(pTHX_ const char* pat, va_list* args)
+Perl_vnewSVpvf(pTHX_ const char *const pat, va_list *const args)
 {
     dVAR;
     register SV *sv;
+
+    PERL_ARGS_ASSERT_VNEWSVPVF;
+
     new_SV(sv);
     sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
     return sv;
@@ -7331,7 +7644,7 @@ The reference count for the SV is set to 1.
 */
 
 SV *
-Perl_newSVnv(pTHX_ NV n)
+Perl_newSVnv(pTHX_ const NV n)
 {
     dVAR;
     register SV *sv;
@@ -7351,7 +7664,7 @@ SV is set to 1.
 */
 
 SV *
-Perl_newSViv(pTHX_ IV i)
+Perl_newSViv(pTHX_ const IV i)
 {
     dVAR;
     register SV *sv;
@@ -7371,7 +7684,7 @@ The reference count for the SV is set to 1.
 */
 
 SV *
-Perl_newSVuv(pTHX_ UV u)
+Perl_newSVuv(pTHX_ const UV u)
 {
     dVAR;
     register SV *sv;
@@ -7391,7 +7704,7 @@ is set to 1.
 */
 
 SV *
-Perl_newSV_type(pTHX_ svtype type)
+Perl_newSV_type(pTHX_ const svtype type)
 {
     register SV *sv;
 
@@ -7410,10 +7723,13 @@ SV is B<not> incremented.
 */
 
 SV *
-Perl_newRV_noinc(pTHX_ SV *tmpRef)
+Perl_newRV_noinc(pTHX_ SV *const tmpRef)
 {
     dVAR;
     register SV *sv = newSV_type(SVt_IV);
+
+    PERL_ARGS_ASSERT_NEWRV_NOINC;
+
     SvTEMP_off(tmpRef);
     SvRV_set(sv, tmpRef);
     SvROK_on(sv);
@@ -7425,9 +7741,12 @@ Perl_newRV_noinc(pTHX_ SV *tmpRef)
  */
 
 SV *
-Perl_newRV(pTHX_ SV *sv)
+Perl_newRV(pTHX_ SV *const sv)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_NEWRV;
+
     return newRV_noinc(SvREFCNT_inc_simple_NN(sv));
 }
 
@@ -7441,7 +7760,7 @@ Creates a new SV which is an exact duplicate of the original SV.
 */
 
 SV *
-Perl_newSVsv(pTHX_ register SV *old)
+Perl_newSVsv(pTHX_ register SV *const old)
 {
     dVAR;
     register SV *sv;
@@ -7471,16 +7790,18 @@ Note that the perl-level function is vaguely deprecated.
 */
 
 void
-Perl_sv_reset(pTHX_ register const char *s, HV *stash)
+Perl_sv_reset(pTHX_ register const char *s, HV *const stash)
 {
     dVAR;
     char todo[PERL_UCHAR_MAX+1];
 
+    PERL_ARGS_ASSERT_SV_RESET;
+
     if (!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;
@@ -7525,7 +7846,7 @@ Perl_sv_reset(pTHX_ register const char *s, HV *stash)
 
                if (!todo[(U8)*HeKEY(entry)])
                    continue;
-               gv = (GV*)HeVAL(entry);
+               gv = MUTABLE_GV(HeVAL(entry));
                sv = GvSV(gv);
                if (sv) {
                    if (SvTHINKFIRST(sv)) {
@@ -7573,21 +7894,26 @@ named after the PV if we're a string.
 */
 
 IO*
-Perl_sv_2io(pTHX_ SV *sv)
+Perl_sv_2io(pTHX_ SV *const sv)
 {
     IO* io;
     GV* gv;
 
+    PERL_ARGS_ASSERT_SV_2IO;
+
     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");
@@ -7616,12 +7942,14 @@ The flags in C<lref> are passed to sv_fetchsv.
 */
 
 CV *
-Perl_sv_2cv(pTHX_ SV *sv, HV **st, GV **gvp, I32 lref)
+Perl_sv_2cv(pTHX_ SV *sv, HV **const st, GV **const gvp, const I32 lref)
 {
     dVAR;
     GV *gv = NULL;
     CV *cv = NULL;
 
+    PERL_ARGS_ASSERT_SV_2CV;
+
     if (!sv) {
        *st = NULL;
        *gvp = NULL;
@@ -7631,47 +7959,52 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **st, GV **gvp, 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;
        }
@@ -7691,7 +8024,7 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **st, GV **gvp, I32 lref)
            LEAVE;
            if (!GvCVu(gv))
                Perl_croak(aTHX_ "Unable to create sub named \"%"SVf"\"",
-                          SVfARG(sv));
+                          SVfARG(SvOK(sv) ? sv : &PL_sv_no));
        }
        return GvCVu(gv);
     }
@@ -7708,7 +8041,7 @@ instead use an in-line version.
 */
 
 I32
-Perl_sv_true(pTHX_ register SV *sv)
+Perl_sv_true(pTHX_ register SV *const sv)
 {
     if (!sv)
        return 0;
@@ -7753,9 +8086,12 @@ C<SvPV_force> and C<SvPV_force_nomg>
 */
 
 char *
-Perl_sv_pvn_force_flags(pTHX_ SV *sv, STRLEN *lp, I32 flags)
+Perl_sv_pvn_force_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_SV_PVN_FORCE_FLAGS;
+
     if (SvTHINKFIRST(sv) && !SvROK(sv))
         sv_force_normal_flags(sv, 0);
 
@@ -7811,8 +8147,10 @@ The backend for the C<SvPVbytex_force> macro. Always use the macro instead.
 */
 
 char *
-Perl_sv_pvbyten_force(pTHX_ SV *sv, STRLEN *lp)
+Perl_sv_pvbyten_force(pTHX_ SV *const sv, STRLEN *const lp)
 {
+    PERL_ARGS_ASSERT_SV_PVBYTEN_FORCE;
+
     sv_pvn_force(sv,lp);
     sv_utf8_downgrade(sv,0);
     *lp = SvCUR(sv);
@@ -7828,8 +8166,10 @@ The backend for the C<SvPVutf8x_force> macro. Always use the macro instead.
 */
 
 char *
-Perl_sv_pvutf8n_force(pTHX_ SV *sv, STRLEN *lp)
+Perl_sv_pvutf8n_force(pTHX_ SV *const sv, STRLEN *const lp)
 {
+    PERL_ARGS_ASSERT_SV_PVUTF8N_FORCE;
+
     sv_pvn_force(sv,lp);
     sv_utf8_upgrade(sv);
     *lp = SvCUR(sv);
@@ -7845,8 +8185,10 @@ Returns a string describing what the SV is a reference to.
 */
 
 const char *
-Perl_sv_reftype(pTHX_ const SV *sv, int ob)
+Perl_sv_reftype(pTHX_ const SV *const sv, const int ob)
 {
+    PERL_ARGS_ASSERT_SV_REFTYPE;
+
     /* The fact that I don't need to downcast to char * everywhere, only in ?:
        inside return suggests a const propagation bug in g++.  */
     if (ob && SvOBJECT(sv)) {
@@ -7877,7 +8219,8 @@ Perl_sv_reftype(pTHX_ const SV *sv, 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";
@@ -7905,7 +8248,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;
@@ -7922,15 +8265,18 @@ an inheritance relationship.
 */
 
 int
-Perl_sv_isa(pTHX_ SV *sv, const char *name)
+Perl_sv_isa(pTHX_ SV *sv, const char *const name)
 {
     const char *hvname;
+
+    PERL_ARGS_ASSERT_SV_ISA;
+
     if (!sv)
        return 0;
     SvGETMAGIC(sv);
     if (!SvROK(sv))
        return 0;
-    sv = (SV*)SvRV(sv);
+    sv = SvRV(sv);
     if (!SvOBJECT(sv))
        return 0;
     hvname = HvNAME_get(SvSTASH(sv));
@@ -7952,11 +8298,13 @@ reference count is 1.
 */
 
 SV*
-Perl_newSVrv(pTHX_ SV *rv, const char *classname)
+Perl_newSVrv(pTHX_ SV *const rv, const char *const classname)
 {
     dVAR;
     SV *sv;
 
+    PERL_ARGS_ASSERT_NEWSVRV;
+
     new_SV(sv);
 
     SV_CHECK_THINKFIRST_COW_DROP(rv);
@@ -8006,9 +8354,12 @@ Note that C<sv_setref_pvn> copies the string while this copies the pointer.
 */
 
 SV*
-Perl_sv_setref_pv(pTHX_ SV *rv, const char *classname, void *pv)
+Perl_sv_setref_pv(pTHX_ SV *const rv, const char *const classname, void *const pv)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_SV_SETREF_PV;
+
     if (!pv) {
        sv_setsv(rv, &PL_sv_undef);
        SvSETMAGIC(rv);
@@ -8031,8 +8382,10 @@ will have a reference count of 1, and the RV will be returned.
 */
 
 SV*
-Perl_sv_setref_iv(pTHX_ SV *rv, const char *classname, IV iv)
+Perl_sv_setref_iv(pTHX_ SV *const rv, const char *const classname, const IV iv)
 {
+    PERL_ARGS_ASSERT_SV_SETREF_IV;
+
     sv_setiv(newSVrv(rv,classname), iv);
     return rv;
 }
@@ -8050,8 +8403,10 @@ will have a reference count of 1, and the RV will be returned.
 */
 
 SV*
-Perl_sv_setref_uv(pTHX_ SV *rv, const char *classname, UV uv)
+Perl_sv_setref_uv(pTHX_ SV *const rv, const char *const classname, const UV uv)
 {
+    PERL_ARGS_ASSERT_SV_SETREF_UV;
+
     sv_setuv(newSVrv(rv,classname), uv);
     return rv;
 }
@@ -8069,8 +8424,10 @@ will have a reference count of 1, and the RV will be returned.
 */
 
 SV*
-Perl_sv_setref_nv(pTHX_ SV *rv, const char *classname, NV nv)
+Perl_sv_setref_nv(pTHX_ SV *const rv, const char *const classname, const NV nv)
 {
+    PERL_ARGS_ASSERT_SV_SETREF_NV;
+
     sv_setnv(newSVrv(rv,classname), nv);
     return rv;
 }
@@ -8091,8 +8448,11 @@ Note that C<sv_setref_pv> copies the pointer while this copies the string.
 */
 
 SV*
-Perl_sv_setref_pvn(pTHX_ SV *rv, const char *classname, const char *pv, STRLEN n)
+Perl_sv_setref_pvn(pTHX_ SV *const rv, const char *const classname,
+                   const char *const pv, const STRLEN n)
 {
+    PERL_ARGS_ASSERT_SV_SETREF_PVN;
+
     sv_setpvn(newSVrv(rv,classname), pv, n);
     return rv;
 }
@@ -8108,10 +8468,13 @@ of the SV is unaffected.
 */
 
 SV*
-Perl_sv_bless(pTHX_ SV *sv, HV *stash)
+Perl_sv_bless(pTHX_ SV *const sv, HV *const stash)
 {
     dVAR;
     SV *tmpRef;
+
+    PERL_ARGS_ASSERT_SV_BLESS;
+
     if (!SvROK(sv))
         Perl_croak(aTHX_ "Can't bless non-reference value");
     tmpRef = SvRV(sv);
@@ -8119,7 +8482,7 @@ Perl_sv_bless(pTHX_ SV *sv, HV *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;
@@ -8130,7 +8493,7 @@ Perl_sv_bless(pTHX_ SV *sv, HV *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);
@@ -8150,24 +8513,27 @@ Perl_sv_bless(pTHX_ SV *sv, HV *stash)
  */
 
 STATIC void
-S_sv_unglob(pTHX_ SV *sv)
+S_sv_unglob(pTHX_ SV *const sv)
 {
     dVAR;
     void *xpvmg;
     HV *stash;
     SV * const temp = sv_newmortal();
 
+    PERL_ARGS_ASSERT_SV_UNGLOB;
+
     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);
@@ -8205,10 +8571,12 @@ See C<SvROK_off>.
 */
 
 void
-Perl_sv_unref_flags(pTHX_ SV *ref, U32 flags)
+Perl_sv_unref_flags(pTHX_ SV *const ref, const U32 flags)
 {
     SV* const target = SvRV(ref);
 
+    PERL_ARGS_ASSERT_SV_UNREF_FLAGS;
+
     if (SvWEAKREF(ref)) {
        sv_del_backref(target, ref);
        SvWEAKREF_off(ref);
@@ -8233,8 +8601,10 @@ Untaint an SV. Use C<SvTAINTED_off> instead.
 */
 
 void
-Perl_sv_untaint(pTHX_ SV *sv)
+Perl_sv_untaint(pTHX_ SV *const sv)
 {
+    PERL_ARGS_ASSERT_SV_UNTAINT;
+
     if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
        MAGIC * const mg = mg_find(sv, PERL_MAGIC_taint);
        if (mg)
@@ -8250,8 +8620,10 @@ Test an SV for taintedness. Use C<SvTAINTED> instead.
 */
 
 bool
-Perl_sv_tainted(pTHX_ SV *sv)
+Perl_sv_tainted(pTHX_ SV *const sv)
 {
+    PERL_ARGS_ASSERT_SV_TAINTED;
+
     if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
        const MAGIC * const mg = mg_find(sv, PERL_MAGIC_taint);
        if (mg && (mg->mg_len & 1) )
@@ -8270,12 +8642,14 @@ Does not handle 'set' magic.  See C<sv_setpviv_mg>.
 */
 
 void
-Perl_sv_setpviv(pTHX_ SV *sv, IV iv)
+Perl_sv_setpviv(pTHX_ SV *const sv, const IV iv)
 {
     char buf[TYPE_CHARS(UV)];
     char *ebuf;
     char * const ptr = uiv_2buf(buf, iv, 0, 0, &ebuf);
 
+    PERL_ARGS_ASSERT_SV_SETPVIV;
+
     sv_setpvn(sv, ptr, ebuf - ptr);
 }
 
@@ -8288,8 +8662,10 @@ Like C<sv_setpviv>, but also handles 'set' magic.
 */
 
 void
-Perl_sv_setpviv_mg(pTHX_ SV *sv, IV iv)
+Perl_sv_setpviv_mg(pTHX_ SV *const sv, const IV iv)
 {
+    PERL_ARGS_ASSERT_SV_SETPVIV_MG;
+
     sv_setpviv(sv, iv);
     SvSETMAGIC(sv);
 }
@@ -8302,10 +8678,13 @@ Perl_sv_setpviv_mg(pTHX_ SV *sv, IV iv)
  */
 
 void
-Perl_sv_setpvf_nocontext(SV *sv, const char* pat, ...)
+Perl_sv_setpvf_nocontext(SV *const sv, const char *const pat, ...)
 {
     dTHX;
     va_list args;
+
+    PERL_ARGS_ASSERT_SV_SETPVF_NOCONTEXT;
+
     va_start(args, pat);
     sv_vsetpvf(sv, pat, &args);
     va_end(args);
@@ -8317,10 +8696,13 @@ Perl_sv_setpvf_nocontext(SV *sv, const char* pat, ...)
  */
 
 void
-Perl_sv_setpvf_mg_nocontext(SV *sv, const char* pat, ...)
+Perl_sv_setpvf_mg_nocontext(SV *const sv, const char *const pat, ...)
 {
     dTHX;
     va_list args;
+
+    PERL_ARGS_ASSERT_SV_SETPVF_MG_NOCONTEXT;
+
     va_start(args, pat);
     sv_vsetpvf_mg(sv, pat, &args);
     va_end(args);
@@ -8337,9 +8719,12 @@ appending it.  Does not handle 'set' magic.  See C<sv_setpvf_mg>.
 */
 
 void
-Perl_sv_setpvf(pTHX_ SV *sv, const char* pat, ...)
+Perl_sv_setpvf(pTHX_ SV *const sv, const char *const pat, ...)
 {
     va_list args;
+
+    PERL_ARGS_ASSERT_SV_SETPVF;
+
     va_start(args, pat);
     sv_vsetpvf(sv, pat, &args);
     va_end(args);
@@ -8357,8 +8742,10 @@ Usually used via its frontend C<sv_setpvf>.
 */
 
 void
-Perl_sv_vsetpvf(pTHX_ SV *sv, const char* pat, va_list* args)
+Perl_sv_vsetpvf(pTHX_ SV *const sv, const char *const pat, va_list *const args)
 {
+    PERL_ARGS_ASSERT_SV_VSETPVF;
+
     sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
 }
 
@@ -8371,9 +8758,12 @@ Like C<sv_setpvf>, but also handles 'set' magic.
 */
 
 void
-Perl_sv_setpvf_mg(pTHX_ SV *sv, const char* pat, ...)
+Perl_sv_setpvf_mg(pTHX_ SV *const sv, const char *const pat, ...)
 {
     va_list args;
+
+    PERL_ARGS_ASSERT_SV_SETPVF_MG;
+
     va_start(args, pat);
     sv_vsetpvf_mg(sv, pat, &args);
     va_end(args);
@@ -8390,8 +8780,10 @@ Usually used via its frontend C<sv_setpvf_mg>.
 */
 
 void
-Perl_sv_vsetpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
+Perl_sv_vsetpvf_mg(pTHX_ SV *const sv, const char *const pat, va_list *const args)
 {
+    PERL_ARGS_ASSERT_SV_VSETPVF_MG;
+
     sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
     SvSETMAGIC(sv);
 }
@@ -8404,10 +8796,13 @@ Perl_sv_vsetpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
  */
 
 void
-Perl_sv_catpvf_nocontext(SV *sv, const char* pat, ...)
+Perl_sv_catpvf_nocontext(SV *const sv, const char *const pat, ...)
 {
     dTHX;
     va_list args;
+
+    PERL_ARGS_ASSERT_SV_CATPVF_NOCONTEXT;
+
     va_start(args, pat);
     sv_vcatpvf(sv, pat, &args);
     va_end(args);
@@ -8419,10 +8814,13 @@ Perl_sv_catpvf_nocontext(SV *sv, const char* pat, ...)
  */
 
 void
-Perl_sv_catpvf_mg_nocontext(SV *sv, const char* pat, ...)
+Perl_sv_catpvf_mg_nocontext(SV *const sv, const char *const pat, ...)
 {
     dTHX;
     va_list args;
+
+    PERL_ARGS_ASSERT_SV_CATPVF_MG_NOCONTEXT;
+
     va_start(args, pat);
     sv_vcatpvf_mg(sv, pat, &args);
     va_end(args);
@@ -8443,9 +8841,12 @@ valid UTF-8; if the original SV was bytes, the pattern should be too.
 =cut */
 
 void
-Perl_sv_catpvf(pTHX_ SV *sv, const char* pat, ...)
+Perl_sv_catpvf(pTHX_ SV *const sv, const char *const pat, ...)
 {
     va_list args;
+
+    PERL_ARGS_ASSERT_SV_CATPVF;
+
     va_start(args, pat);
     sv_vcatpvf(sv, pat, &args);
     va_end(args);
@@ -8463,8 +8864,10 @@ Usually used via its frontend C<sv_catpvf>.
 */
 
 void
-Perl_sv_vcatpvf(pTHX_ SV *sv, const char* pat, va_list* args)
+Perl_sv_vcatpvf(pTHX_ SV *const sv, const char *const pat, va_list *const args)
 {
+    PERL_ARGS_ASSERT_SV_VCATPVF;
+
     sv_vcatpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
 }
 
@@ -8477,9 +8880,12 @@ Like C<sv_catpvf>, but also handles 'set' magic.
 */
 
 void
-Perl_sv_catpvf_mg(pTHX_ SV *sv, const char* pat, ...)
+Perl_sv_catpvf_mg(pTHX_ SV *const sv, const char *const pat, ...)
 {
     va_list args;
+
+    PERL_ARGS_ASSERT_SV_CATPVF_MG;
+
     va_start(args, pat);
     sv_vcatpvf_mg(sv, pat, &args);
     va_end(args);
@@ -8496,8 +8902,10 @@ Usually used via its frontend C<sv_catpvf_mg>.
 */
 
 void
-Perl_sv_vcatpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
+Perl_sv_vcatpvf_mg(pTHX_ SV *const sv, const char *const pat, va_list *const args)
 {
+    PERL_ARGS_ASSERT_SV_VCATPVF_MG;
+
     sv_vcatpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
     SvSETMAGIC(sv);
 }
@@ -8514,17 +8922,23 @@ Usually used via one of its frontends C<sv_vsetpvf> and C<sv_vsetpvf_mg>.
 */
 
 void
-Perl_sv_vsetpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV **svargs, I32 svmax, bool *maybe_tainted)
+Perl_sv_vsetpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
+                 va_list *const args, SV **const svargs, const I32 svmax, bool *const maybe_tainted)
 {
-    sv_setpvn(sv, "", 0);
+    PERL_ARGS_ASSERT_SV_VSETPVFN;
+
+    sv_setpvs(sv, "");
     sv_vcatpvfn(sv, pat, patlen, args, svargs, svmax, maybe_tainted);
 }
 
 STATIC I32
-S_expect_number(pTHX_ char** pattern)
+S_expect_number(pTHX_ char **const pattern)
 {
     dVAR;
     I32 var = 0;
+
+    PERL_ARGS_ASSERT_EXPECT_NUMBER;
+
     switch (**pattern) {
     case '1': case '2': case '3':
     case '4': case '5': case '6':
@@ -8541,11 +8955,13 @@ S_expect_number(pTHX_ char** pattern)
 }
 
 STATIC char *
-S_F0convert(NV nv, char *endbuf, STRLEN *len)
+S_F0convert(NV nv, char *const endbuf, STRLEN *const len)
 {
     const int neg = nv < 0;
     UV uv;
 
+    PERL_ARGS_ASSERT_F0CONVERT;
+
     if (neg)
        nv = -nv;
     if (nv < UV_MAX) {
@@ -8589,7 +9005,8 @@ Usually used via one of its frontends C<sv_vcatpvf> and C<sv_vcatpvf_mg>.
 /* XXX maybe_tainted is never assigned to, so the doc above is lying. */
 
 void
-Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV **svargs, I32 svmax, bool *maybe_tainted)
+Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
+                 va_list *const args, SV **const svargs, const I32 svmax, bool *const maybe_tainted)
 {
     dVAR;
     char *p;
@@ -8609,6 +9026,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
     /* large enough for "%#.#f" --chip */
     /* what about long double NVs? --jhi */
 
+    PERL_ARGS_ASSERT_SV_VCATPVFN;
     PERL_UNUSED_ARG(maybe_tainted);
 
     /* no matter what, this is a string now */
@@ -8629,7 +9047,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
     }
     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;
     }
@@ -8704,6 +9122,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        STRLEN esignlen = 0;
 
        const char *eptr = NULL;
+       const char *fmtstart;
        STRLEN elen = 0;
        SV *vecsv = NULL;
        const U8 *vecstr = NULL;
@@ -8744,6 +9163,8 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        if (q++ >= patend)
            break;
 
+       fmtstart = q;
+
 /*
     We allow format specification elements in this order:
        \d+\$              explicit format parameter index
@@ -8786,7 +9207,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                        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;
@@ -8906,7 +9327,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                 */
                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;
@@ -9139,8 +9560,11 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                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
                }
            }
@@ -9151,8 +9575,11 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                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
                }
            }
@@ -9224,8 +9651,11 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                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
                }
            }
@@ -9236,8 +9666,11 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                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
                }
            }
@@ -9523,8 +9956,11 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                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
                }
            }
@@ -9543,16 +9979,22 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                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 */
            }
 
@@ -9594,13 +10036,13 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 
        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') {
@@ -9681,26 +10123,28 @@ ptr_table_* functions.
    If this changes, please unmerge ss_dup.  */
 #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)
 
 /* clone a parser */
 
 yy_parser *
-Perl_parser_dup(pTHX_ const yy_parser *proto, CLONE_PARAMS* param)
+Perl_parser_dup(pTHX_ const yy_parser *const proto, CLONE_PARAMS *const param)
 {
     yy_parser *parser;
 
+    PERL_ARGS_ASSERT_PARSER_DUP;
+
     if (!proto)
        return NULL;
 
@@ -9814,10 +10258,11 @@ Perl_parser_dup(pTHX_ const yy_parser *proto, CLONE_PARAMS* param)
 /* duplicate a file handle */
 
 PerlIO *
-Perl_fp_dup(pTHX_ PerlIO *fp, char type, CLONE_PARAMS *param)
+Perl_fp_dup(pTHX_ PerlIO *const fp, const char type, CLONE_PARAMS *const param)
 {
     PerlIO *ret;
 
+    PERL_ARGS_ASSERT_FP_DUP;
     PERL_UNUSED_ARG(type);
 
     if (!fp)
@@ -9837,7 +10282,7 @@ Perl_fp_dup(pTHX_ PerlIO *fp, char type, CLONE_PARAMS *param)
 /* duplicate a directory handle */
 
 DIR *
-Perl_dirp_dup(pTHX_ DIR *dp)
+Perl_dirp_dup(pTHX_ DIR *const dp)
 {
     PERL_UNUSED_CONTEXT;
     if (!dp)
@@ -9849,10 +10294,12 @@ Perl_dirp_dup(pTHX_ DIR *dp)
 /* duplicate a typeglob */
 
 GP *
-Perl_gp_dup(pTHX_ GP *gp, CLONE_PARAMS* param)
+Perl_gp_dup(pTHX_ GP *const gp, CLONE_PARAMS *const param)
 {
     GP *ret;
 
+    PERL_ARGS_ASSERT_GP_DUP;
+
     if (!gp)
        return (GP*)NULL;
     /* look for it in the table first */
@@ -9882,10 +10329,13 @@ Perl_gp_dup(pTHX_ GP *gp, CLONE_PARAMS* param)
 /* duplicate a chain of magic */
 
 MAGIC *
-Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS* param)
+Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *const param)
 {
     MAGIC *mgprev = (MAGIC*)NULL;
     MAGIC *mgret;
+
+    PERL_ARGS_ASSERT_MG_DUP;
+
     if (!mg)
        return (MAGIC*)NULL;
     /* look for it in the table first */
@@ -9906,14 +10356,15 @@ Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS* param)
        nmg->mg_flags   = mg->mg_flags;
        /* FIXME for plugins
        if (mg->mg_type == PERL_MAGIC_qr) {
-           nmg->mg_obj = (SV*)CALLREGDUPE((REGEXP*)mg->mg_obj, param);
+           nmg->mg_obj = MUTABLE_SV(CALLREGDUPE((REGEXP*)mg->mg_obj, param));
        }
        else
        */
        if(mg->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 *) mg->mg_obj, param));
        }
        else {
            nmg->mg_obj = (mg->mg_flags & MGf_REFCOUNTED)
@@ -9937,7 +10388,7 @@ Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS* param)
                }
            }
            else if (mg->mg_len == HEf_SVKEY)
-               nmg->mg_ptr     = (char*)sv_dup_inc((SV*)mg->mg_ptr, param);
+               nmg->mg_ptr = (char*)sv_dup_inc((const SV *)mg->mg_ptr, param);
        }
        if ((mg->mg_flags & MGf_DUP) && mg->mg_virtual && mg->mg_virtual->svt_dup) {
            CALL_FPTR(nmg->mg_virtual->svt_dup)(aTHX_ nmg, param);
@@ -9978,10 +10429,13 @@ Perl_ptr_table_new(pTHX)
 /* map an existing pointer using a table */
 
 STATIC PTR_TBL_ENT_t *
-S_ptr_table_find(PTR_TBL_t *tbl, const void *sv) {
+S_ptr_table_find(PTR_TBL_t *const tbl, const void *const sv)
+{
     PTR_TBL_ENT_t *tblent;
     const UV hash = PTR_TABLE_HASH(sv);
-    assert(tbl);
+
+    PERL_ARGS_ASSERT_PTR_TABLE_FIND;
+
     tblent = tbl->tbl_ary[hash & tbl->tbl_max];
     for (; tblent; tblent = tblent->next) {
        if (tblent->oldval == sv)
@@ -9991,19 +10445,24 @@ S_ptr_table_find(PTR_TBL_t *tbl, const void *sv) {
 }
 
 void *
-Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *tbl, const void *sv)
+Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *const tbl, const void *const sv)
 {
     PTR_TBL_ENT_t const *const tblent = ptr_table_find(tbl, sv);
+
+    PERL_ARGS_ASSERT_PTR_TABLE_FETCH;
     PERL_UNUSED_CONTEXT;
+
     return tblent ? tblent->newval : NULL;
 }
 
 /* add a new entry to a pointer-mapping table */
 
 void
-Perl_ptr_table_store(pTHX_ PTR_TBL_t *tbl, const void *oldsv, void *newsv)
+Perl_ptr_table_store(pTHX_ PTR_TBL_t *const tbl, const void *const oldsv, void *const newsv)
 {
     PTR_TBL_ENT_t *tblent = ptr_table_find(tbl, oldsv);
+
+    PERL_ARGS_ASSERT_PTR_TABLE_STORE;
     PERL_UNUSED_CONTEXT;
 
     if (tblent) {
@@ -10026,12 +10485,14 @@ Perl_ptr_table_store(pTHX_ PTR_TBL_t *tbl, const void *oldsv, void *newsv)
 /* double the hash bucket size of an existing ptr table */
 
 void
-Perl_ptr_table_split(pTHX_ PTR_TBL_t *tbl)
+Perl_ptr_table_split(pTHX_ PTR_TBL_t *const tbl)
 {
     PTR_TBL_ENT_t **ary = tbl->tbl_ary;
     const UV oldsize = tbl->tbl_max + 1;
     UV newsize = oldsize * 2;
     UV i;
+
+    PERL_ARGS_ASSERT_PTR_TABLE_SPLIT;
     PERL_UNUSED_CONTEXT;
 
     Renew(ary, newsize, PTR_TBL_ENT_t*);
@@ -10059,7 +10520,7 @@ Perl_ptr_table_split(pTHX_ PTR_TBL_t *tbl)
 /* remove all the entries from a ptr table */
 
 void
-Perl_ptr_table_clear(pTHX_ PTR_TBL_t *tbl)
+Perl_ptr_table_clear(pTHX_ PTR_TBL_t *const tbl)
 {
     if (tbl && tbl->tbl_items) {
        register PTR_TBL_ENT_t * const * const array = tbl->tbl_ary;
@@ -10082,7 +10543,7 @@ Perl_ptr_table_clear(pTHX_ PTR_TBL_t *tbl)
 /* clear and free a ptr table */
 
 void
-Perl_ptr_table_free(pTHX_ PTR_TBL_t *tbl)
+Perl_ptr_table_free(pTHX_ PTR_TBL_t *const tbl)
 {
     if (!tbl) {
         return;
@@ -10095,12 +10556,14 @@ Perl_ptr_table_free(pTHX_ PTR_TBL_t *tbl)
 #if defined(USE_ITHREADS)
 
 void
-Perl_rvpv_dup(pTHX_ SV *dstr, const SV *sstr, CLONE_PARAMS* param)
+Perl_rvpv_dup(pTHX_ SV *const dstr, const SV *const sstr, CLONE_PARAMS *const param)
 {
+    PERL_ARGS_ASSERT_RVPV_DUP;
+
     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)) {
@@ -10128,7 +10591,7 @@ Perl_rvpv_dup(pTHX_ SV *dstr, const SV *sstr, CLONE_PARAMS* param)
            }
            else {
                /* Some other special case - random pointer */
-               SvPV_set(dstr, SvPVX(sstr));            
+               SvPV_set(dstr, (char *) SvPVX_const(sstr));             
            }
        }
     }
@@ -10141,11 +10604,13 @@ Perl_rvpv_dup(pTHX_ SV *dstr, const SV *sstr, CLONE_PARAMS* param)
 /* duplicate an SV of any type (including AV, HV etc) */
 
 SV *
-Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
+Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
 {
     dVAR;
     SV *dstr;
 
+    PERL_ARGS_ASSERT_SV_DUP;
+
     if (!sstr)
        return NULL;
     if (SvTYPE(sstr) == SVTYPEMASK) {
@@ -10155,7 +10620,7 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* 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;
 
@@ -10166,7 +10631,7 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* 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));
         }
     }
 
@@ -10231,7 +10696,7 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                break;
 
            case SVt_PVGV:
-               if (GvUNIQUE((GV*)sstr)) {
+               if (GvUNIQUE((const GV *)sstr)) {
                    NOOP;   /* Do sharing here, and fall through */
                }
            case SVt_PVIO:
@@ -10304,7 +10769,7 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* 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:
@@ -10352,16 +10817,16 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                IoBOTTOM_NAME(dstr)     = SAVEPV(IoBOTTOM_NAME(dstr));
                break;
            case SVt_PVAV:
-               if (AvARRAY((AV*)sstr)) {
+               if (AvARRAY((const AV *)sstr)) {
                    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)) {
+                   AvARRAY(MUTABLE_AV(dstr)) = dst_ary;
+                   AvALLOC((const AV *)dstr) = dst_ary;
+                   if (AvREAL((const AV *)sstr)) {
                        while (items-- > 0)
                            *dst_ary++ = sv_dup_inc(*src_ary++, param);
                    }
@@ -10369,18 +10834,18 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                        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;
                }
                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);
@@ -10411,10 +10876,11 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                        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
@@ -10427,7 +10893,7 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                    }
                }
                else
-                   HvARRAY((HV*)dstr) = NULL;
+                   HvARRAY(MUTABLE_HV(dstr)) = NULL;
                break;
            case SVt_PVCV:
                if (!(param->flags & CLONEf_COPY_STACKS)) {
@@ -10443,7 +10909,7 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                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);
+                       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 */
@@ -10474,6 +10940,8 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max, CLONE_PARAMS* param)
 {
     PERL_CONTEXT *ncxs;
 
+    PERL_ARGS_ASSERT_CX_DUP;
+
     if (!cxs)
        return (PERL_CONTEXT*)NULL;
 
@@ -10483,69 +10951,64 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max, CLONE_PARAMS* param)
        return ncxs;
 
     /* create anew and remember what it is */
-    Newxz(ncxs, max + 1, PERL_CONTEXT);
+    Newx(ncxs, max + 1, PERL_CONTEXT);
     ptr_table_store(PL_ptr_table, cxs, ncxs);
+    Copy(cxs, ncxs, max + 1, PERL_CONTEXT);
 
     while (ix >= 0) {
-       PERL_CONTEXT * const cx = &cxs[ix];
        PERL_CONTEXT * const ncx = &ncxs[ix];
-       ncx->cx_type    = cx->cx_type;
-       if (CxTYPE(cx) == CXt_SUBST) {
+       if (CxTYPE(ncx) == CXt_SUBST) {
            Perl_croak(aTHX_ "Cloning substitution context is unimplemented");
        }
        else {
-           ncx->blk_oldsp      = cx->blk_oldsp;
-           ncx->blk_oldcop     = cx->blk_oldcop;
-           ncx->blk_oldmarksp  = cx->blk_oldmarksp;
-           ncx->blk_oldscopesp = cx->blk_oldscopesp;
-           ncx->blk_oldpm      = cx->blk_oldpm;
-           ncx->blk_gimme      = cx->blk_gimme;
-           switch (CxTYPE(cx)) {
+           switch (CxTYPE(ncx)) {
            case CXt_SUB:
-               ncx->blk_sub.cv         = (cx->blk_sub.olddepth == 0
-                                          ? cv_dup_inc(cx->blk_sub.cv, param)
-                                          : cv_dup(cx->blk_sub.cv,param));
-               ncx->blk_sub.argarray   = (cx->blk_sub.hasargs
-                                          ? av_dup_inc(cx->blk_sub.argarray, param)
+               ncx->blk_sub.cv         = (ncx->blk_sub.olddepth == 0
+                                          ? cv_dup_inc(ncx->blk_sub.cv, param)
+                                          : cv_dup(ncx->blk_sub.cv,param));
+               ncx->blk_sub.argarray   = (CxHASARGS(ncx)
+                                          ? av_dup_inc(ncx->blk_sub.argarray,
+                                                       param)
                                           : NULL);
-               ncx->blk_sub.savearray  = av_dup_inc(cx->blk_sub.savearray, param);
-               ncx->blk_sub.olddepth   = cx->blk_sub.olddepth;
-               ncx->blk_sub.hasargs    = cx->blk_sub.hasargs;
-               ncx->blk_sub.lval       = cx->blk_sub.lval;
-               ncx->blk_sub.retop      = cx->blk_sub.retop;
+               ncx->blk_sub.savearray  = av_dup_inc(ncx->blk_sub.savearray,
+                                                    param);
                ncx->blk_sub.oldcomppad = (PAD*)ptr_table_fetch(PL_ptr_table,
-                                          cx->blk_sub.oldcomppad);
+                                          ncx->blk_sub.oldcomppad);
                break;
            case CXt_EVAL:
-               ncx->blk_eval.old_in_eval = cx->blk_eval.old_in_eval;
-               ncx->blk_eval.old_op_type = cx->blk_eval.old_op_type;
-               ncx->blk_eval.old_namesv = sv_dup_inc(cx->blk_eval.old_namesv, param);
-               ncx->blk_eval.old_eval_root = cx->blk_eval.old_eval_root;
-               ncx->blk_eval.cur_text  = sv_dup(cx->blk_eval.cur_text, param);
-               ncx->blk_eval.retop = cx->blk_eval.retop;
+               ncx->blk_eval.old_namesv = sv_dup_inc(ncx->blk_eval.old_namesv,
+                                                     param);
+               ncx->blk_eval.cur_text  = sv_dup(ncx->blk_eval.cur_text, param);
                break;
-           case CXt_LOOP:
-               ncx->blk_loop.label     = cx->blk_loop.label;
-               ncx->blk_loop.resetsp   = cx->blk_loop.resetsp;
-               ncx->blk_loop.my_op     = cx->blk_loop.my_op;
-               ncx->blk_loop.iterdata  = (CxPADLOOP(cx)
-                                          ? cx->blk_loop.iterdata
-                                          : gv_dup((GV*)cx->blk_loop.iterdata, param));
-               ncx->blk_loop.oldcomppad
-                   = (PAD*)ptr_table_fetch(PL_ptr_table,
-                                           cx->blk_loop.oldcomppad);
-               ncx->blk_loop.itersave  = sv_dup_inc(cx->blk_loop.itersave, param);
-               ncx->blk_loop.iterlval  = sv_dup_inc(cx->blk_loop.iterlval, param);
-               ncx->blk_loop.iterary   = av_dup_inc(cx->blk_loop.iterary, param);
-               ncx->blk_loop.iterix    = cx->blk_loop.iterix;
-               ncx->blk_loop.itermax   = cx->blk_loop.itermax;
+           case CXt_LOOP_LAZYSV:
+               ncx->blk_loop.state_u.lazysv.end
+                   = sv_dup_inc(ncx->blk_loop.state_u.lazysv.end, param);
+               /* We are taking advantage of av_dup_inc and sv_dup_inc
+                  actually being the same function, and order equivalance of
+                  the two unions.
+                  We can assert the later [but only at run time :-(]  */
+               assert ((void *) &ncx->blk_loop.state_u.ary.ary ==
+                       (void *) &ncx->blk_loop.state_u.lazysv.cur);
+           case CXt_LOOP_FOR:
+               ncx->blk_loop.state_u.ary.ary
+                   = av_dup_inc(ncx->blk_loop.state_u.ary.ary, param);
+           case CXt_LOOP_LAZYIV:
+           case CXt_LOOP_PLAIN:
+               if (CxPADLOOP(ncx)) {
+                   ncx->blk_loop.oldcomppad
+                       = (PAD*)ptr_table_fetch(PL_ptr_table,
+                                               ncx->blk_loop.oldcomppad);
+               } else {
+                   ncx->blk_loop.oldcomppad
+                       = (PAD*)gv_dup((const GV *)ncx->blk_loop.oldcomppad,
+                                      param);
+               }
                break;
            case CXt_FORMAT:
-               ncx->blk_sub.cv         = cv_dup(cx->blk_sub.cv, param);
-               ncx->blk_sub.gv         = gv_dup(cx->blk_sub.gv, param);
-               ncx->blk_sub.dfoutgv    = gv_dup_inc(cx->blk_sub.dfoutgv, param);
-               ncx->blk_sub.hasargs    = cx->blk_sub.hasargs;
-               ncx->blk_sub.retop      = cx->blk_sub.retop;
+               ncx->blk_format.cv      = cv_dup(ncx->blk_format.cv, param);
+               ncx->blk_format.gv      = gv_dup(ncx->blk_format.gv, param);
+               ncx->blk_format.dfoutgv = gv_dup_inc(ncx->blk_format.dfoutgv,
+                                                    param);
                break;
            case CXt_BLOCK:
            case CXt_NULL:
@@ -10564,6 +11027,8 @@ Perl_si_dup(pTHX_ PERL_SI *si, CLONE_PARAMS* param)
 {
     PERL_SI *nsi;
 
+    PERL_ARGS_ASSERT_SI_DUP;
+
     if (!si)
        return (PERL_SI*)NULL;
 
@@ -10617,6 +11082,8 @@ Perl_any_dup(pTHX_ void *v, const PerlInterpreter *proto_perl)
 {
     void *ret;
 
+    PERL_ARGS_ASSERT_ANY_DUP;
+
     if (!v)
        return (void*)NULL;
 
@@ -10645,10 +11112,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;
@@ -10659,6 +11126,8 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
     void (*dptr) (void*);
     void (*dxptr) (pTHX_ void*);
 
+    PERL_ARGS_ASSERT_SS_DUP;
+
     Newxz(nss, max, ANY);
 
     while (ix > 0) {
@@ -10666,17 +11135,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 */
@@ -10687,19 +11156,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 */
@@ -10736,7 +11205,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 */
@@ -10756,7 +11225,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:
@@ -10790,7 +11259,7 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            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);
            c = (char*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = pv_dup_inc(c);
@@ -10822,11 +11291,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:
@@ -10834,8 +11303,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;
@@ -10843,18 +11310,20 @@ 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;
-       case SAVEt_PADSV:
+       case SAVEt_PADSV_AND_MORTALIZE:
            longval = (long)POPLONG(ss,ix);
            TOPLONG(nss,ix) = longval;
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           sv = (SV*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup(sv, param);
+           sv = (const SV *)POPPTR(ss,ix);
+           TOPPTR(nss,ix) = sv_dup_inc(sv, param);
            break;
        case SAVEt_BOOL:
            ptr = POPPTR(ss,ix);
@@ -10867,7 +11336,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:
@@ -10954,11 +11423,11 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
  * so we know which stashes want their objects cloned */
 
 static void
-do_mark_cloneable_stash(pTHX_ SV *sv)
+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;
@@ -10969,7 +11438,7 @@ do_mark_cloneable_stash(pTHX_ SV *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;
@@ -11030,6 +11499,8 @@ perl_clone(PerlInterpreter *proto_perl, UV flags)
    dVAR;
 #ifdef PERL_IMPLICIT_SYS
 
+    PERL_ARGS_ASSERT_PERL_CLONE;
+
    /* perlhost.h so we need to call into it
    to clone the host, CPerlHost should have a c interface, sky */
 
@@ -11065,6 +11536,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     CLONE_PARAMS* const param = &clone_params;
 
     PerlInterpreter * const my_perl = (PerlInterpreter*)(*ipM->pMalloc)(ipM, sizeof(PerlInterpreter));
+
+    PERL_ARGS_ASSERT_PERL_CLONE_USING;
+
     /* for each stash, determine whether its objects should be cloned */
     S_visit(proto_perl, do_mark_cloneable_stash, SVt_PVHV, SVTYPEMASK);
     PERL_SET_THX(my_perl);
@@ -11100,6 +11574,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     CLONE_PARAMS clone_params;
     CLONE_PARAMS* param = &clone_params;
     PerlInterpreter * const my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));
+
+    PERL_ARGS_ASSERT_PERL_CLONE;
+
     /* for each stash, determine whether its objects should be cloned */
     S_visit(proto_perl, do_mark_cloneable_stash, SVt_PVHV, SVTYPEMASK);
     PERL_SET_THX(my_perl);
@@ -11265,9 +11742,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 */
@@ -11284,6 +11761,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);
@@ -11600,8 +12078,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);
@@ -11630,7 +12108,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);
@@ -11694,7 +12171,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;
@@ -11703,7 +12180,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;
        }
@@ -11744,6 +12221,9 @@ char *
 Perl_sv_recode_to_utf8(pTHX_ SV *sv, SV *encoding)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_SV_RECODE_TO_UTF8;
+
     if (SvPOK(sv) && !SvUTF8(sv) && !IN_BYTES && SvROK(encoding)) {
        SV *uni;
        STRLEN len;
@@ -11806,6 +12286,9 @@ Perl_sv_cat_decode(pTHX_ SV *dsv, SV *encoding,
 {
     dVAR;
     bool ret = FALSE;
+
+    PERL_ARGS_ASSERT_SV_CAT_DECODE;
+
     if (SvPOK(ssv) && SvPOK(dsv) && SvROK(encoding) && offset) {
        SV *offsv;
        dSP;
@@ -11849,12 +12332,14 @@ 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;
     I32 i;
 
+    PERL_ARGS_ASSERT_FIND_HASH_SUBSCRIPT;
+
     if (!hv || SvMAGICAL(hv) || !HvARRAY(hv) ||
                        (HvTOTALKEYS(hv) > FUV_MAX_SEARCH_SIZE))
        return NULL;
@@ -11883,9 +12368,12 @@ 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;
+
+    PERL_ARGS_ASSERT_FIND_ARRAY_SUBSCRIPT;
+
     if (!av || SvMAGICAL(av) || !AvARRAY(av) ||
                        (AvFILLp(av) > FUV_MAX_SEARCH_SIZE))
        return -1;
@@ -11913,8 +12401,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();
@@ -11943,7 +12431,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));
     }
@@ -11959,8 +12447,10 @@ S_varname(pTHX_ GV *gv, const char gvtype, PADOFFSET targ,
        *SvPVX(name) = '$';
        Perl_sv_catpvf(aTHX_ name, "[%"IVdf"]", (IV)aindex);
     }
-    else if (subscript_type == FUV_SUBSCRIPT_WITHIN)
-       Perl_sv_insert(aTHX_ name, 0, 0,  STR_WITH_LEN("within "));
+    else if (subscript_type == FUV_SUBSCRIPT_WITHIN) {
+       /* We know that name has no magic, so can use 0 instead of SV_GMAGIC */
+       Perl_sv_insert_flags(aTHX_ name, 0, 0,  STR_WITH_LEN("within "), 0);
+    }
 
     return name;
 }
@@ -11987,13 +12477,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)))
@@ -12022,7 +12512,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,
@@ -12031,12 +12521,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;
        }
@@ -12064,7 +12554,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);
@@ -12080,7 +12570,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);
@@ -12120,7 +12610,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;
@@ -12131,12 +12622,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;
                }
@@ -12152,13 +12643,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);
@@ -12209,7 +12701,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;
            }
        }
@@ -12218,6 +12710,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)
@@ -12225,9 +12718,83 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
        goto do_op2;
 
 
+    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:
@@ -12239,6 +12806,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))
@@ -12303,7 +12871,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) {