This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
new perldelta
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index 485755b..cfbf997 100644 (file)
--- a/sv.c
+++ b/sv.c
  */
 #   define ASSERT_UTF8_CACHE(cache) \
     STMT_START { if (cache) { assert((cache)[0] <= (cache)[1]); \
-                             assert((cache)[2] <= (cache)[3]); \
-                             assert((cache)[3] <= (cache)[1]);} \
-                             } STMT_END
+                              assert((cache)[2] <= (cache)[3]); \
+                              assert((cache)[3] <= (cache)[1]);} \
+                              } STMT_END
 #else
 #   define ASSERT_UTF8_CACHE(cache) NOOP
 #endif
@@ -130,8 +130,6 @@ static const char S_destroy[] = "DESTROY";
 
 /* ============================================================================
 
-=head1 Allocation and deallocation of SVs.
-
 An SV (or AV, HV, etc.) is allocated in two parts: the head (struct
 sv, av, hv...) contains type and reference count information, and for
 many types, a pointer to the body (struct xrv, xpv, xpviv...), which
@@ -181,34 +179,34 @@ At the time of very final cleanup, sv_free_arenas() is called from
 perl_destruct() to physically free all the arenas allocated since the
 start of the interpreter.
 
-The function visit() scans the SV arenas list, and calls a specified
-function for each SV it finds which is still live - ie which has an SvTYPE
+The internal function visit() scans the SV arenas list, and calls a specified
+function for each SV it finds which is still live, I<i.e.> which has an SvTYPE
 other than all 1's, and a non-zero SvREFCNT. visit() is used by the
 following functions (specified as [function that calls visit()] / [function
 called by visit() for each SV]):
 
     sv_report_used() / do_report_used()
-                       dump all remaining SVs (debugging aid)
+                        dump all remaining SVs (debugging aid)
 
     sv_clean_objs() / do_clean_objs(),do_clean_named_objs(),
-                     do_clean_named_io_objs(),do_curse()
-                       Attempt to free all objects pointed to by RVs,
-                       try to do the same for all objects indir-
-                       ectly referenced by typeglobs too, and
-                       then do a final sweep, cursing any
-                       objects that remain.  Called once from
-                       perl_destruct(), prior to calling sv_clean_all()
-                       below.
+                      do_clean_named_io_objs(),do_curse()
+                        Attempt to free all objects pointed to by RVs,
+                        try to do the same for all objects indir-
+                        ectly referenced by typeglobs too, and
+                        then do a final sweep, cursing any
+                        objects that remain.  Called once from
+                        perl_destruct(), prior to calling sv_clean_all()
+                        below.
 
     sv_clean_all() / do_clean_all()
-                       SvREFCNT_dec(sv) each remaining SV, possibly
-                       triggering an sv_free(). It also sets the
-                       SVf_BREAK flag on the SV to indicate that the
-                       refcnt has been artificially lowered, and thus
-                       stopping sv_free() from giving spurious warnings
-                       about SVs which unexpectedly have a refcnt
-                       of zero.  called repeatedly from perl_destruct()
-                       until there are no SVs left.
+                        SvREFCNT_dec(sv) each remaining SV, possibly
+                        triggering an sv_free(). It also sets the
+                        SVf_BREAK flag on the SV to indicate that the
+                        refcnt has been artificially lowered, and thus
+                        stopping sv_free() from giving spurious warnings
+                        about SVs which unexpectedly have a refcnt
+                        of zero.  called repeatedly from perl_destruct()
+                        until there are no SVs left.
 
 =head2 Arena allocator API Summary
 
@@ -216,7 +214,7 @@ Private API to rest of sv.c
 
     new_SV(),  del_SV(),
 
-    new_XPVNV(), del_XPVGV(),
+    new_XPVNV(), del_body()
     etc
 
 Public API:
@@ -231,43 +229,21 @@ Public API:
  * "A time to plant, and a time to uproot what was planted..."
  */
 
-#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) STMT_START { \
-       if ((sv)->sv_debug_file) PerlMemShared_free((sv)->sv_debug_file); \
+        if ((sv)->sv_debug_file) {                   \
+            PerlMemShared_free((sv)->sv_debug_file); \
+            sv->sv_debug_file = NULL;                \
+        }                                            \
     } STMT_END
 #  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))
+            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 POISON_SV_HEAD(sv)   PoisonNew(sv, 1, struct STRUCT_SV)
-*/
-#  define POISON_SV_HEAD(sv)   PoisonNew(&SvANY(sv), 1, void *), \
-                               PoisonNew(&SvREFCNT(sv), 1, U32)
-#else
-#  define SvARENA_CHAIN(sv)    SvANY(sv)
-#  define SvARENA_CHAIN_SET(sv,val)    SvANY(sv) = (void *)(val)
-#  define POISON_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
@@ -277,31 +253,24 @@ Public API:
 
 #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);                          \
-       POISON_SV_HEAD(p);                              \
-       SvFLAGS(p) = SVTYPEMASK;                        \
-       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 = MUTABLE_SV(SvARENA_CHAIN(p));              \
-       ++PL_sv_count;                                  \
+        const U32 old_flags = SvFLAGS(p);                      \
+        MEM_LOG_DEL_SV(p, __FILE__, __LINE__, FUNCTION__);  \
+        DEBUG_SV_SERIAL(p);                            \
+        FREE_SV_DEBUG_FILE(p);                         \
+        POISON_SV_HEAD(p);                             \
+        SvFLAGS(p) = SVTYPEMASK;                       \
+        if (!(old_flags & SVf_BREAK)) {                \
+            SvARENA_CHAIN_SET(p, PL_sv_root);  \
+            PL_sv_root = (p);                          \
+        }                                              \
+        --PL_sv_count;                                 \
     } STMT_END
 
 
 /* make some more SVs by adding another arena */
 
-STATIC SV*
-S_more_sv(pTHX)
+SV*
+Perl_more_sv(pTHX)
 {
     SV* sv;
     char *chunk;                /* must use New here to match call to */
@@ -311,68 +280,16 @@ S_more_sv(pTHX)
     return sv;
 }
 
-/* new_SV(): return a new, empty SV head */
-
-#ifdef DEBUG_LEAKING_SCALARS
-/* provide a real function for a debugger to play with */
-STATIC SV*
-S_new_SV(pTHX_ const char *file, int line, const char *func)
-{
-    SV* sv;
-
-    if (PL_sv_root)
-       uproot_SV(sv);
-    else
-       sv = S_more_sv(aTHX);
-    SvANY(sv) = 0;
-    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_parser->copline
-               :  PL_curcop
-                   ? CopLINE(PL_curcop)
-                   : 0
-           );
-    sv->sv_debug_inpad = 0;
-    sv->sv_debug_parent = NULL;
-    sv->sv_debug_file = PL_curcop ? savesharedpv(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_ __FILE__, __LINE__, FUNCTION__)
-
-#else
-#  define new_SV(p) \
-    STMT_START {                                       \
-       if (PL_sv_root)                                 \
-           uproot_SV(p);                               \
-       else                                            \
-           (p) = S_more_sv(aTHX);                      \
-       SvANY(p) = 0;                                   \
-       SvREFCNT(p) = 1;                                \
-       SvFLAGS(p) = 0;                                 \
-       MEM_LOG_NEW_SV(p, __FILE__, __LINE__, FUNCTION__);  \
-    } STMT_END
-#endif
-
-
 /* del_SV(): return an empty SV head to the free list */
 
 #ifdef DEBUGGING
 
 #define del_SV(p) \
     STMT_START {                                       \
-       if (DEBUG_D_TEST)                               \
-           del_sv(p);                                  \
-       else                                            \
-           plant_SV(p);                                \
+        if (DEBUG_D_TEST)                              \
+            del_sv(p);                                 \
+        else                                           \
+            plant_SV(p);                               \
     } STMT_END
 
 STATIC void
@@ -381,22 +298,22 @@ S_del_sv(pTHX_ SV *p)
     PERL_ARGS_ASSERT_DEL_SV;
 
     if (DEBUG_D_TEST) {
-       SV* sva;
-       bool ok = 0;
-       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) {
-               ok = 1;
-               break;
-           }
-       }
-       if (!ok) {
-           Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),
-                            "Attempt to free non-arena SV: 0x%" UVxf
-                            pTHX__FORMAT, PTR2UV(p) pTHX__VALUE);
-           return;
-       }
+        SV* sva;
+        bool ok = 0;
+        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) {
+                ok = 1;
+                break;
+            }
+        }
+        if (!ok) {
+            Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),
+                             "Attempt to free non-arena SV: 0x%" UVxf
+                             pTHX__FORMAT, PTR2UV(p) pTHX__VALUE);
+            return;
+        }
     }
     plant_SV(p);
 }
@@ -409,7 +326,7 @@ S_del_sv(pTHX_ SV *p)
 
 
 /*
-=head1 SV Manipulation Functions
+=for apidoc_section $SV
 
 =for apidoc sv_add_arena
 
@@ -439,14 +356,14 @@ S_sv_add_arena(pTHX_ char *const ptr, const U32 size, const U32 flags)
     svend = &sva[SvREFCNT(sva) - 1];
     sv = sva + 1;
     while (sv < svend) {
-       SvARENA_CHAIN_SET(sv, (sv + 1));
+        SvARENA_CHAIN_SET(sv, (sv + 1));
 #ifdef DEBUGGING
-       SvREFCNT(sv) = 0;
+        SvREFCNT(sv) = 0;
 #endif
-       /* Must always set typemask because it's always checked in on cleanup
-          when the arenas are walked looking for objects.  */
-       SvFLAGS(sv) = SVTYPEMASK;
-       sv++;
+        /* Must always set typemask because it's always checked in on cleanup
+           when the arenas are walked looking for objects.  */
+        SvFLAGS(sv) = SVTYPEMASK;
+        sv++;
     }
     SvARENA_CHAIN_SET(sv, 0);
 #ifdef DEBUGGING
@@ -458,7 +375,7 @@ S_sv_add_arena(pTHX_ char *const ptr, const U32 size, const U32 flags)
 /* visit(): call the named function for each non-free SV in the arenas
  * whose flags field matches the flags/mask args. */
 
-STATIC I32
+STATIC SSize_t
 S_visit(pTHX_ SVFUNC_t f, const U32 flags, const U32 mask)
 {
     SV* sva;
@@ -467,17 +384,17 @@ S_visit(pTHX_ SVFUNC_t f, const U32 flags, const U32 mask)
     PERL_ARGS_ASSERT_VISIT;
 
     for (sva = PL_sv_arenaroot; sva; sva = MUTABLE_SV(SvANY(sva))) {
-       const SV * const svend = &sva[SvREFCNT(sva)];
-       SV* sv;
-       for (sv = sva + 1; sv < svend; ++sv) {
-           if (SvTYPE(sv) != (svtype)SVTYPEMASK
-                   && (sv->sv_flags & mask) == flags
-                   && SvREFCNT(sv))
-           {
-               (*f)(aTHX_ sv);
-               ++visited;
-           }
-       }
+        const SV * const svend = &sva[SvREFCNT(sva)];
+        SV* sv;
+        for (sv = sva + 1; sv < svend; ++sv) {
+            if (!SvIS_FREED(sv)
+                    && (sv->sv_flags & mask) == flags
+                    && SvREFCNT(sv))
+            {
+                (*f)(aTHX_ sv);
+                ++visited;
+            }
+        }
     }
     return visited;
 }
@@ -489,9 +406,9 @@ S_visit(pTHX_ SVFUNC_t f, const U32 flags, const U32 mask)
 static void
 do_report_used(pTHX_ SV *const sv)
 {
-    if (SvTYPE(sv) != (svtype)SVTYPEMASK) {
-       PerlIO_printf(Perl_debug_log, "****\n");
-       sv_dump(sv);
+    if (!SvIS_FREED(sv)) {
+        PerlIO_printf(Perl_debug_log, "****\n");
+        sv_dump(sv);
     }
 }
 #endif
@@ -521,19 +438,19 @@ do_clean_objs(pTHX_ SV *const ref)
 {
     assert (SvROK(ref));
     {
-       SV * const target = SvRV(ref);
-       if (SvOBJECT(target)) {
-           DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning object ref:\n "), sv_dump(ref)));
-           if (SvWEAKREF(ref)) {
-               sv_del_backref(target, ref);
-               SvWEAKREF_off(ref);
-               SvRV_set(ref, NULL);
-           } else {
-               SvROK_off(ref);
-               SvRV_set(ref, NULL);
-               SvREFCNT_dec_NN(target);
-           }
-       }
+        SV * const target = SvRV(ref);
+        if (SvOBJECT(target)) {
+            DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning object ref:\n "), sv_dump(ref)));
+            if (SvWEAKREF(ref)) {
+                sv_del_backref(target, ref);
+                SvWEAKREF_off(ref);
+                SvRV_set(ref, NULL);
+            } else {
+                SvROK_off(ref);
+                SvRV_set(ref, NULL);
+                SvREFCNT_dec_NN(target);
+            }
+        }
     }
 }
 
@@ -548,35 +465,35 @@ do_clean_named_objs(pTHX_ SV *const sv)
     assert(SvTYPE(sv) == SVt_PVGV);
     assert(isGV_with_GP(sv));
     if (!GvGP(sv))
-       return;
+        return;
 
     /* freeing GP entries may indirectly free the current GV;
      * hold onto it while we mess with the GP slots */
     SvREFCNT_inc(sv);
 
     if ( ((obj = GvSV(sv) )) && SvOBJECT(obj)) {
-       DEBUG_D((PerlIO_printf(Perl_debug_log,
-               "Cleaning named glob SV object:\n "), sv_dump(obj)));
-       GvSV(sv) = NULL;
-       SvREFCNT_dec_NN(obj);
+        DEBUG_D((PerlIO_printf(Perl_debug_log,
+                "Cleaning named glob SV object:\n "), sv_dump(obj)));
+        GvSV(sv) = NULL;
+        SvREFCNT_dec_NN(obj);
     }
     if ( ((obj = MUTABLE_SV(GvAV(sv)) )) && SvOBJECT(obj)) {
-       DEBUG_D((PerlIO_printf(Perl_debug_log,
-               "Cleaning named glob AV object:\n "), sv_dump(obj)));
-       GvAV(sv) = NULL;
-       SvREFCNT_dec_NN(obj);
+        DEBUG_D((PerlIO_printf(Perl_debug_log,
+                "Cleaning named glob AV object:\n "), sv_dump(obj)));
+        GvAV(sv) = NULL;
+        SvREFCNT_dec_NN(obj);
     }
     if ( ((obj = MUTABLE_SV(GvHV(sv)) )) && SvOBJECT(obj)) {
-       DEBUG_D((PerlIO_printf(Perl_debug_log,
-               "Cleaning named glob HV object:\n "), sv_dump(obj)));
-       GvHV(sv) = NULL;
-       SvREFCNT_dec_NN(obj);
+        DEBUG_D((PerlIO_printf(Perl_debug_log,
+                "Cleaning named glob HV object:\n "), sv_dump(obj)));
+        GvHV(sv) = NULL;
+        SvREFCNT_dec_NN(obj);
     }
     if ( ((obj = MUTABLE_SV(GvCV(sv)) )) && SvOBJECT(obj)) {
-       DEBUG_D((PerlIO_printf(Perl_debug_log,
-               "Cleaning named glob CV object:\n "), sv_dump(obj)));
-       GvCV_set(sv, NULL);
-       SvREFCNT_dec_NN(obj);
+        DEBUG_D((PerlIO_printf(Perl_debug_log,
+                "Cleaning named glob CV object:\n "), sv_dump(obj)));
+        GvCV_set(sv, NULL);
+        SvREFCNT_dec_NN(obj);
     }
     SvREFCNT_dec_NN(sv); /* undo the inc above */
 }
@@ -591,14 +508,14 @@ do_clean_named_io_objs(pTHX_ SV *const sv)
     assert(SvTYPE(sv) == SVt_PVGV);
     assert(isGV_with_GP(sv));
     if (!GvGP(sv) || sv == (SV*)PL_stderrgv || sv == (SV*)PL_defoutgv)
-       return;
+        return;
 
     SvREFCNT_inc(sv);
     if ( ((obj = MUTABLE_SV(GvIO(sv)) )) && SvOBJECT(obj)) {
-       DEBUG_D((PerlIO_printf(Perl_debug_log,
-               "Cleaning named glob IO object:\n "), sv_dump(obj)));
-       GvIOp(sv) = NULL;
-       SvREFCNT_dec_NN(obj);
+        DEBUG_D((PerlIO_printf(Perl_debug_log,
+                "Cleaning named glob IO object:\n "), sv_dump(obj)));
+        GvIOp(sv) = NULL;
+        SvREFCNT_dec_NN(obj);
     }
     SvREFCNT_dec_NN(sv); /* undo the inc above */
 }
@@ -608,7 +525,7 @@ static void
 do_curse(pTHX_ SV * const sv) {
     if ((PL_stderrgv && GvGP(PL_stderrgv) && (SV*)GvIO(PL_stderrgv) == sv)
      || (PL_defoutgv && GvGP(PL_defoutgv) && (SV*)GvIO(PL_defoutgv) == sv))
-       return;
+        return;
     (void)curse(sv, 0);
 }
 
@@ -637,11 +554,11 @@ Perl_sv_clean_objs(pTHX)
     olddef = PL_defoutgv;
     PL_defoutgv = NULL; /* disable skip of PL_defoutgv */
     if (olddef && isGV_with_GP(olddef))
-       do_clean_named_io_objs(aTHX_ MUTABLE_SV(olddef));
+        do_clean_named_io_objs(aTHX_ MUTABLE_SV(olddef));
     olderr = PL_stderrgv;
     PL_stderrgv = NULL; /* disable skip of PL_stderrgv */
     if (olderr && isGV_with_GP(olderr))
-       do_clean_named_io_objs(aTHX_ MUTABLE_SV(olderr));
+        do_clean_named_io_objs(aTHX_ MUTABLE_SV(olderr));
     SvREFCNT_dec(olddef);
     PL_in_clean_objs = FALSE;
 }
@@ -652,8 +569,8 @@ static void
 do_clean_all(pTHX_ SV *const sv)
 {
     if (sv == (const SV *) PL_fdpid || sv == (const SV *)PL_strtab) {
-       /* don't clean pid table and strtab */
-       return;
+        /* 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;
@@ -670,15 +587,67 @@ SVs which are in complex self-referential hierarchies.
 =cut
 */
 
-I32
+SSize_t
 Perl_sv_clean_all(pTHX)
 {
-    I32 cleaned;
+    SSize_t cleaned;
     PL_in_clean_all = TRUE;
     cleaned = visit(do_clean_all, 0,0);
     return cleaned;
 }
 
+
+#ifdef DEBUGGING
+
+/* Called by sv_mark_arenas() for each live SV: set SVf_BREAK */
+
+static void
+S_do_sv_mark_arenas(pTHX_ SV *const sv)
+{
+        sv->sv_flags |= SVf_BREAK;
+}
+
+/* sv_mark_arenas(): for leak debugging: mark all live SVs with SVf_BREAK.
+ * Then later, use sv_sweep_arenas() to list any SVs not so marked.
+ */
+
+void
+Perl_sv_mark_arenas(pTHX)
+{
+    visit(S_do_sv_mark_arenas, 0, 0);
+}
+
+/* Called by sv_sweep_arenas() for each live SV, to list any SVs without
+ * SVf_BREAK set */
+
+static void
+S_do_sv_sweep_arenas(pTHX_ SV *const sv)
+{
+        if (sv->sv_flags & SVf_BREAK) {
+            sv->sv_flags &= ~SVf_BREAK;
+            return;
+        }
+        PerlIO_printf(Perl_debug_log, "Unmarked SV: 0x%p: %s\n",
+                        sv, SvPEEK(sv));
+}
+
+
+/* sv_sweep_arenas(): for debugging: list all live SVs that don't have
+ * SVf_BREAK set, then turn off all SVf_BREAK flags.  Typically used some
+ * time after sv_mark_arenas(), to find SVs which have been created since
+ * the marking but not yet freed (they may have leaked, or been stored in
+ * an array, or whatever).
+ */
+
+void
+Perl_sv_sweep_arenas(pTHX)
+{
+    visit(S_do_sv_sweep_arenas, 0, 0);
+}
+
+#endif
+
+
 /*
   ARENASETS: a meta-arena implementation which separates arena-info
   into struct arena_set, which contains an array of struct
@@ -707,7 +676,7 @@ struct arena_set;
    therefore likely to be 1 aligned memory page.  */
 
 #define ARENAS_PER_SET  ((PERL_ARENA_SIZE - sizeof(struct arena_set*) \
-                         - 2 * sizeof(int)) / sizeof (struct arena_desc))
+                          - 2 * sizeof(int)) / sizeof (struct arena_desc))
 
 struct arena_set {
     struct arena_set* next;
@@ -736,41 +705,45 @@ Perl_sv_free_arenas(pTHX)
        contiguity of the fake ones with the corresponding real ones.) */
 
     for (sva = PL_sv_arenaroot; sva; sva = svanext) {
-       svanext = MUTABLE_SV(SvANY(sva));
-       while (svanext && SvFAKE(svanext))
-           svanext = MUTABLE_SV(SvANY(svanext));
+        svanext = MUTABLE_SV(SvANY(sva));
+        while (svanext && SvFAKE(svanext))
+            svanext = MUTABLE_SV(SvANY(svanext));
 
-       if (!SvFAKE(sva))
-           Safefree(sva);
+        if (!SvFAKE(sva))
+            Safefree(sva);
     }
 
     {
-       struct arena_set *aroot = (struct arena_set*) PL_body_arenas;
-
-       while (aroot) {
-           struct arena_set *current = aroot;
-           i = aroot->curr;
-           while (i--) {
-               assert(aroot->set[i].arena);
-               Safefree(aroot->set[i].arena);
-           }
-           aroot = aroot->next;
-           Safefree(current);
-       }
+        struct arena_set *aroot = (struct arena_set*) PL_body_arenas;
+
+        while (aroot) {
+            struct arena_set *current = aroot;
+            i = aroot->curr;
+            while (i--) {
+                assert(aroot->set[i].arena);
+                Safefree(aroot->set[i].arena);
+            }
+            aroot = aroot->next;
+            Safefree(current);
+        }
     }
     PL_body_arenas = 0;
 
     i = PERL_ARENA_ROOTS_SIZE;
     while (i--)
-       PL_body_roots[i] = 0;
+        PL_body_roots[i] = 0;
 
     PL_sv_arenaroot = 0;
     PL_sv_root = 0;
 }
 
 /*
-  Here are mid-level routines that manage the allocation of bodies out
-  of the various arenas.  There are 4 kinds of arenas:
+  Historically, here were mid-level routines that manage the
+  allocation of bodies out of the various arenas. Some of these
+  routines and related definitions remain here, but others were
+  moved into sv_inline.h to facilitate inlining of newSV_type().
+
+  There are 4 kinds of arenas:
 
   1. SV-head arenas, which are discussed and handled above
   2. regular body arenas
@@ -780,7 +753,7 @@ Perl_sv_free_arenas(pTHX)
   Arena types 2 & 3 are chained by body-type off an array of
   arena-root pointers, which is indexed by svtype.  Some of the
   larger/less used body types are malloced singly, since a large
-  unused block of them is wasteful.  Also, several svtypes dont have
+  unused block of them is wasteful.  Also, several svtypes don't have
   bodies; the data fits into the sv-head itself.  The arena-root
   pointer thus has a few unused root-pointers (which may be hijacked
   later for arena type 4)
@@ -834,7 +807,7 @@ the start of the structure.  IV bodies, and also in some builds NV bodies,
 don't need it either, because they are no longer allocated.
 
 In turn, the new_body_* allocators call S_new_body(), which invokes
-new_body_inline macro, which takes a lock, and takes a body off the
+new_body_from_arena macro, which takes a lock, and takes a body off the
 linked list at PL_body_roots[sv_type], calling Perl_more_bodies() if
 necessary to refresh an empty list.  Then the lock is released, and
 the body is returned.
@@ -866,200 +839,25 @@ are used for this, except for arena_size.
 For the sv-types that have no bodies, arenas are not used, so those
 PL_body_roots[sv_type] are unused, and can be overloaded.  In
 something of a special case, SVt_NULL is borrowed for HE arenas;
-PL_body_roots[HE_SVSLOT=SVt_NULL] is filled by S_more_he, but the
+PL_body_roots[HE_ARENA_ROOT_IX=SVt_NULL] is filled by S_more_he, but the
 bodies_by_type[SVt_NULL] slot is not used, as the table is not
-available in hv.c.
+available in hv.c. Similarly SVt_IV is re-used for HVAUX_ARENA_ROOT_IX.
 
 */
 
-struct body_details {
-    U8 body_size;      /* Size to allocate  */
-    U8 copy;           /* Size of structure to copy (may be shorter)  */
-    U8 offset;         /* Size of unalloced ghost fields to first alloced field*/
-    PERL_BITFIELD8 type : 4;        /* We have space for a sanity check. */
-    PERL_BITFIELD8 cant_upgrade : 1;/* Cannot upgrade this type */
-    PERL_BITFIELD8 zero_nv : 1;     /* zero the NV when upgrading from this */
-    PERL_BITFIELD8 arena : 1;       /* Allocated from an arena */
-    U32 arena_size;                 /* Size of arena to allocate */
-};
-
-#define HADNV FALSE
-#define NONV TRUE
-
-
-#ifdef PURIFY
-/* With -DPURFIY we allocate everything directly, and don't use arenas.
-   This seems a rather elegant way to simplify some of the code below.  */
-#define HASARENA FALSE
-#else
-#define HASARENA TRUE
-#endif
-#define NOARENA FALSE
-
-/* Size the arenas to exactly fit a given number of bodies.  A count
-   of 0 fits the max number bodies into a PERL_ARENA_SIZE.block,
-   simplifying the default.  If count > 0, the arena is sized to fit
-   only that many bodies, allowing arenas to be used for large, rare
-   bodies (XPVFM, XPVIO) without undue waste.  The arena size is
-   limited by PERL_ARENA_SIZE, so we can safely oversize the
-   declarations.
- */
-#define FIT_ARENA0(body_size)                          \
-    ((size_t)(PERL_ARENA_SIZE / body_size) * body_size)
-#define FIT_ARENAn(count,body_size)                    \
-    ( count * body_size <= PERL_ARENA_SIZE)            \
-    ? count * body_size                                        \
-    : FIT_ARENA0 (body_size)
-#define FIT_ARENA(count,body_size)                     \
-   (U32)(count                                                 \
-    ? FIT_ARENAn (count, body_size)                    \
-    : FIT_ARENA0 (body_size))
-
-/* Calculate the length to copy. Specifically work out the length less any
-   final padding the compiler needed to add.  See the comment in sv_upgrade
-   for why copying the padding proved to be a bug.  */
-
-#define copy_length(type, last_member) \
-       STRUCT_OFFSET(type, last_member) \
-       + sizeof (((type*)SvANY((const SV *)0))->last_member)
-
-static const struct body_details bodies_by_type[] = {
-    /* HEs use this offset for their arena.  */
-    { 0, 0, 0, SVt_NULL, FALSE, NONV, NOARENA, 0 },
-
-    /* IVs are in the head, so the allocation size is 0.  */
-    { 0,
-      sizeof(IV), /* This is used to copy out the IV body.  */
-      STRUCT_OFFSET(XPVIV, xiv_iv), SVt_IV, FALSE, NONV,
-      NOARENA /* IVS don't need an arena  */, 0
-    },
-
-#if NVSIZE <= IVSIZE
-    { 0, sizeof(NV),
-      STRUCT_OFFSET(XPVNV, xnv_u),
-      SVt_NV, FALSE, HADNV, NOARENA, 0 },
-#else
-    { sizeof(NV), sizeof(NV),
-      STRUCT_OFFSET(XPVNV, xnv_u),
-      SVt_NV, FALSE, HADNV, HASARENA, FIT_ARENA(0, sizeof(NV)) },
-#endif
-
-    { sizeof(XPV) - STRUCT_OFFSET(XPV, xpv_cur),
-      copy_length(XPV, xpv_len) - STRUCT_OFFSET(XPV, xpv_cur),
-      + STRUCT_OFFSET(XPV, xpv_cur),
-      SVt_PV, FALSE, NONV, HASARENA,
-      FIT_ARENA(0, sizeof(XPV) - STRUCT_OFFSET(XPV, xpv_cur)) },
-
-    { sizeof(XINVLIST) - STRUCT_OFFSET(XPV, xpv_cur),
-      copy_length(XINVLIST, is_offset) - STRUCT_OFFSET(XPV, xpv_cur),
-      + STRUCT_OFFSET(XPV, xpv_cur),
-      SVt_INVLIST, TRUE, NONV, HASARENA,
-      FIT_ARENA(0, sizeof(XINVLIST) - STRUCT_OFFSET(XPV, xpv_cur)) },
-
-    { sizeof(XPVIV) - STRUCT_OFFSET(XPV, xpv_cur),
-      copy_length(XPVIV, xiv_u) - STRUCT_OFFSET(XPV, xpv_cur),
-      + STRUCT_OFFSET(XPV, xpv_cur),
-      SVt_PVIV, FALSE, NONV, HASARENA,
-      FIT_ARENA(0, sizeof(XPVIV) - STRUCT_OFFSET(XPV, xpv_cur)) },
-
-    { sizeof(XPVNV) - STRUCT_OFFSET(XPV, xpv_cur),
-      copy_length(XPVNV, xnv_u) - STRUCT_OFFSET(XPV, xpv_cur),
-      + STRUCT_OFFSET(XPV, xpv_cur),
-      SVt_PVNV, FALSE, HADNV, HASARENA,
-      FIT_ARENA(0, sizeof(XPVNV) - STRUCT_OFFSET(XPV, xpv_cur)) },
-
-    { sizeof(XPVMG), copy_length(XPVMG, xnv_u), 0, SVt_PVMG, FALSE, HADNV,
-      HASARENA, FIT_ARENA(0, sizeof(XPVMG)) },
-
-    { sizeof(regexp),
-      sizeof(regexp),
-      0,
-      SVt_REGEXP, TRUE, NONV, HASARENA,
-      FIT_ARENA(0, sizeof(regexp))
-    },
-
-    { sizeof(XPVGV), sizeof(XPVGV), 0, SVt_PVGV, TRUE, HADNV,
-      HASARENA, FIT_ARENA(0, sizeof(XPVGV)) },
-    
-    { sizeof(XPVLV), sizeof(XPVLV), 0, SVt_PVLV, TRUE, HADNV,
-      HASARENA, FIT_ARENA(0, sizeof(XPVLV)) },
-
-    { sizeof(XPVAV),
-      copy_length(XPVAV, xav_alloc),
-      0,
-      SVt_PVAV, TRUE, NONV, HASARENA,
-      FIT_ARENA(0, sizeof(XPVAV)) },
-
-    { sizeof(XPVHV),
-      copy_length(XPVHV, xhv_max),
-      0,
-      SVt_PVHV, TRUE, NONV, HASARENA,
-      FIT_ARENA(0, sizeof(XPVHV)) },
-
-    { sizeof(XPVCV),
-      sizeof(XPVCV),
-      0,
-      SVt_PVCV, TRUE, NONV, HASARENA,
-      FIT_ARENA(0, sizeof(XPVCV)) },
-
-    { sizeof(XPVFM),
-      sizeof(XPVFM),
-      0,
-      SVt_PVFM, TRUE, NONV, NOARENA,
-      FIT_ARENA(20, sizeof(XPVFM)) },
-
-    { sizeof(XPVIO),
-      sizeof(XPVIO),
-      0,
-      SVt_PVIO, TRUE, NONV, HASARENA,
-      FIT_ARENA(24, sizeof(XPVIO)) },
-};
-
-#define new_body_allocated(sv_type)            \
-    (void *)((char *)S_new_body(aTHX_ sv_type) \
-            - bodies_by_type[sv_type].offset)
-
 /* return a thing to the free list */
 
 #define del_body(thing, root)                          \
     STMT_START {                                       \
-       void ** const thing_copy = (void **)thing;      \
-       *thing_copy = *root;                            \
-       *root = (void*)thing_copy;                      \
+        void ** const thing_copy = (void **)thing;     \
+        *thing_copy = *root;                           \
+        *root = (void*)thing_copy;                     \
     } STMT_END
 
-#ifdef PURIFY
-#if !(NVSIZE <= IVSIZE)
-#  define new_XNV()    safemalloc(sizeof(XPVNV))
-#endif
-#define new_XPVNV()    safemalloc(sizeof(XPVNV))
-#define new_XPVMG()    safemalloc(sizeof(XPVMG))
-
-#define del_XPVGV(p)   safefree(p)
-
-#else /* !PURIFY */
-
-#if !(NVSIZE <= IVSIZE)
-#  define new_XNV()    new_body_allocated(SVt_NV)
-#endif
-#define new_XPVNV()    new_body_allocated(SVt_PVNV)
-#define new_XPVMG()    new_body_allocated(SVt_PVMG)
-
-#define del_XPVGV(p)   del_body(p + bodies_by_type[SVt_PVGV].offset,   \
-                                &PL_body_roots[SVt_PVGV])
-
-#endif /* PURIFY */
-
-/* no arena for you! */
-
-#define new_NOARENA(details) \
-       safemalloc((details)->body_size + (details)->offset)
-#define new_NOARENAZ(details) \
-       safecalloc((details)->body_size + (details)->offset, 1)
 
 void *
 Perl_more_bodies (pTHX_ const svtype sv_type, const size_t body_size,
-                 const size_t arena_size)
+                  const size_t arena_size)
 {
     void ** const root = &PL_body_roots[sv_type];
     struct arena_desc *adesc;
@@ -1068,21 +866,16 @@ Perl_more_bodies (pTHX_ const svtype sv_type, const size_t body_size,
     char *start;
     const char *end;
     const size_t good_arena_size = Perl_malloc_good_size(arena_size);
-#if defined(DEBUGGING) && defined(PERL_GLOBAL_STRUCT)
-    dVAR;
-#endif
-#if defined(DEBUGGING) && !defined(PERL_GLOBAL_STRUCT)
+#if defined(DEBUGGING)
     static bool done_sanity_check;
 
-    /* PERL_GLOBAL_STRUCT cannot coexist with global
-     * variables like done_sanity_check. */
     if (!done_sanity_check) {
-       unsigned int i = SVt_LAST;
+        unsigned int i = SVt_LAST;
 
-       done_sanity_check = TRUE;
+        done_sanity_check = TRUE;
 
-       while (i--)
-           assert (bodies_by_type[i].type == i);
+        while (i--)
+            assert (bodies_by_type[i].type == i);
     }
 #endif
 
@@ -1090,25 +883,25 @@ Perl_more_bodies (pTHX_ const svtype sv_type, const size_t body_size,
 
     /* may need new arena-set to hold new arena */
     if (!aroot || aroot->curr >= aroot->set_size) {
-       struct arena_set *newroot;
-       Newxz(newroot, 1, struct arena_set);
-       newroot->set_size = ARENAS_PER_SET;
-       newroot->next = aroot;
-       aroot = newroot;
-       PL_body_arenas = (void *) newroot;
-       DEBUG_m(PerlIO_printf(Perl_debug_log, "new arenaset %p\n", (void*)aroot));
+        struct arena_set *newroot;
+        Newxz(newroot, 1, struct arena_set);
+        newroot->set_size = ARENAS_PER_SET;
+        newroot->next = aroot;
+        aroot = newroot;
+        PL_body_arenas = (void *) newroot;
+        DEBUG_m(PerlIO_printf(Perl_debug_log, "new arenaset %p\n", (void*)aroot));
     }
 
     /* ok, now have arena-set with at least 1 empty/available arena-desc */
     curr = aroot->curr++;
     adesc = &(aroot->set[curr]);
     assert(!adesc->arena);
-    
+
     Newx(adesc->arena, good_arena_size, char);
     adesc->size = good_arena_size;
     adesc->utype = sv_type;
     DEBUG_m(PerlIO_printf(Perl_debug_log, "arena %d added: %p size %" UVuf "\n",
-                         curr, (void*)adesc->arena, (UV)good_arena_size));
+                          curr, (void*)adesc->arena, (UV)good_arena_size));
 
     start = (char *) adesc->arena;
 
@@ -1119,66 +912,37 @@ Perl_more_bodies (pTHX_ const svtype sv_type, const size_t body_size,
     /* computed count doesn't 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)good_arena_size,
-                         (int)arena_size, sv_type, (int)body_size,
-                         (int)good_arena_size / (int)body_size));
+                          "arena %p end %p arena-size %d (from %d) type %d "
+                          "size %d ct %d\n",
+                          (void*)start, (void*)end, (int)good_arena_size,
+                          (int)arena_size, sv_type, (int)body_size,
+                          (int)good_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)arena_size, sv_type, (int)body_size,
-                         (int)good_arena_size / (int)body_size));
+                          "arena %p end %p arena-size %d type %d size %d ct %d\n",
+                          (void*)start, (void*)end,
+                          (int)arena_size, sv_type, (int)body_size,
+                          (int)good_arena_size / (int)body_size));
 #endif
     *root = (void *)start;
 
     while (1) {
-       /* Where the next body would start:  */
-       char * const next = start + body_size;
+        /* Where the next body would start:  */
+        char * const next = start + body_size;
 
-       if (next >= end) {
-           /* This is the last body:  */
-           assert(next == end);
+        if (next >= end) {
+            /* This is the last body:  */
+            assert(next == end);
 
-           *(void **)start = 0;
-           return *root;
-       }
+            *(void **)start = 0;
+            return *root;
+        }
 
-       *(void**) start = (void *)next;
-       start = next;
+        *(void**) start = (void *)next;
+        start = next;
     }
 }
 
-/* grab a new thing from the free list, allocating more if necessary.
-   The inline version is used for speed in hot routines, and the
-   function using it serves the rest (unless PURIFY).
-*/
-#define new_body_inline(xpv, sv_type) \
-    STMT_START { \
-       void ** const r3wt = &PL_body_roots[sv_type]; \
-       xpv = (PTR_TBL_ENT_t*) (*((void **)(r3wt))      \
-         ? *((void **)(r3wt)) : Perl_more_bodies(aTHX_ sv_type, \
-                                            bodies_by_type[sv_type].body_size,\
-                                            bodies_by_type[sv_type].arena_size)); \
-       *(r3wt) = *(void**)(xpv); \
-    } STMT_END
-
-#ifndef PURIFY
-
-STATIC void *
-S_new_body(pTHX_ const svtype sv_type)
-{
-    void *xpv;
-    new_body_inline(xpv, sv_type);
-    return xpv;
-}
-
-#endif
-
-static const struct body_details fake_rv =
-    { 0, 0, 0, SVt_IV, FALSE, NONV, NOARENA, 0 };
-
 /*
 =for apidoc sv_upgrade
 
@@ -1200,13 +964,13 @@ Perl_sv_upgrade(pTHX_ SV *const sv, svtype new_type)
     const svtype old_type = SvTYPE(sv);
     const struct body_details *new_type_details;
     const struct body_details *old_type_details
-       = bodies_by_type + old_type;
+        = bodies_by_type + old_type;
     SV *referent = NULL;
 
     PERL_ARGS_ASSERT_SV_UPGRADE;
 
     if (old_type == new_type)
-       return;
+        return;
 
     /* This clause was purposefully added ahead of the early return above to
        the shared string hackery for (sort {$a <=> $b} keys %hash), with the
@@ -1218,7 +982,7 @@ Perl_sv_upgrade(pTHX_ SV *const sv, svtype new_type)
        purpose. So it's safe to move the early return earlier.  */
 
     if (new_type > SVt_PVMG && SvIsCOW(sv)) {
-       sv_force_normal_flags(sv, 0);
+        sv_force_normal_flags(sv, 0);
     }
 
     old_body = SvANY(sv);
@@ -1263,49 +1027,49 @@ Perl_sv_upgrade(pTHX_ SV *const sv, svtype new_type)
 
     switch (old_type) {
     case SVt_NULL:
-       break;
+        break;
     case SVt_IV:
-       if (SvROK(sv)) {
-           referent = SvRV(sv);
-           old_type_details = &fake_rv;
-           if (new_type == SVt_NV)
-               new_type = SVt_PVNV;
-       } else {
-           if (new_type < SVt_PVIV) {
-               new_type = (new_type == SVt_NV)
-                   ? SVt_PVNV : SVt_PVIV;
-           }
-       }
-       break;
+        if (SvROK(sv)) {
+            referent = SvRV(sv);
+            old_type_details = &fake_rv;
+            if (new_type == SVt_NV)
+                new_type = SVt_PVNV;
+        } else {
+            if (new_type < SVt_PVIV) {
+                new_type = (new_type == SVt_NV)
+                    ? SVt_PVNV : SVt_PVIV;
+            }
+        }
+        break;
     case SVt_NV:
-       if (new_type < SVt_PVNV) {
-           new_type = SVt_PVNV;
-       }
-       break;
+        if (new_type < SVt_PVNV) {
+            new_type = SVt_PVNV;
+        }
+        break;
     case SVt_PV:
-       assert(new_type > SVt_PV);
-       STATIC_ASSERT_STMT(SVt_IV < SVt_PV);
-       STATIC_ASSERT_STMT(SVt_NV < SVt_PV);
-       break;
+        assert(new_type > SVt_PV);
+        STATIC_ASSERT_STMT(SVt_IV < SVt_PV);
+        STATIC_ASSERT_STMT(SVt_NV < SVt_PV);
+        break;
     case SVt_PVIV:
-       break;
+        break;
     case SVt_PVNV:
-       break;
+        break;
     case SVt_PVMG:
-       /* Because the XPVMG of PL_mess_sv isn't allocated from the arena,
-          there's no way that it can be safely upgraded, because perl.c
-          expects to Safefree(SvANY(PL_mess_sv))  */
-       assert(sv != PL_mess_sv);
-       break;
+        /* Because the XPVMG of PL_mess_sv isn't allocated from the arena,
+           there's no way that it can be safely upgraded, because perl.c
+           expects to Safefree(SvANY(PL_mess_sv))  */
+        assert(sv != PL_mess_sv);
+        break;
     default:
-       if (UNLIKELY(old_type_details->cant_upgrade))
-           Perl_croak(aTHX_ "Can't upgrade %s (%" UVuf ") to %" UVuf,
-                      sv_reftype(sv, 0), (UV) old_type, (UV) new_type);
+        if (UNLIKELY(old_type_details->cant_upgrade))
+            Perl_croak(aTHX_ "Can't upgrade %s (%" UVuf ") to %" UVuf,
+                       sv_reftype(sv, 0), (UV) old_type, (UV) new_type);
     }
 
     if (UNLIKELY(old_type > new_type))
-       Perl_croak(aTHX_ "sv_upgrade from type %d down to type %d",
-               (int)old_type, (int)new_type);
+        Perl_croak(aTHX_ "sv_upgrade from type %d down to type %d",
+                (int)old_type, (int)new_type);
 
     new_type_details = bodies_by_type + new_type;
 
@@ -1317,80 +1081,106 @@ Perl_sv_upgrade(pTHX_ SV *const sv, svtype new_type)
     assert (new_type != SVt_NULL);
     switch (new_type) {
     case SVt_IV:
-       assert(old_type == SVt_NULL);
-       SET_SVANY_FOR_BODYLESS_IV(sv);
-       SvIV_set(sv, 0);
-       return;
+        assert(old_type == SVt_NULL);
+        SET_SVANY_FOR_BODYLESS_IV(sv);
+        SvIV_set(sv, 0);
+        return;
     case SVt_NV:
-       assert(old_type == SVt_NULL);
+        assert(old_type == SVt_NULL);
 #if NVSIZE <= IVSIZE
-       SET_SVANY_FOR_BODYLESS_NV(sv);
+        SET_SVANY_FOR_BODYLESS_NV(sv);
 #else
-       SvANY(sv) = new_XNV();
+        SvANY(sv) = new_XNV();
 #endif
-       SvNV_set(sv, 0);
-       return;
+        SvNV_set(sv, 0);
+        return;
     case SVt_PVHV:
     case SVt_PVAV:
-       assert(new_type_details->body_size);
-
-#ifndef PURIFY 
-       assert(new_type_details->arena);
-       assert(new_type_details->arena_size);
-       /* This points to the start of the allocated area.  */
-       new_body_inline(new_body, new_type);
-       Zero(new_body, new_type_details->body_size, char);
-       new_body = ((char *)new_body) - new_type_details->offset;
+    case SVt_PVOBJ:
+        assert(new_type_details->body_size);
+
+#ifndef PURIFY
+        assert(new_type_details->arena);
+        assert(new_type_details->arena_size);
+        /* This points to the start of the allocated area.  */
+        new_body = S_new_body(aTHX_ new_type);
+        /* xpvav and xpvhv have no offset, so no need to adjust new_body */
+        assert(!(new_type_details->offset));
 #else
-       /* We always allocated the full length item with PURIFY. To do this
-          we fake things so that arena is false for all 16 types..  */
-       new_body = new_NOARENAZ(new_type_details);
+        /* We always allocated the full length item with PURIFY. To do this
+           we fake things so that arena is false for all 16 types..  */
+        new_body = new_NOARENAZ(new_type_details);
 #endif
-       SvANY(sv) = new_body;
-       if (new_type == SVt_PVAV) {
-           AvMAX(sv)   = -1;
-           AvFILLp(sv) = -1;
-           AvREAL_only(sv);
-           if (old_type_details->body_size) {
-               AvALLOC(sv) = 0;
-           } else {
-               /* It will have been zeroed when the new body was allocated.
-                  Lets not write to it, in case it confuses a write-back
-                  cache.  */
-           }
-       } else {
-           assert(!SvOK(sv));
-           SvOK_off(sv);
+        SvANY(sv) = new_body;
+        switch(new_type) {
+        case SVt_PVAV:
+            {
+                XPVAV pvav = {
+                    .xmg_stash = NULL,
+                    .xmg_u = {.xmg_magic = NULL},
+                    .xav_fill = -1, .xav_max = -1, .xav_alloc = 0
+                };
+                *((XPVAV*) SvANY(sv)) = pvav;
+            }
+
+            AvREAL_only(sv);
+            break;
+        case SVt_PVHV:
+            {
+                XPVHV pvhv = {
+                    .xmg_stash = NULL,
+                    .xmg_u = {.xmg_magic = NULL},
+                    .xhv_keys = 0,
+                    /* start with PERL_HASH_DEFAULT_HvMAX+1 buckets: */
+                    .xhv_max = PERL_HASH_DEFAULT_HvMAX
+                };
+                *((XPVHV*) SvANY(sv)) = pvhv;
+            }
+
+            assert(!SvOK(sv));
+            SvOK_off(sv);
 #ifndef NODEFAULT_SHAREKEYS
-           HvSHAREKEYS_on(sv);         /* key-sharing on by default */
+            HvSHAREKEYS_on(sv);         /* key-sharing on by default */
 #endif
-            /* start with PERL_HASH_DEFAULT_HvMAX+1 buckets: */
-           HvMAX(sv) = PERL_HASH_DEFAULT_HvMAX;
-       }
-
-       /* SVt_NULL isn't the only thing upgraded to AV or HV.
-          The target created by newSVrv also is, and it can have magic.
-          However, it never has SvPVX set.
-       */
-       if (old_type == SVt_IV) {
-           assert(!SvROK(sv));
-       } else if (old_type >= SVt_PV) {
-           assert(SvPVX_const(sv) == 0);
-       }
-
-       if (old_type >= SVt_PVMG) {
-           SvMAGIC_set(sv, ((XPVMG*)old_body)->xmg_u.xmg_magic);
-           SvSTASH_set(sv, ((XPVMG*)old_body)->xmg_stash);
-       } else {
-           sv->sv_u.svu_array = NULL; /* or svu_hash  */
-       }
-       break;
+            break;
+        case SVt_PVOBJ:
+            {
+                XPVOBJ pvo = {
+                    .xmg_stash = NULL, .xmg_u = {.xmg_magic = NULL},
+                    .xobject_maxfield = -1,
+                    .xobject_iter_sv_at = 0,
+                    .xobject_fields = NULL,
+                };
+                *((XPVOBJ*) SvANY(sv)) = pvo;
+            }
+            break;
+        default:
+            NOT_REACHED;
+        }
+
+        /* SVt_NULL isn't the only thing upgraded to AV or HV.
+           The target created by newSVrv also is, and it can have magic.
+           However, it never has SvPVX set.
+        */
+        if (old_type == SVt_IV) {
+            assert(!SvROK(sv));
+        } else if (old_type >= SVt_PV) {
+            assert(SvPVX_const(sv) == 0);
+        }
+
+        if (old_type >= SVt_PVMG) {
+            SvMAGIC_set(sv, ((XPVMG*)old_body)->xmg_u.xmg_magic);
+            SvSTASH_set(sv, ((XPVMG*)old_body)->xmg_stash);
+        } else {
+            sv->sv_u.svu_array = NULL; /* or svu_hash  */
+        }
+        break;
 
     case SVt_PVIV:
-       /* XXX Is this still needed?  Was it ever needed?   Surely as there is
-          no route from NV to PVIV, NOK can never be true  */
-       assert(!SvNOKp(sv));
-       assert(!SvNOK(sv));
+        /* XXX Is this still needed?  Was it ever needed?   Surely as there is
+           no route from NV to PVIV, NOK can never be true  */
+        assert(!SvNOKp(sv));
+        assert(!SvNOK(sv));
         /* FALLTHROUGH */
     case SVt_PVIO:
     case SVt_PVFM:
@@ -1403,88 +1193,127 @@ Perl_sv_upgrade(pTHX_ SV *const sv, svtype new_type)
     case SVt_PVNV:
     case SVt_PV:
 
-       assert(new_type_details->body_size);
-       /* We always allocated the full length item with PURIFY. To do this
-          we fake things so that arena is false for all 16 types..  */
-       if(new_type_details->arena) {
-           /* This points to the start of the allocated area.  */
-           new_body_inline(new_body, new_type);
-           Zero(new_body, new_type_details->body_size, char);
-           new_body = ((char *)new_body) - new_type_details->offset;
-       } else {
-           new_body = new_NOARENAZ(new_type_details);
-       }
-       SvANY(sv) = new_body;
-
-       if (old_type_details->copy) {
-           /* There is now the potential for an upgrade from something without
-              an offset (PVNV or PVMG) to something with one (PVCV, PVFM)  */
-           int offset = old_type_details->offset;
-           int length = old_type_details->copy;
-
-           if (new_type_details->offset > old_type_details->offset) {
-               const int difference
-                   = new_type_details->offset - old_type_details->offset;
-               offset += difference;
-               length -= difference;
-           }
-           assert (length >= 0);
-               
-           Copy((char *)old_body + offset, (char *)new_body + offset, length,
-                char);
-       }
+        assert(new_type_details->body_size);
+        /* We always allocated the full length item with PURIFY. To do this
+           we fake things so that arena is false for all 16 types..  */
+#ifndef PURIFY
+        if(new_type_details->arena) {
+            /* This points to the start of the allocated area.  */
+            new_body = S_new_body(aTHX_ new_type);
+            Zero(new_body, new_type_details->body_size, char);
+            new_body = ((char *)new_body) - new_type_details->offset;
+        } else
+#endif
+        {
+            new_body = new_NOARENAZ(new_type_details);
+        }
+        SvANY(sv) = new_body;
+
+        if (old_type_details->copy) {
+            /* There is now the potential for an upgrade from something without
+               an offset (PVNV or PVMG) to something with one (PVCV, PVFM)  */
+            int offset = old_type_details->offset;
+            int length = old_type_details->copy;
+
+            if (new_type_details->offset > old_type_details->offset) {
+                const int difference
+                    = new_type_details->offset - old_type_details->offset;
+                offset += difference;
+                length -= difference;
+            }
+            assert (length >= 0);
+
+            Copy((char *)old_body + offset, (char *)new_body + offset, length,
+                 char);
+        }
 
 #ifndef NV_ZERO_IS_ALLBITS_ZERO
-       /* If NV 0.0 is stores as all bits 0 then Zero() already creates a
-        * correct 0.0 for us.  Otherwise, if the old body didn't have an
-        * NV slot, but the new one does, then we need to initialise the
-        * freshly created NV slot with whatever the correct bit pattern is
-        * for 0.0  */
-       if (old_type_details->zero_nv && !new_type_details->zero_nv
-           && !isGV_with_GP(sv))
-           SvNV_set(sv, 0);
+        /* If NV 0.0 is stores as all bits 0 then Zero() already creates a
+         * correct 0.0 for us.  Otherwise, if the old body didn't have an
+         * NV slot, but the new one does, then we need to initialise the
+         * freshly created NV slot with whatever the correct bit pattern is
+         * for 0.0  */
+        if (old_type_details->zero_nv && !new_type_details->zero_nv
+            && !isGV_with_GP(sv))
+            SvNV_set(sv, 0);
 #endif
 
-       if (UNLIKELY(new_type == SVt_PVIO)) {
-           IO * const io = MUTABLE_IO(sv);
-           GV *iogv = gv_fetchpvs("IO::File::", GV_ADD, SVt_PVHV);
+        if (UNLIKELY(new_type == SVt_PVIO)) {
+            IO * const io = MUTABLE_IO(sv);
+            GV *iogv = gv_fetchpvs("IO::File::", GV_ADD, SVt_PVHV);
 
-           SvOBJECT_on(io);
-           /* Clear the stashcache because a new IO could overrule a package
-              name */
+            SvOBJECT_on(io);
+            /* Clear the stashcache because a new IO could overrule a package
+               name */
             DEBUG_o(Perl_deb(aTHX_ "sv_upgrade clearing PL_stashcache\n"));
-           hv_clear(PL_stashcache);
-
-           SvSTASH_set(io, MUTABLE_HV(SvREFCNT_inc(GvHV(iogv))));
-           IoPAGE_LEN(sv) = 60;
-       }
-       if (old_type < SVt_PV) {
-           /* referent will be NULL unless the old type was SVt_IV emulating
-              SVt_RV */
-           sv->sv_u.svu_rv = referent;
-       }
-       break;
+            hv_clear(PL_stashcache);
+
+            SvSTASH_set(io, MUTABLE_HV(SvREFCNT_inc(GvHV(iogv))));
+            IoPAGE_LEN(sv) = 60;
+        }
+        if (old_type < SVt_PV) {
+            /* referent will be NULL unless the old type was SVt_IV emulating
+               SVt_RV */
+            sv->sv_u.svu_rv = referent;
+        }
+        break;
     default:
-       Perl_croak(aTHX_ "panic: sv_upgrade to unknown type %lu",
-                  (unsigned long)new_type);
+        Perl_croak(aTHX_ "panic: sv_upgrade to unknown type %lu",
+                   (unsigned long)new_type);
     }
 
     /* if this is zero, this is a body-less SVt_NULL, SVt_IV/SVt_RV,
        and sometimes SVt_NV */
     if (old_type_details->body_size) {
 #ifdef PURIFY
-       safefree(old_body);
+        safefree(old_body);
 #else
-       /* Note that there is an assumption that all bodies of types that
-          can be upgraded came from arenas. Only the more complex non-
-          upgradable types are allowed to be directly malloc()ed.  */
-       assert(old_type_details->arena);
-       del_body((void*)((char*)old_body + old_type_details->offset),
-                &PL_body_roots[old_type]);
+        /* Note that there is an assumption that all bodies of types that
+           can be upgraded came from arenas. Only the more complex non-
+           upgradable types are allowed to be directly malloc()ed.  */
+        assert(old_type_details->arena);
+        del_body((void*)((char*)old_body + old_type_details->offset),
+                 &PL_body_roots[old_type]);
 #endif
     }
 }
 
+struct xpvhv_aux*
+Perl_hv_auxalloc(pTHX_ HV *hv) {
+    const struct body_details *old_type_details = bodies_by_type + SVt_PVHV;
+    void *old_body;
+    void *new_body;
+
+    PERL_ARGS_ASSERT_HV_AUXALLOC;
+    assert(SvTYPE(hv) == SVt_PVHV);
+    assert(!HvHasAUX(hv));
+
+#ifdef PURIFY
+    new_body = new_NOARENAZ(&fake_hv_with_aux);
+#else
+    new_body_from_arena(new_body, HVAUX_ARENA_ROOT_IX, fake_hv_with_aux);
+#endif
+
+    old_body = SvANY(hv);
+
+    Copy((char *)old_body + old_type_details->offset,
+         (char *)new_body + fake_hv_with_aux.offset,
+         old_type_details->copy,
+         char);
+
+#ifdef PURIFY
+    safefree(old_body);
+#else
+    assert(old_type_details->arena);
+    del_body((void*)((char*)old_body + old_type_details->offset),
+             &PL_body_roots[SVt_PVHV]);
+#endif
+
+    SvANY(hv) = (XPVHV *) new_body;
+    SvFLAGS(hv) |= SVphv_HasAUX;
+    return HvAUX(hv);
+}
+
 /*
 =for apidoc sv_backoff
 
@@ -1511,7 +1340,7 @@ Perl_sv_backoff(SV *const sv)
     assert(SvTYPE(sv) != SVt_PVAV);
 
     SvOOK_offset(sv, delta);
-    
+
     SvLEN_set(sv, SvLEN(sv) + delta);
     SvPV_set(sv, SvPVX(sv) - delta);
     SvFLAGS(sv) &= ~SVf_OOK;
@@ -1543,21 +1372,21 @@ Perl_sv_grow(pTHX_ SV *const sv, STRLEN newlen)
     PERL_ARGS_ASSERT_SV_GROW;
 
     if (SvROK(sv))
-       sv_unref(sv);
+        sv_unref(sv);
     if (SvTYPE(sv) < SVt_PV) {
-       sv_upgrade(sv, SVt_PV);
-       s = SvPVX_mutable(sv);
+        sv_upgrade(sv, SVt_PV);
+        s = SvPVX_mutable(sv);
     }
     else if (SvOOK(sv)) {      /* pv is offset? */
-       sv_backoff(sv);
-       s = SvPVX_mutable(sv);
-       if (newlen > SvLEN(sv))
-           newlen += 10 * (newlen - SvCUR(sv)); /* avoid copy each time */
+        sv_backoff(sv);
+        s = SvPVX_mutable(sv);
+        if (newlen > SvLEN(sv))
+            newlen += 10 * (newlen - SvCUR(sv)); /* avoid copy each time */
     }
     else
     {
-       if (SvIsCOW(sv)) S_sv_uncow(aTHX_ sv, 0);
-       s = SvPVX_mutable(sv);
+        if (SvIsCOW(sv)) S_sv_uncow(aTHX_ sv, 0);
+        s = SvPVX_mutable(sv);
     }
 
 #ifdef PERL_COPY_ON_WRITE
@@ -1578,10 +1407,10 @@ Perl_sv_grow(pTHX_ SV *const sv, STRLEN newlen)
 #endif
 
     if (newlen > SvLEN(sv)) {          /* need more room? */
-       STRLEN minlen = SvCUR(sv);
-       minlen += (minlen >> PERL_STRLEN_EXPAND_SHIFT) + 10;
-       if (newlen < minlen)
-           newlen = minlen;
+        STRLEN minlen = SvCUR(sv);
+        minlen += (minlen >> PERL_STRLEN_EXPAND_SHIFT) + PERL_STRLEN_NEW_MIN;
+        if (newlen < minlen)
+            newlen = minlen;
 #ifndef PERL_UNWARANTED_CHUMMINESS_WITH_MALLOC
 
         /* Don't round up on the first allocation, as odds are pretty good that
@@ -1592,21 +1421,21 @@ Perl_sv_grow(pTHX_ SV *const sv, STRLEN newlen)
                 newlen = rounded;
         }
 #endif
-       if (SvLEN(sv) && s) {
-           s = (char*)saferealloc(s, newlen);
-       }
-       else {
-           s = (char*)safemalloc(newlen);
-           if (SvPVX_const(sv) && SvCUR(sv)) {
+        if (SvLEN(sv) && s) {
+            s = (char*)saferealloc(s, newlen);
+        }
+        else {
+            s = (char*)safemalloc(newlen);
+            if (SvPVX_const(sv) && SvCUR(sv)) {
                 Move(SvPVX_const(sv), s, SvCUR(sv), char);
-           }
-       }
-       SvPV_set(sv, s);
+            }
+        }
+        SvPV_set(sv, s);
 #ifdef PERL_UNWARANTED_CHUMMINESS_WITH_MALLOC
-       /* 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));
+        /* 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
@@ -1615,10 +1444,64 @@ Perl_sv_grow(pTHX_ SV *const sv, STRLEN newlen)
 }
 
 /*
+=for apidoc sv_grow_fresh
+
+A cut-down version of sv_grow intended only for when sv is a freshly-minted
+SVt_PV, SVt_PVIV, SVt_PVNV, or SVt_PVMG. i.e. sv has the default flags, has
+never been any other type, and does not have an existing string. Basically,
+just assigns a char buffer and returns a pointer to it.
+
+=cut
+*/
+
+
+char *
+Perl_sv_grow_fresh(pTHX_ SV *const sv, STRLEN newlen)
+{
+    char *s;
+
+    PERL_ARGS_ASSERT_SV_GROW_FRESH;
+
+    assert(SvTYPE(sv) >= SVt_PV && SvTYPE(sv) <= SVt_PVMG);
+    assert(!SvROK(sv));
+    assert(!SvOOK(sv));
+    assert(!SvIsCOW(sv));
+    assert(!SvLEN(sv));
+    assert(!SvCUR(sv));
+
+#ifdef PERL_COPY_ON_WRITE
+    /* the new COW scheme uses SvPVX(sv)[SvLEN(sv)-1] (if spare)
+     * to store the COW count. So in general, allocate one more byte than
+     * asked for, to make it likely this byte is always spare: and thus
+     * make more strings COW-able.
+     *
+     * Only increment if the allocation isn't MEM_SIZE_MAX,
+     * otherwise it will wrap to 0.
+     */
+    if ( newlen != MEM_SIZE_MAX )
+        newlen++;
+#endif
+
+    if (newlen < PERL_STRLEN_NEW_MIN)
+        newlen = PERL_STRLEN_NEW_MIN;
+
+    s = (char*)safemalloc(newlen);
+    SvPV_set(sv, s);
+
+    /* No PERL_UNWARANTED_CHUMMINESS_WITH_MALLOC here, since many strings */
+    /* will never be grown once set. Let the real sv_grow worry about that. */
+    SvLEN_set(sv, newlen);
+    return s;
+}
+
+/*
 =for apidoc sv_setiv
+=for apidoc_item sv_setiv_mg
+
+These copy an integer into the given SV, upgrading first if necessary.
 
-Copies an integer into the given SV, upgrading first if necessary.
-Does not handle 'set' magic.  See also C<L</sv_setiv_mg>>.
+They differ only in that C<sv_setiv_mg> handles 'set' magic; C<sv_setiv> does
+not.
 
 =cut
 */
@@ -1630,26 +1513,39 @@ Perl_sv_setiv(pTHX_ SV *const sv, const IV i)
 
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     switch (SvTYPE(sv)) {
+#if NVSIZE <= IVSIZE
+    case SVt_NULL:
+    case SVt_NV:
+        SET_SVANY_FOR_BODYLESS_IV(sv);
+        SvFLAGS(sv) &= ~SVTYPEMASK;
+        SvFLAGS(sv) |= SVt_IV;
+        break;
+#else
     case SVt_NULL:
+        SET_SVANY_FOR_BODYLESS_IV(sv);
+        SvFLAGS(sv) &= ~SVTYPEMASK;
+        SvFLAGS(sv) |= SVt_IV;
+        break;
     case SVt_NV:
-       sv_upgrade(sv, SVt_IV);
-       break;
+        sv_upgrade(sv, SVt_IV);
+        break;
+#endif
     case SVt_PV:
-       sv_upgrade(sv, SVt_PVIV);
-       break;
+        sv_upgrade(sv, SVt_PVIV);
+        break;
 
     case SVt_PVGV:
-       if (!isGV_with_GP(sv))
-           break;
+        if (!isGV_with_GP(sv))
+            break;
         /* FALLTHROUGH */
     case SVt_PVAV:
     case SVt_PVHV:
     case SVt_PVCV:
     case SVt_PVFM:
     case SVt_PVIO:
-       /* diag_listed_as: Can't coerce %s to %s in %s */
-       Perl_croak(aTHX_ "Can't coerce %s to integer in %s", sv_reftype(sv,0),
-                  OP_DESC(PL_op));
+        /* diag_listed_as: Can't coerce %s to %s in %s */
+        Perl_croak(aTHX_ "Can't coerce %s to integer in %s", sv_reftype(sv,0),
+                   OP_DESC(PL_op));
         NOT_REACHED; /* NOTREACHED */
         break;
     default: NOOP;
@@ -1659,14 +1555,6 @@ Perl_sv_setiv(pTHX_ SV *const sv, const IV i)
     SvTAINT(sv);
 }
 
-/*
-=for apidoc sv_setiv_mg
-
-Like C<sv_setiv>, but also handles 'set' magic.
-
-=cut
-*/
-
 void
 Perl_sv_setiv_mg(pTHX_ SV *const sv, const IV i)
 {
@@ -1678,9 +1566,13 @@ Perl_sv_setiv_mg(pTHX_ SV *const sv, const IV i)
 
 /*
 =for apidoc sv_setuv
+=for apidoc_item sv_setuv_mg
 
-Copies an unsigned integer into the given SV, upgrading first if necessary.
-Does not handle 'set' magic.  See also C<L</sv_setuv_mg>>.
+These copy an unsigned integer into the given SV, upgrading first if necessary.
+
+
+They differ only in that C<sv_setuv_mg> handles 'set' magic; C<sv_setuv> does
+not.
 
 =cut
 */
@@ -1710,14 +1602,6 @@ Perl_sv_setuv(pTHX_ SV *const sv, const UV u)
     SvUV_set(sv, u);
 }
 
-/*
-=for apidoc sv_setuv_mg
-
-Like C<sv_setuv>, but also handles 'set' magic.
-
-=cut
-*/
-
 void
 Perl_sv_setuv_mg(pTHX_ SV *const sv, const UV u)
 {
@@ -1729,9 +1613,12 @@ Perl_sv_setuv_mg(pTHX_ SV *const sv, const UV u)
 
 /*
 =for apidoc sv_setnv
+=for apidoc_item sv_setnv_mg
 
-Copies a double into the given SV, upgrading first if necessary.
-Does not handle 'set' magic.  See also C<L</sv_setnv_mg>>.
+These copy a double into the given SV, upgrading first if necessary.
+
+They differ only in that C<sv_setnv_mg> handles 'set' magic; C<sv_setnv> does
+not.
 
 =cut
 */
@@ -1745,25 +1632,32 @@ Perl_sv_setnv(pTHX_ SV *const sv, const NV num)
     switch (SvTYPE(sv)) {
     case SVt_NULL:
     case SVt_IV:
-       sv_upgrade(sv, SVt_NV);
-       break;
+#if NVSIZE <= IVSIZE
+        SET_SVANY_FOR_BODYLESS_NV(sv);
+        SvFLAGS(sv) &= ~SVTYPEMASK;
+        SvFLAGS(sv) |= SVt_NV;
+        break;
+#else
+        sv_upgrade(sv, SVt_NV);
+        break;
+#endif
     case SVt_PV:
     case SVt_PVIV:
-       sv_upgrade(sv, SVt_PVNV);
-       break;
+        sv_upgrade(sv, SVt_PVNV);
+        break;
 
     case SVt_PVGV:
-       if (!isGV_with_GP(sv))
-           break;
+        if (!isGV_with_GP(sv))
+            break;
         /* FALLTHROUGH */
     case SVt_PVAV:
     case SVt_PVHV:
     case SVt_PVCV:
     case SVt_PVFM:
     case SVt_PVIO:
-       /* diag_listed_as: Can't coerce %s to %s in %s */
-       Perl_croak(aTHX_ "Can't coerce %s to number in %s", sv_reftype(sv,0),
-                  OP_DESC(PL_op));
+        /* diag_listed_as: Can't coerce %s to %s in %s */
+        Perl_croak(aTHX_ "Can't coerce %s to number in %s", sv_reftype(sv,0),
+                   OP_DESC(PL_op));
         NOT_REACHED; /* NOTREACHED */
         break;
     default: NOOP;
@@ -1773,20 +1667,77 @@ Perl_sv_setnv(pTHX_ SV *const sv, const NV num)
     SvTAINT(sv);
 }
 
+void
+Perl_sv_setnv_mg(pTHX_ SV *const sv, const NV num)
+{
+    PERL_ARGS_ASSERT_SV_SETNV_MG;
+
+    sv_setnv(sv,num);
+    SvSETMAGIC(sv);
+}
+
 /*
-=for apidoc sv_setnv_mg
+=for apidoc sv_setrv_noinc
+=for apidoc_item sv_setrv_noinc_mg
+
+Copies an SV pointer into the given SV as an SV reference, upgrading it if
+necessary. After this, C<SvRV(sv)> is equal to I<ref>. This does not adjust
+the reference count of I<ref>. The reference I<ref> must not be NULL.
 
-Like C<sv_setnv>, but also handles 'set' magic.
+C<sv_setrv_noinc_mg> will invoke 'set' magic on the SV; C<sv_setrv_noinc> will
+not.
 
 =cut
 */
 
 void
-Perl_sv_setnv_mg(pTHX_ SV *const sv, const NV num)
+Perl_sv_setrv_noinc(pTHX_ SV *const sv, SV *const ref)
 {
-    PERL_ARGS_ASSERT_SV_SETNV_MG;
+    PERL_ARGS_ASSERT_SV_SETRV_NOINC;
 
-    sv_setnv(sv,num);
+    SV_CHECK_THINKFIRST_COW_DROP(sv);
+    prepare_SV_for_RV(sv);
+
+    SvOK_off(sv);
+    SvRV_set(sv, ref);
+    SvROK_on(sv);
+}
+
+void
+Perl_sv_setrv_noinc_mg(pTHX_ SV *const sv, SV *const ref)
+{
+    PERL_ARGS_ASSERT_SV_SETRV_NOINC_MG;
+
+    sv_setrv_noinc(sv, ref);
+    SvSETMAGIC(sv);
+}
+
+/*
+=for apidoc sv_setrv_inc
+=for apidoc_item sv_setrv_inc_mg
+
+As C<sv_setrv_noinc> but increments the reference count of I<ref>.
+
+C<sv_setrv_inc_mg> will invoke 'set' magic on the SV; C<sv_setrv_inc> will
+not.
+
+=cut
+*/
+
+void
+Perl_sv_setrv_inc(pTHX_ SV *const sv, SV *const ref)
+{
+    PERL_ARGS_ASSERT_SV_SETRV_INC;
+
+    sv_setrv_noinc(sv, SvREFCNT_inc_simple_NN(ref));
+}
+
+void
+Perl_sv_setrv_inc_mg(pTHX_ SV *const sv, SV *const ref)
+{
+    PERL_ARGS_ASSERT_SV_SETRV_INC_MG;
+
+    sv_setrv_noinc(sv, SvREFCNT_inc_simple_NN(ref));
     SvSETMAGIC(sv);
 }
 
@@ -1806,56 +1757,56 @@ S_sv_display(pTHX_ SV *const sv, char *tmpbuf, STRLEN tmpbuf_size) {
           SV *dsv = newSVpvs_flags("", SVs_TEMP);
           pv = sv_uni_display(dsv, sv, 32, UNI_DISPLAY_ISPRINT);
      } else {
-         char *d = tmpbuf;
-         const char * const limit = tmpbuf + tmpbuf_size - 8;
-         /* each *s can expand to 4 chars + "...\0",
-            i.e. need room for 8 chars */
-       
-         const char *s = SvPVX_const(sv);
-         const char * const end = s + SvCUR(sv);
-         for ( ; s < end && d < limit; s++ ) {
-              int ch = *s & 0xFF;
-              if (! isASCII(ch) && !isPRINT_LC(ch)) {
-                   *d++ = 'M';
-                   *d++ = '-';
+          char *d = tmpbuf;
+          const char * const limit = tmpbuf + tmpbuf_size - 8;
+          /* each *s can expand to 4 chars + "...\0",
+             i.e. need room for 8 chars */
+
+          const char *s = SvPVX_const(sv);
+          const char * const end = s + SvCUR(sv);
+          for ( ; s < end && d < limit; s++ ) {
+               int ch = (U8) *s;
+               if (! isASCII(ch) && !isPRINT_LC(ch)) {
+                    *d++ = 'M';
+                    *d++ = '-';
 
                     /* Map to ASCII "equivalent" of Latin1 */
-                   ch = LATIN1_TO_NATIVE(NATIVE_TO_LATIN1(ch) & 127);
-              }
-              if (ch == '\n') {
-                   *d++ = '\\';
-                   *d++ = 'n';
-              }
-              else if (ch == '\r') {
-                   *d++ = '\\';
-                   *d++ = 'r';
-              }
-              else if (ch == '\f') {
-                   *d++ = '\\';
-                   *d++ = 'f';
-              }
-              else if (ch == '\\') {
-                   *d++ = '\\';
-                   *d++ = '\\';
-              }
-              else if (ch == '\0') {
-                   *d++ = '\\';
-                   *d++ = '0';
-              }
-              else if (isPRINT_LC(ch))
-                   *d++ = ch;
-              else {
-                   *d++ = '^';
-                   *d++ = toCTRL(ch);
-              }
-         }
-         if (s < end) {
-              *d++ = '.';
-              *d++ = '.';
-              *d++ = '.';
-         }
-         *d = '\0';
-         pv = tmpbuf;
+                    ch = LATIN1_TO_NATIVE(NATIVE_TO_LATIN1(ch) & 127);
+               }
+               if (ch == '\n') {
+                    *d++ = '\\';
+                    *d++ = 'n';
+               }
+               else if (ch == '\r') {
+                    *d++ = '\\';
+                    *d++ = 'r';
+               }
+               else if (ch == '\f') {
+                    *d++ = '\\';
+                    *d++ = 'f';
+               }
+               else if (ch == '\\') {
+                    *d++ = '\\';
+                    *d++ = '\\';
+               }
+               else if (ch == '\0') {
+                    *d++ = '\\';
+                    *d++ = '0';
+               }
+               else if (isPRINT_LC(ch))
+                    *d++ = ch;
+               else {
+                    *d++ = '^';
+                    *d++ = toCTRL(ch);
+               }
+          }
+          if (s < end) {
+               *d++ = '.';
+               *d++ = '.';
+               *d++ = '.';
+          }
+          *d = '\0';
+          pv = tmpbuf;
     }
 
     return pv;
@@ -1876,14 +1827,14 @@ S_not_a_number(pTHX_ SV *const sv)
      pv = sv_display(sv, tmpbuf, sizeof(tmpbuf));
 
     if (PL_op)
-       Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
-                   /* diag_listed_as: Argument "%s" isn't numeric%s */
-                   "Argument \"%s\" isn't numeric in %s", pv,
-                   OP_DESC(PL_op));
+        Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
+                    /* diag_listed_as: Argument "%s" isn't numeric%s */
+                    "Argument \"%s\" isn't numeric in %s", pv,
+                    OP_DESC(PL_op));
     else
-       Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
-                   /* diag_listed_as: Argument "%s" isn't numeric%s */
-                   "Argument \"%s\" isn't numeric", pv);
+        Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
+                    /* diag_listed_as: Argument "%s" isn't numeric%s */
+                    "Argument \"%s\" isn't numeric", pv);
 }
 
 STATIC void
@@ -1920,10 +1871,10 @@ Perl_looks_like_number(pTHX_ SV *const sv)
     PERL_ARGS_ASSERT_LOOKS_LIKE_NUMBER;
 
     if (SvPOK(sv) || SvPOKp(sv)) {
-       sbegin = SvPV_nomg_const(sv, len);
+        sbegin = SvPV_nomg_const(sv, len);
     }
     else
-       return SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK);
+        return SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK);
     numtype = grok_number(sbegin, len, NULL);
     return ((numtype & IS_NUMBER_TRAILING)) ? 0 : numtype;
 }
@@ -1934,15 +1885,15 @@ S_glob_2number(pTHX_ GV * const gv)
     PERL_ARGS_ASSERT_GLOB_2NUMBER;
 
     /* We know that all GVs stringify to something that is not-a-number,
-       so no need to test that.  */
+        so no need to test that.  */
     if (ckWARN(WARN_NUMERIC))
     {
-       SV *const buffer = sv_newmortal();
-       gv_efullname3(buffer, gv, "*");
-       not_a_number(buffer);
+        SV *const buffer = sv_newmortal();
+        gv_efullname3(buffer, gv, "*");
+        not_a_number(buffer);
     }
     /* We just want something true to return, so that S_sv_2iuv_common
-       can tail call us and return true.  */
+        can tail call us and return true.  */
     return TRUE;
 }
 
@@ -2033,32 +1984,32 @@ S_glob_2number(pTHX_ GV * const gv)
 STATIC int
 S_sv_2iuv_non_preserve(pTHX_ SV *const sv
 #  ifdef DEBUGGING
-                      , I32 numtype
+                       , I32 numtype
 #  endif
-                      )
+                       )
 {
     PERL_ARGS_ASSERT_SV_2IUV_NON_PRESERVE;
     PERL_UNUSED_CONTEXT;
 
     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);
-       (void)SvNOK_on(sv);
-       SvIV_set(sv, IV_MIN);
-       return IS_NUMBER_UNDERFLOW_IV;
+        (void)SvIOKp_on(sv);
+        (void)SvNOK_on(sv);
+        SvIV_set(sv, IV_MIN);
+        return IS_NUMBER_UNDERFLOW_IV;
     }
     if (SvNVX(sv) > (NV)UV_MAX) {
-       (void)SvIOKp_on(sv);
-       (void)SvNOK_on(sv);
-       SvIsUV_on(sv);
-       SvUV_set(sv, UV_MAX);
-       return IS_NUMBER_OVERFLOW_UV;
+        (void)SvIOKp_on(sv);
+        (void)SvNOK_on(sv);
+        SvIsUV_on(sv);
+        SvUV_set(sv, UV_MAX);
+        return IS_NUMBER_OVERFLOW_UV;
     }
     (void)SvIOKp_on(sv);
     (void)SvNOK_on(sv);
     /* Can't use strtol etc to convert this string.  (See truth table in
        sv_2iv  */
-    if (SvNVX(sv) <= (UV)IV_MAX) {
+    if (SvNVX(sv) < IV_MAX_P1) {
         SvIV_set(sv, I_V(SvNVX(sv)));
         if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
             SvIOK_on(sv); /* Integer is precise. NOK, IOK */
@@ -2121,96 +2072,97 @@ S_sv_2iuv_common(pTHX_ SV *const sv)
     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
-        * (ie PV->NV conversion should detect loss of accuracy and cache
-        * IV or UV at same time to avoid this. */
-       /* IV-over-UV optimisation - choose to cache IV if possible */
-
-       if (SvTYPE(sv) == SVt_NV)
-           sv_upgrade(sv, SVt_PVNV);
-
-       (void)SvIOKp_on(sv);    /* Must do this first, to clear any SvOOK */
-       /* < not <= as for NV doesn't preserve UV, ((NV)IV_MAX+1) will almost
-          certainly cast into the IV range at IV_MAX, whereas the correct
-          answer is the UV IV_MAX +1. Hence < ensures that dodgy boundary
-          cases go to UV */
+        /* 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
+         * (ie PV->NV conversion should detect loss of accuracy and cache
+         * IV or UV at same time to avoid this. */
+        /* IV-over-UV optimisation - choose to cache IV if possible */
+
+        if (SvTYPE(sv) == SVt_NV)
+            sv_upgrade(sv, SVt_PVNV);
+
+    got_nv:
+        (void)SvIOKp_on(sv);   /* Must do this first, to clear any SvOOK */
+        /* < not <= as for NV doesn't preserve UV, ((NV)IV_MAX+1) will almost
+           certainly cast into the IV range at IV_MAX, whereas the correct
+           answer is the UV IV_MAX +1. Hence < ensures that dodgy boundary
+           cases go to UV */
 #if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
-       if (Perl_isnan(SvNVX(sv))) {
-           SvUV_set(sv, 0);
-           SvIsUV_on(sv);
-           return FALSE;
-       }
+        if (Perl_isnan(SvNVX(sv))) {
+            SvUV_set(sv, 0);
+            SvIsUV_on(sv);
+            return FALSE;
+        }
 #endif
-       if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
-           SvIV_set(sv, I_V(SvNVX(sv)));
-           if (SvNVX(sv) == (NV) SvIVX(sv)
+        if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
+            SvIV_set(sv, I_V(SvNVX(sv)));
+            if (SvNVX(sv) == (NV) SvIVX(sv)
 #ifndef NV_PRESERVES_UV
                 && SvIVX(sv) != IV_MIN /* avoid negating IV_MIN below */
-               && (((UV)1 << NV_PRESERVES_UV_BITS) >
-                   (UV)(SvIVX(sv) > 0 ? SvIVX(sv) : -SvIVX(sv)))
-               /* Don't flag it as "accurately an integer" if the number
-                  came from a (by definition imprecise) NV operation, and
-                  we're outside the range of NV integer precision */
+                && (((UV)1 << NV_PRESERVES_UV_BITS) >
+                    (UV)(SvIVX(sv) > 0 ? SvIVX(sv) : -SvIVX(sv)))
+                /* Don't flag it as "accurately an integer" if the number
+                   came from a (by definition imprecise) NV operation, and
+                   we're outside the range of NV integer precision */
 #endif
-               ) {
-               if (SvNOK(sv))
-                   SvIOK_on(sv);  /* Can this go wrong with rounding? NWC */
-               else {
-                   /* scalar has trailing garbage, eg "42a" */
-               }
-               DEBUG_c(PerlIO_printf(Perl_debug_log,
-                                     "0x%" UVxf " iv(%" NVgf " => %" IVdf ") (precise)\n",
-                                     PTR2UV(sv),
-                                     SvNVX(sv),
-                                     SvIVX(sv)));
-
-           } else {
-               /* IV not precise.  No need to convert from PV, as NV
-                  conversion would already have cached IV if it detected
-                  that PV->IV would be better than PV->NV->IV
-                  flags already correct - don't set public IOK.  */
-               DEBUG_c(PerlIO_printf(Perl_debug_log,
-                                     "0x%" UVxf " iv(%" NVgf " => %" IVdf ") (imprecise)\n",
-                                     PTR2UV(sv),
-                                     SvNVX(sv),
-                                     SvIVX(sv)));
-           }
-           /* Can the above go wrong if SvIVX == IV_MIN and SvNVX < IV_MIN,
-              but the cast (NV)IV_MIN rounds to a the value less (more
-              negative) than IV_MIN which happens to be equal to SvNVX ??
-              Analogous to 0xFFFFFFFFFFFFFFFF rounding up to NV (2**64) and
-              NV rounding back to 0xFFFFFFFFFFFFFFFF, so UVX == UV(NVX) and
-              (NV)UVX == NVX are both true, but the values differ. :-(
-              Hopefully for 2s complement IV_MIN is something like
-              0x8000000000000000 which will be exact. NWC */
-       }
-       else {
-           SvUV_set(sv, U_V(SvNVX(sv)));
-           if (
-               (SvNVX(sv) == (NV) SvUVX(sv))
+                ) {
+                if (SvNOK(sv))
+                    SvIOK_on(sv);  /* Can this go wrong with rounding? NWC */
+                else {
+                    /* scalar has trailing garbage, eg "42a" */
+                }
+                DEBUG_c(PerlIO_printf(Perl_debug_log,
+                                      "0x%" UVxf " iv(%" NVgf " => %" IVdf ") (precise)\n",
+                                      PTR2UV(sv),
+                                      SvNVX(sv),
+                                      SvIVX(sv)));
+
+            } else {
+                /* IV not precise.  No need to convert from PV, as NV
+                   conversion would already have cached IV if it detected
+                   that PV->IV would be better than PV->NV->IV
+                   flags already correct - don't set public IOK.  */
+                DEBUG_c(PerlIO_printf(Perl_debug_log,
+                                      "0x%" UVxf " iv(%" NVgf " => %" IVdf ") (imprecise)\n",
+                                      PTR2UV(sv),
+                                      SvNVX(sv),
+                                      SvIVX(sv)));
+            }
+            /* Can the above go wrong if SvIVX == IV_MIN and SvNVX < IV_MIN,
+               but the cast (NV)IV_MIN rounds to a the value less (more
+               negative) than IV_MIN which happens to be equal to SvNVX ??
+               Analogous to 0xFFFFFFFFFFFFFFFF rounding up to NV (2**64) and
+               NV rounding back to 0xFFFFFFFFFFFFFFFF, so UVX == UV(NVX) and
+               (NV)UVX == NVX are both true, but the values differ. :-(
+               Hopefully for 2s complement IV_MIN is something like
+               0x8000000000000000 which will be exact. NWC */
+        }
+        else {
+            SvUV_set(sv, U_V(SvNVX(sv)));
+            if (
+                (SvNVX(sv) == (NV) SvUVX(sv))
 #ifndef  NV_PRESERVES_UV
-               /* Make sure it's not 0xFFFFFFFFFFFFFFFF */
-               /*&& (SvUVX(sv) != UV_MAX) irrelevant with code below */
-               && (((UV)1 << NV_PRESERVES_UV_BITS) > SvUVX(sv))
-               /* Don't flag it as "accurately an integer" if the number
-                  came from a (by definition imprecise) NV operation, and
-                  we're outside the range of NV integer precision */
+                /* Make sure it's not 0xFFFFFFFFFFFFFFFF */
+                /*&& (SvUVX(sv) != UV_MAX) irrelevant with code below */
+                && (((UV)1 << NV_PRESERVES_UV_BITS) > SvUVX(sv))
+                /* Don't flag it as "accurately an integer" if the number
+                   came from a (by definition imprecise) NV operation, and
+                   we're outside the range of NV integer precision */
 #endif
-               && SvNOK(sv)
-               )
-               SvIOK_on(sv);
-           SvIsUV_on(sv);
-           DEBUG_c(PerlIO_printf(Perl_debug_log,
-                                 "0x%" UVxf " 2iv(%" UVuf " => %" IVdf ") (as unsigned)\n",
-                                 PTR2UV(sv),
-                                 SvUVX(sv),
-                                 SvUVX(sv)));
-       }
+                && SvNOK(sv)
+                )
+                SvIOK_on(sv);
+            SvIsUV_on(sv);
+            DEBUG_c(PerlIO_printf(Perl_debug_log,
+                                  "0x%" UVxf " 2iv(%" UVuf " => %" IVdf ") (as unsigned)\n",
+                                  PTR2UV(sv),
+                                  SvUVX(sv),
+                                  SvUVX(sv)));
+        }
     }
     else if (SvPOKp(sv)) {
-       UV value;
-       int numtype;
+        UV value;
+        int numtype;
         const char *s = SvPVX_const(sv);
         const STRLEN cur = SvCUR(sv);
 
@@ -2227,154 +2179,124 @@ S_sv_2iuv_common(pTHX_ SV *const sv)
             }
         }
 
-       numtype = grok_number(s, cur, &value);
-       /* We want to avoid a possible problem when we cache an IV/ a UV which
-          may be later translated to an NV, and the resulting NV is not
-          the same as the direct translation of the initial string
-          (eg 123.456 can shortcut to the IV 123 with atol(), but we must
-          be careful to ensure that the value with the .456 is around if the
-          NV value is requested in the future).
-       
-          This means that if we cache such an IV/a UV, we need to cache the
-          NV as well.  Moreover, we trade speed for space, and do not
-          cache the NV if we are sure it's not needed.
-        */
-
-       /* SVt_PVNV is one higher than SVt_PVIV, hence this order  */
-       if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
-            == IS_NUMBER_IN_UV) {
-           /* It's definitely an integer, only upgrade to PVIV */
-           if (SvTYPE(sv) < SVt_PVIV)
-               sv_upgrade(sv, SVt_PVIV);
-           (void)SvIOK_on(sv);
-       } else if (SvTYPE(sv) < SVt_PVNV)
-           sv_upgrade(sv, SVt_PVNV);
+        numtype = grok_number(s, cur, &value);
+        /* We want to avoid a possible problem when we cache an IV/ a UV which
+           may be later translated to an NV, and the resulting NV is not
+           the same as the direct translation of the initial string
+           (eg 123.456 can shortcut to the IV 123 with atol(), but we must
+           be careful to ensure that the value with the .456 is around if the
+           NV value is requested in the future).
+
+           This means that if we cache such an IV/a UV, we need to cache the
+           NV as well.  Moreover, we trade speed for space, and do not
+           cache the NV if we are sure it's not needed.
+         */
+
+        /* SVt_PVNV is one higher than SVt_PVIV, hence this order  */
+        if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+             == IS_NUMBER_IN_UV) {
+            /* It's definitely an integer, only upgrade to PVIV */
+            if (SvTYPE(sv) < SVt_PVIV)
+                sv_upgrade(sv, SVt_PVIV);
+            (void)SvIOK_on(sv);
+        } else if (SvTYPE(sv) < SVt_PVNV)
+            sv_upgrade(sv, SVt_PVNV);
 
         if ((numtype & (IS_NUMBER_INFINITY | IS_NUMBER_NAN))) {
             if (ckWARN(WARN_NUMERIC) && ((numtype & IS_NUMBER_TRAILING)))
-               not_a_number(sv);
+                not_a_number(sv);
             S_sv_setnv(aTHX_ sv, numtype);
-            return FALSE;
+            goto got_nv;        /* Fill IV/UV slot and set IOKp */
         }
 
-       /* If NVs preserve UVs then we only use the UV value if we know that
-          we aren't going to call atof() below. If NVs don't preserve UVs
-          then the value returned may have more precision than atof() will
-          return, even though value isn't perfectly accurate.  */
-       if ((numtype & (IS_NUMBER_IN_UV
+        /* If NVs preserve UVs then we only use the UV value if we know that
+           we aren't going to call atof() below. If NVs don't preserve UVs
+           then the value returned may have more precision than atof() will
+           return, even though value isn't perfectly accurate.  */
+        if ((numtype & (IS_NUMBER_IN_UV
 #ifdef NV_PRESERVES_UV
-                       | IS_NUMBER_NOT_INT
+                        | IS_NUMBER_NOT_INT
 #endif
-           )) == IS_NUMBER_IN_UV) {
-           /* This won't turn off the public IOK flag if it was set above  */
-           (void)SvIOKp_on(sv);
-
-           if (!(numtype & IS_NUMBER_NEG)) {
-               /* positive */;
-               if (value <= (UV)IV_MAX) {
-                   SvIV_set(sv, (IV)value);
-               } else {
-                   /* it didn't overflow, and it was positive. */
-                   SvUV_set(sv, value);
-                   SvIsUV_on(sv);
-               }
-           } else {
-               /* 2s complement assumption  */
-               if (value <= (UV)IV_MIN) {
-                   SvIV_set(sv, value == (UV)IV_MIN
+            )) == IS_NUMBER_IN_UV) {
+            /* This won't turn off the public IOK flag if it was set above  */
+            (void)SvIOKp_on(sv);
+
+            if (!(numtype & IS_NUMBER_NEG)) {
+                /* positive */;
+                if (value <= (UV)IV_MAX) {
+                    SvIV_set(sv, (IV)value);
+                } else {
+                    /* it didn't overflow, and it was positive. */
+                    SvUV_set(sv, value);
+                    SvIsUV_on(sv);
+                }
+            } else {
+                /* 2s complement assumption  */
+                if (value <= (UV)IV_MIN) {
+                    SvIV_set(sv, value == (UV)IV_MIN
                                     ? IV_MIN : -(IV)value);
-               } else {
-                   /* Too negative for an IV.  This is a double upgrade, but
-                      I'm assuming it will be rare.  */
-                   if (SvTYPE(sv) < SVt_PVNV)
-                       sv_upgrade(sv, SVt_PVNV);
-                   SvNOK_on(sv);
-                   SvIOK_off(sv);
-                   SvIOKp_on(sv);
-                   SvNV_set(sv, -(NV)value);
-                   SvIV_set(sv, IV_MIN);
-               }
-           }
-       }
-       /* For !NV_PRESERVES_UV and IS_NUMBER_IN_UV and IS_NUMBER_NOT_INT we
+                } else {
+                    /* Too negative for an IV.  This is a double upgrade, but
+                       I'm assuming it will be rare.  */
+                    if (SvTYPE(sv) < SVt_PVNV)
+                        sv_upgrade(sv, SVt_PVNV);
+                    SvNOK_on(sv);
+                    SvIOK_off(sv);
+                    SvIOKp_on(sv);
+                    SvNV_set(sv, -(NV)value);
+                    SvIV_set(sv, IV_MIN);
+                }
+            }
+        }
+        /* For !NV_PRESERVES_UV and IS_NUMBER_IN_UV and IS_NUMBER_NOT_INT we
            will be in the previous block to set the IV slot, and the next
            block to set the NV slot.  So no else here.  */
-       
-       if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
-           != IS_NUMBER_IN_UV) {
-           /* It wasn't an (integer that doesn't overflow the UV). */
+
+        if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+            != IS_NUMBER_IN_UV) {
+            /* It wasn't an (integer that doesn't overflow the UV). */
             S_sv_setnv(aTHX_ sv, numtype);
 
-           if (! numtype && ckWARN(WARN_NUMERIC))
-               not_a_number(sv);
+            if (! numtype && ckWARN(WARN_NUMERIC))
+                not_a_number(sv);
 
-           DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%" UVxf " 2iv(%" NVgf ")\n",
-                                 PTR2UV(sv), SvNVX(sv)));
+            DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%" UVxf " 2iv(%" NVgf ")\n",
+                                  PTR2UV(sv), SvNVX(sv)));
 
 #ifdef NV_PRESERVES_UV
-            (void)SvIOKp_on(sv);
-            (void)SvNOK_on(sv);
-#if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
-            if (Perl_isnan(SvNVX(sv))) {
-                SvUV_set(sv, 0);
-                SvIsUV_on(sv);
-                return FALSE;
-            }
-#endif
-            if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
-                SvIV_set(sv, I_V(SvNVX(sv)));
-                if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
-                    SvIOK_on(sv);
-                } else {
-                   NOOP;  /* Integer is imprecise. NOK, IOKp */
-                }
-                /* UV will not work better than IV */
-            } else {
-                if (SvNVX(sv) > (NV)UV_MAX) {
-                    SvIsUV_on(sv);
-                    /* Integer is inaccurate. NOK, IOKp, is UV */
-                    SvUV_set(sv, UV_MAX);
-                } else {
-                    SvUV_set(sv, U_V(SvNVX(sv)));
-                    /* 0xFFFFFFFFFFFFFFFF not an issue in here, NVs
-                       NV preservse UV so can do correct comparison.  */
-                    if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
-                        SvIOK_on(sv);
-                    } else {
-                       NOOP;   /* Integer is imprecise. NOK, IOKp, is UV */
-                    }
-                }
-               SvIsUV_on(sv);
-            }
+            SvNOKp_on(sv);
+            if (numtype)
+                SvNOK_on(sv);
+            goto got_nv;        /* Fill IV/UV slot and set IOKp, maybe IOK */
 #else /* NV_PRESERVES_UV */
             if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
                 == (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT)) {
                 /* The IV/UV slot will have been set from value returned by
                    grok_number above.  The NV slot has just been set using
                    Atof.  */
-               SvNOK_on(sv);
+                SvNOK_on(sv);
                 assert (SvIOKp(sv));
             } else {
                 if (((UV)1 << NV_PRESERVES_UV_BITS) >
-                    U_V(SvNVX(sv) > 0 ? SvNVX(sv) : -SvNVX(sv))) {
+                    U_V(Perl_fabs(SvNVX(sv)))) {
                     /* Small enough to preserve all bits. */
                     (void)SvIOKp_on(sv);
                     SvNOK_on(sv);
                     SvIV_set(sv, I_V(SvNVX(sv)));
                     if ((NV)(SvIVX(sv)) == SvNVX(sv))
                         SvIOK_on(sv);
-                    /* Assumption: first non-preserved integer is < IV_MAX,
-                       this NV is in the preserved range, therefore: */
-                    if (!(U_V(SvNVX(sv) > 0 ? SvNVX(sv) : -SvNVX(sv))
-                          < (UV)IV_MAX)) {
-                        Perl_croak(aTHX_ "sv_2iv assumed (U_V(fabs((double)SvNVX(sv))) < (UV)IV_MAX) but SvNVX(sv)=%" NVgf " U_V is 0x%" UVxf ", IV_MAX is 0x%" UVxf "\n", SvNVX(sv), U_V(SvNVX(sv)), (UV)IV_MAX);
-                    }
+                    /* There had been runtime checking for
+                       "U_V(Perl_fabs(SvNVX(sv))) < (UV)IV_MAX" here to ensure
+                       that this NV is in the preserved range, but this should
+                       be always true if the following assertion is true: */
+                    STATIC_ASSERT_STMT(((UV)1 << NV_PRESERVES_UV_BITS) <=
+                                       (UV)IV_MAX);
                 } else {
                     /* IN_UV NOT_INT
                          0      0      already failed to read UV.
                          0      1       already failed to read UV.
                          1      0       you won't get here in this case. IV/UV
-                                       slot set, public IOK, Atof() unneeded.
+                                        slot set, public IOK, Atof() unneeded.
                          1      1       already read UV.
                        so there's no point in sv_2iuv_non_preserve() attempting
                        to use atol, strtol, strtoul etc.  */
@@ -2385,26 +2307,26 @@ S_sv_2iuv_common(pTHX_ SV *const sv)
 #  endif
                 }
             }
+        /* It might be more code efficient to go through the entire logic above
+           and conditionally set with SvIOKp_on() rather than SvIOK(), but it
+           gets complex and potentially buggy, so more programmer efficient
+           to do it this way, by turning off the public flags:  */
+        if (!numtype)
+            SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK);
 #endif /* NV_PRESERVES_UV */
-       /* It might be more code efficient to go through the entire logic above
-          and conditionally set with SvIOKp_on() rather than SvIOK(), but it
-          gets complex and potentially buggy, so more programmer efficient
-          to do it this way, by turning off the public flags:  */
-       if (!numtype)
-           SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK);
-       }
-    }
-    else  {
-       if (isGV_with_GP(sv))
-           return glob_2number(MUTABLE_GV(sv));
-
-       if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
-               report_uninit(sv);
-       if (SvTYPE(sv) < SVt_IV)
-           /* Typically the caller expects that sv_any is not NULL now.  */
-           sv_upgrade(sv, SVt_IV);
-       /* Return 0 from the caller.  */
-       return TRUE;
+        }
+    }
+    else {
+        if (isGV_with_GP(sv))
+            return glob_2number(MUTABLE_GV(sv));
+
+        if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
+                report_uninit(sv);
+        if (SvTYPE(sv) < SVt_IV)
+            /* Typically the caller expects that sv_any is not NULL now.  */
+            sv_upgrade(sv, SVt_IV);
+        /* Return 0 from the caller.  */
+        return TRUE;
     }
     return FALSE;
 }
@@ -2425,52 +2347,52 @@ Perl_sv_2iv_flags(pTHX_ SV *const sv, const I32 flags)
     PERL_ARGS_ASSERT_SV_2IV_FLAGS;
 
     assert (SvTYPE(sv) != SVt_PVAV && SvTYPE(sv) != SVt_PVHV
-        && SvTYPE(sv) != SVt_PVFM);
+         && SvTYPE(sv) != SVt_PVFM);
 
     if (SvGMAGICAL(sv) && (flags & SV_GMAGIC))
-       mg_get(sv);
+        mg_get(sv);
 
     if (SvROK(sv)) {
-       if (SvAMAGIC(sv)) {
-           SV * tmpstr;
-           if (flags & SV_SKIP_OVERLOAD)
-               return 0;
-           tmpstr = AMG_CALLunary(sv, numer_amg);
-           if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
-               return SvIV(tmpstr);
-           }
-       }
-       return PTR2IV(SvRV(sv));
+        if (SvAMAGIC(sv)) {
+            SV * tmpstr;
+            if (flags & SV_SKIP_OVERLOAD)
+                return 0;
+            tmpstr = AMG_CALLunary(sv, numer_amg);
+            if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
+                return SvIV(tmpstr);
+            }
+        }
+        return PTR2IV(SvRV(sv));
     }
 
     if (SvVALID(sv) || isREGEXP(sv)) {
         /* FBMs use the space for SvIVX and SvNVX for other purposes, so
            must not let them cache IVs.
-          In practice they are extremely unlikely to actually get anywhere
-          accessible by user Perl code - the only way that I'm aware of is when
-          a constant subroutine which is used as the second argument to index.
-
-          Regexps have no SvIVX and SvNVX fields.
-       */
-       assert(SvPOKp(sv));
-       {
-           UV value;
-           const char * const ptr =
-               isREGEXP(sv) ? RX_WRAPPED((REGEXP*)sv) : SvPVX_const(sv);
-           const int numtype
-               = grok_number(ptr, SvCUR(sv), &value);
-
-           if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
-               == IS_NUMBER_IN_UV) {
-               /* It's definitely an integer */
-               if (numtype & IS_NUMBER_NEG) {
-                   if (value < (UV)IV_MIN)
-                       return -(IV)value;
-               } else {
-                   if (value < (UV)IV_MAX)
-                       return (IV)value;
-               }
-           }
+           In practice they are extremely unlikely to actually get anywhere
+           accessible by user Perl code - the only way that I'm aware of is when
+           a constant subroutine which is used as the second argument to index.
+
+           Regexps have no SvIVX and SvNVX fields.
+        */
+        assert(SvPOKp(sv));
+        {
+            UV value;
+            const char * const ptr =
+                isREGEXP(sv) ? RX_WRAPPED((REGEXP*)sv) : SvPVX_const(sv);
+            const int numtype
+                = grok_number(ptr, SvCUR(sv), &value);
+
+            if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+                == IS_NUMBER_IN_UV) {
+                /* It's definitely an integer */
+                if (numtype & IS_NUMBER_NEG) {
+                    if (value < (UV)IV_MIN)
+                        return -(IV)value;
+                } else {
+                    if (value < (UV)IV_MAX)
+                        return (IV)value;
+                }
+            }
 
             /* Quite wrong but no good choices. */
             if ((numtype & IS_NUMBER_INFINITY)) {
@@ -2479,29 +2401,29 @@ Perl_sv_2iv_flags(pTHX_ SV *const sv, const I32 flags)
                 return 0; /* So wrong. */
             }
 
-           if (!numtype) {
-               if (ckWARN(WARN_NUMERIC))
-                   not_a_number(sv);
-           }
-           return I_V(Atof(ptr));
-       }
+            if (!numtype) {
+                if (ckWARN(WARN_NUMERIC))
+                    not_a_number(sv);
+            }
+            return I_V(Atof(ptr));
+        }
     }
 
     if (SvTHINKFIRST(sv)) {
-       if (SvREADONLY(sv) && !SvOK(sv)) {
-           if (ckWARN(WARN_UNINITIALIZED))
-               report_uninit(sv);
-           return 0;
-       }
+        if (SvREADONLY(sv) && !SvOK(sv)) {
+            if (ckWARN(WARN_UNINITIALIZED))
+                report_uninit(sv);
+            return 0;
+        }
     }
 
     if (!SvIOKp(sv)) {
-       if (S_sv_2iuv_common(aTHX_ sv))
-           return 0;
+        if (S_sv_2iuv_common(aTHX_ sv))
+            return 0;
     }
 
     DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%" UVxf " 2iv(%" IVdf ")\n",
-       PTR2UV(sv),SvIVX(sv)));
+        PTR2UV(sv),SvIVX(sv)));
     return SvIsUV(sv) ? (IV)SvUVX(sv) : SvIVX(sv);
 }
 
@@ -2523,39 +2445,39 @@ Perl_sv_2uv_flags(pTHX_ SV *const sv, const I32 flags)
     PERL_ARGS_ASSERT_SV_2UV_FLAGS;
 
     if (SvGMAGICAL(sv) && (flags & SV_GMAGIC))
-       mg_get(sv);
+        mg_get(sv);
 
     if (SvROK(sv)) {
-       if (SvAMAGIC(sv)) {
-           SV *tmpstr;
-           if (flags & SV_SKIP_OVERLOAD)
-               return 0;
-           tmpstr = AMG_CALLunary(sv, numer_amg);
-           if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
-               return SvUV(tmpstr);
-           }
-       }
-       return PTR2UV(SvRV(sv));
+        if (SvAMAGIC(sv)) {
+            SV *tmpstr;
+            if (flags & SV_SKIP_OVERLOAD)
+                return 0;
+            tmpstr = AMG_CALLunary(sv, numer_amg);
+            if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
+                return SvUV(tmpstr);
+            }
+        }
+        return PTR2UV(SvRV(sv));
     }
 
     if (SvVALID(sv) || isREGEXP(sv)) {
-       /* FBMs use the space for SvIVX and SvNVX for other purposes, and use
-          the same flag bit as SVf_IVisUV, so must not let them cache IVs.  
-          Regexps have no SvIVX and SvNVX fields. */
-       assert(SvPOKp(sv));
-       {
-           UV value;
-           const char * const ptr =
-               isREGEXP(sv) ? RX_WRAPPED((REGEXP*)sv) : SvPVX_const(sv);
-           const int numtype
-               = grok_number(ptr, SvCUR(sv), &value);
-
-           if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
-               == IS_NUMBER_IN_UV) {
-               /* It's definitely an integer */
-               if (!(numtype & IS_NUMBER_NEG))
-                   return value;
-           }
+        /* FBMs use the space for SvIVX and SvNVX for other purposes, and use
+           the same flag bit as SVf_IVisUV, so must not let them cache IVs.
+           Regexps have no SvIVX and SvNVX fields. */
+        assert(SvPOKp(sv));
+        {
+            UV value;
+            const char * const ptr =
+                isREGEXP(sv) ? RX_WRAPPED((REGEXP*)sv) : SvPVX_const(sv);
+            const int numtype
+                = grok_number(ptr, SvCUR(sv), &value);
+
+            if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+                == IS_NUMBER_IN_UV) {
+                /* It's definitely an integer */
+                if (!(numtype & IS_NUMBER_NEG))
+                    return value;
+            }
 
             /* Quite wrong but no good choices. */
             if ((numtype & IS_NUMBER_INFINITY)) {
@@ -2564,29 +2486,29 @@ Perl_sv_2uv_flags(pTHX_ SV *const sv, const I32 flags)
                 return 0; /* So wrong. */
             }
 
-           if (!numtype) {
-               if (ckWARN(WARN_NUMERIC))
-                   not_a_number(sv);
-           }
-           return U_V(Atof(ptr));
-       }
+            if (!numtype) {
+                if (ckWARN(WARN_NUMERIC))
+                    not_a_number(sv);
+            }
+            return U_V(Atof(ptr));
+        }
     }
 
     if (SvTHINKFIRST(sv)) {
-       if (SvREADONLY(sv) && !SvOK(sv)) {
-           if (ckWARN(WARN_UNINITIALIZED))
-               report_uninit(sv);
-           return 0;
-       }
+        if (SvREADONLY(sv) && !SvOK(sv)) {
+            if (ckWARN(WARN_UNINITIALIZED))
+                report_uninit(sv);
+            return 0;
+        }
     }
 
     if (!SvIOKp(sv)) {
-       if (S_sv_2iuv_common(aTHX_ sv))
-           return 0;
+        if (S_sv_2iuv_common(aTHX_ sv))
+            return 0;
     }
 
     DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%" UVxf " 2uv(%" UVuf ")\n",
-                         PTR2UV(sv),SvUVX(sv)));
+                          PTR2UV(sv),SvUVX(sv)));
     return SvIsUV(sv) ? SvUVX(sv) : (UV)SvIVX(sv);
 }
 
@@ -2606,129 +2528,128 @@ Perl_sv_2nv_flags(pTHX_ SV *const sv, const I32 flags)
     PERL_ARGS_ASSERT_SV_2NV_FLAGS;
 
     assert (SvTYPE(sv) != SVt_PVAV && SvTYPE(sv) != SVt_PVHV
-        && SvTYPE(sv) != SVt_PVFM);
+         && SvTYPE(sv) != SVt_PVFM);
     if (SvGMAGICAL(sv) || SvVALID(sv) || isREGEXP(sv)) {
-       /* FBMs use the space for SvIVX and SvNVX for other purposes, and use
-          the same flag bit as SVf_IVisUV, so must not let them cache NVs.
-          Regexps have no SvIVX and SvNVX fields.  */
-       const char *ptr;
-       if (flags & SV_GMAGIC)
-           mg_get(sv);
-       if (SvNOKp(sv))
-           return SvNVX(sv);
-       if (SvPOKp(sv) && !SvIOKp(sv)) {
-           ptr = SvPVX_const(sv);
-           if (!SvIOKp(sv) && ckWARN(WARN_NUMERIC) &&
-               !grok_number(ptr, SvCUR(sv), NULL))
-               not_a_number(sv);
-           return Atof(ptr);
-       }
-       if (SvIOKp(sv)) {
-           if (SvIsUV(sv))
-               return (NV)SvUVX(sv);
-           else
-               return (NV)SvIVX(sv);
-       }
+        /* FBMs use the space for SvIVX and SvNVX for other purposes, and use
+           the same flag bit as SVf_IVisUV, so must not let them cache NVs.
+           Regexps have no SvIVX and SvNVX fields.  */
+        const char *ptr;
+        if (flags & SV_GMAGIC)
+            mg_get(sv);
+        if (SvNOKp(sv))
+            return SvNVX(sv);
+        if (SvPOKp(sv) && !SvIOKp(sv)) {
+            ptr = SvPVX_const(sv);
+            if (!SvIOKp(sv) && ckWARN(WARN_NUMERIC) &&
+                !grok_number(ptr, SvCUR(sv), NULL))
+                not_a_number(sv);
+            return Atof(ptr);
+        }
+        if (SvIOKp(sv)) {
+            if (SvIsUV(sv))
+                return (NV)SvUVX(sv);
+            else
+                return (NV)SvIVX(sv);
+        }
         if (SvROK(sv)) {
-           goto return_rok;
-       }
-       assert(SvTYPE(sv) >= SVt_PVMG);
-       /* This falls through to the report_uninit near the end of the
-          function. */
+            goto return_rok;
+        }
+        assert(SvTYPE(sv) >= SVt_PVMG);
+        /* This falls through to the report_uninit near the end of the
+           function. */
     } else if (SvTHINKFIRST(sv)) {
-       if (SvROK(sv)) {
-       return_rok:
-           if (SvAMAGIC(sv)) {
-               SV *tmpstr;
-               if (flags & SV_SKIP_OVERLOAD)
-                   return 0;
-               tmpstr = AMG_CALLunary(sv, numer_amg);
+        if (SvROK(sv)) {
+        return_rok:
+            if (SvAMAGIC(sv)) {
+                SV *tmpstr;
+                if (flags & SV_SKIP_OVERLOAD)
+                    return 0;
+                tmpstr = AMG_CALLunary(sv, numer_amg);
                 if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
-                   return SvNV(tmpstr);
-               }
-           }
-           return PTR2NV(SvRV(sv));
-       }
-       if (SvREADONLY(sv) && !SvOK(sv)) {
-           if (ckWARN(WARN_UNINITIALIZED))
-               report_uninit(sv);
-           return 0.0;
-       }
+                    return SvNV(tmpstr);
+                }
+            }
+            return PTR2NV(SvRV(sv));
+        }
+        if (SvREADONLY(sv) && !SvOK(sv)) {
+            if (ckWARN(WARN_UNINITIALIZED))
+                report_uninit(sv);
+            return 0.0;
+        }
     }
     if (SvTYPE(sv) < SVt_NV) {
-       /* The logic to use SVt_PVNV if necessary is in sv_upgrade.  */
-       sv_upgrade(sv, SVt_NV);
+        /* The logic to use SVt_PVNV if necessary is in sv_upgrade.  */
+        sv_upgrade(sv, SVt_NV);
         CLANG_DIAG_IGNORE_STMT(-Wthread-safety);
-       DEBUG_c({
+        DEBUG_c({
             DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
             STORE_LC_NUMERIC_SET_STANDARD();
-           PerlIO_printf(Perl_debug_log,
-                         "0x%" UVxf " num(%" NVgf ")\n",
-                         PTR2UV(sv), SvNVX(sv));
+            PerlIO_printf(Perl_debug_log,
+                          "0x%" UVxf " num(%" NVgf ")\n",
+                          PTR2UV(sv), SvNVX(sv));
             RESTORE_LC_NUMERIC();
-       });
+        });
         CLANG_DIAG_RESTORE_STMT;
 
     }
     else if (SvTYPE(sv) < SVt_PVNV)
-       sv_upgrade(sv, SVt_PVNV);
+        sv_upgrade(sv, SVt_PVNV);
     if (SvNOKp(sv)) {
         return SvNVX(sv);
     }
     if (SvIOKp(sv)) {
-       SvNV_set(sv, SvIsUV(sv) ? (NV)SvUVX(sv) : (NV)SvIVX(sv));
+        SvNV_set(sv, SvIsUV(sv) ? (NV)SvUVX(sv) : (NV)SvIVX(sv));
 #ifdef NV_PRESERVES_UV
-       if (SvIOK(sv))
-           SvNOK_on(sv);
-       else
-           SvNOKp_on(sv);
+        if (SvIOK(sv))
+            SvNOK_on(sv);
+        else
+            SvNOKp_on(sv);
 #else
-       /* Only set the public NV OK flag if this NV preserves the IV  */
-       /* Check it's not 0xFFFFFFFFFFFFFFFF */
-       if (SvIOK(sv) &&
-           SvIsUV(sv) ? ((SvUVX(sv) != UV_MAX)&&(SvUVX(sv) == U_V(SvNVX(sv))))
-                      : (SvIVX(sv) == I_V(SvNVX(sv))))
-           SvNOK_on(sv);
-       else
-           SvNOKp_on(sv);
+        /* Only set the public NV OK flag if this NV preserves the IV  */
+        /* Check it's not 0xFFFFFFFFFFFFFFFF */
+        if (SvIOK(sv) &&
+            SvIsUV(sv) ? ((SvUVX(sv) != UV_MAX)&&(SvUVX(sv) == U_V(SvNVX(sv))))
+                       : (SvIVX(sv) == I_V(SvNVX(sv))))
+            SvNOK_on(sv);
+        else
+            SvNOKp_on(sv);
 #endif
     }
     else if (SvPOKp(sv)) {
-       UV value;
-       const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
-       if (!SvIOKp(sv) && !numtype && ckWARN(WARN_NUMERIC))
-           not_a_number(sv);
+        UV value;
+        const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
+        if (!SvIOKp(sv) && !numtype && ckWARN(WARN_NUMERIC))
+            not_a_number(sv);
 #ifdef NV_PRESERVES_UV
-       if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
-           == IS_NUMBER_IN_UV) {
-           /* It's definitely an integer */
-           SvNV_set(sv, (numtype & IS_NUMBER_NEG) ? -(NV)value : (NV)value);
-       } else {
+        if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+            == IS_NUMBER_IN_UV) {
+            /* It's definitely an integer */
+            SvNV_set(sv, (numtype & IS_NUMBER_NEG) ? -(NV)value : (NV)value);
+        } else {
             S_sv_setnv(aTHX_ sv, numtype);
         }
-       if (numtype)
-           SvNOK_on(sv);
-       else
-           SvNOKp_on(sv);
+        if (numtype)
+            SvNOK_on(sv);
+        else
+            SvNOKp_on(sv);
 #else
-       SvNV_set(sv, Atof(SvPVX_const(sv)));
-       /* Only set the public NV OK flag if this NV preserves the value in
-          the PV at least as well as an IV/UV would.
-          Not sure how to do this 100% reliably. */
-       /* if that shift count is out of range then Configure's test is
-          wonky. We shouldn't be in here with NV_PRESERVES_UV_BITS ==
-          UV_BITS */
-       if (((UV)1 << NV_PRESERVES_UV_BITS) >
-           U_V(SvNVX(sv) > 0 ? SvNVX(sv) : -SvNVX(sv))) {
-           SvNOK_on(sv); /* Definitely small enough to preserve all bits */
-       } else if (!(numtype & IS_NUMBER_IN_UV)) {
+        SvNV_set(sv, Atof(SvPVX_const(sv)));
+        /* Only set the public NV OK flag if this NV preserves the value in
+           the PV at least as well as an IV/UV would.
+           Not sure how to do this 100% reliably. */
+        /* if that shift count is out of range then Configure's test is
+           wonky. We shouldn't be in here with NV_PRESERVES_UV_BITS ==
+           UV_BITS */
+        if (((UV)1 << NV_PRESERVES_UV_BITS) > U_V(Perl_fabs(SvNVX(sv)))) {
+            SvNOK_on(sv); /* Definitely small enough to preserve all bits */
+        } else if (!(numtype & IS_NUMBER_IN_UV)) {
             /* Can't use strtol etc to convert this string, so don't try.
                sv_2iv and sv_2uv will use the NV to convert, not the PV.  */
             SvNOK_on(sv);
         } else {
             /* value has been set.  It may not be precise.  */
-           if ((numtype & IS_NUMBER_NEG) && (value >= (UV)IV_MIN)) {
-               /* 2s complement assumption for (UV)IV_MIN  */
+            if ((numtype & IS_NUMBER_NEG) && (value >= (UV)IV_MIN)) {
+                /* 2s complement assumption for (UV)IV_MIN  */
                 SvNOK_on(sv); /* Integer is too negative.  */
             } else {
                 SvNOKp_on(sv);
@@ -2741,11 +2662,11 @@ Perl_sv_2nv_flags(pTHX_ SV *const sv, const I32 flags)
                     assert(value != (UV)IV_MIN);
                     SvIV_set(sv, -(IV)value);
                 } else if (value <= (UV)IV_MAX) {
-                   SvIV_set(sv, (IV)value);
-               } else {
-                   SvUV_set(sv, value);
-                   SvIsUV_on(sv);
-               }
+                    SvIV_set(sv, (IV)value);
+                } else {
+                    SvUV_set(sv, value);
+                    SvIsUV_on(sv);
+                }
 
                 if (numtype & IS_NUMBER_NOT_INT) {
                     /* I believe that even if the original PV had decimals,
@@ -2754,7 +2675,7 @@ Perl_sv_2nv_flags(pTHX_ SV *const sv, const I32 flags)
                        flags.  NWC, 2000/11/25 */
                     /* Both already have p flags, so do nothing */
                 } else {
-                   const NV nv = SvNVX(sv);
+                    const NV nv = SvNVX(sv);
                     /* XXX should this spot have NAN_COMPARE_BROKEN, too? */
                     if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
                         if (SvIVX(sv) == I_V(nv)) {
@@ -2762,7 +2683,7 @@ Perl_sv_2nv_flags(pTHX_ SV *const sv, const I32 flags)
                         } else {
                             /* It had no "." so it must be integer.  */
                         }
-                       SvIOK_on(sv);
+                        SvIOK_on(sv);
                     } else {
                         /* between IV_MAX and NV(UV_MAX).
                            Could be slightly > UV_MAX */
@@ -2770,45 +2691,45 @@ Perl_sv_2nv_flags(pTHX_ SV *const sv, const I32 flags)
                         if (numtype & IS_NUMBER_NOT_INT) {
                             /* UV and NV both imprecise.  */
                         } else {
-                           const UV nv_as_uv = U_V(nv);
+                            const UV nv_as_uv = U_V(nv);
 
                             if (value == nv_as_uv && SvUVX(sv) != UV_MAX) {
                                 SvNOK_on(sv);
                             }
-                           SvIOK_on(sv);
+                            SvIOK_on(sv);
                         }
                     }
                 }
             }
         }
-       /* It might be more code efficient to go through the entire logic above
-          and conditionally set with SvNOKp_on() rather than SvNOK(), but it
-          gets complex and potentially buggy, so more programmer efficient
-          to do it this way, by turning off the public flags:  */
-       if (!numtype)
-           SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK);
+        /* It might be more code efficient to go through the entire logic above
+           and conditionally set with SvNOKp_on() rather than SvNOK(), but it
+           gets complex and potentially buggy, so more programmer efficient
+           to do it this way, by turning off the public flags:  */
+        if (!numtype)
+            SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK);
 #endif /* NV_PRESERVES_UV */
     }
-    else  {
-       if (isGV_with_GP(sv)) {
-           glob_2number(MUTABLE_GV(sv));
-           return 0.0;
-       }
+    else {
+        if (isGV_with_GP(sv)) {
+            glob_2number(MUTABLE_GV(sv));
+            return 0.0;
+        }
 
-       if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
-           report_uninit(sv);
-       assert (SvTYPE(sv) >= SVt_NV);
-       /* Typically the caller expects that sv_any is not NULL now.  */
-       /* XXX Ilya implies that this is a bug in callers that assume this
-          and ideally should be fixed.  */
-       return 0.0;
+        if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
+            report_uninit(sv);
+        assert (SvTYPE(sv) >= SVt_NV);
+        /* Typically the caller expects that sv_any is not NULL now.  */
+        /* XXX Ilya implies that this is a bug in callers that assume this
+           and ideally should be fixed.  */
+        return 0.0;
     }
     CLANG_DIAG_IGNORE_STMT(-Wthread-safety);
     DEBUG_c({
         DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
         STORE_LC_NUMERIC_SET_STANDARD();
-       PerlIO_printf(Perl_debug_log, "0x%" UVxf " 2nv(%" NVgf ")\n",
-                     PTR2UV(sv), SvNVX(sv));
+        PerlIO_printf(Perl_debug_log, "0x%" UVxf " 2nv(%" NVgf ")\n",
+                      PTR2UV(sv), SvNVX(sv));
         RESTORE_LC_NUMERIC();
     });
     CLANG_DIAG_RESTORE_STMT;
@@ -2831,12 +2752,12 @@ Perl_sv_2num(pTHX_ SV *const sv)
     PERL_ARGS_ASSERT_SV_2NUM;
 
     if (!SvROK(sv))
-       return sv;
+        return sv;
     if (SvAMAGIC(sv)) {
-       SV * const tmpsv = AMG_CALLunary(sv, numer_amg);
-       TAINT_IF(tmpsv && SvTAINTED(tmpsv));
-       if (tmpsv && (!SvROK(tmpsv) || (SvRV(tmpsv) != SvRV(sv))))
-           return sv_2num(tmpsv);
+        SV * const tmpsv = AMG_CALLunary(sv, numer_amg);
+        TAINT_IF(tmpsv && SvTAINTED(tmpsv));
+        if (tmpsv && (!SvROK(tmpsv) || (SvRV(tmpsv) != SvRV(sv))))
+            return sv_2num(tmpsv);
     }
     return sv_2mortal(newSVuv(PTR2UV(SvRV(sv))));
 }
@@ -2893,14 +2814,14 @@ S_uiv_2buf(char *const buf, const IV iv, UV uv, const int is_uv, char **const pe
     word_table = (U16*)int2str_table.arr;
 
     if (UNLIKELY(is_uv))
-       sign = 0;
+        sign = 0;
     else if (iv >= 0) {
-       uv = iv;
-       sign = 0;
+        uv = iv;
+        sign = 0;
     } else {
         /* Using 0- here to silence bogus warning from MS VC */
         uv = (UV) (0 - (UV) iv);
-       sign = 1;
+        sign = 1;
     }
 
     while (uv > 99) {
@@ -2967,197 +2888,227 @@ S_infnan_2pv(NV nv, char* buffer, size_t maxlen, char plus) {
 }
 
 /*
-=for apidoc sv_2pv_flags
+=for apidoc      sv_2pv
+=for apidoc_item sv_2pv_flags
+
+These implement the various forms of the L<perlapi/C<SvPV>> macros.
+The macros are the preferred interface.
+
+These return a pointer to the string value of an SV (coercing it to a string if
+necessary), and set C<*lp> to its length in bytes.
 
-Returns a pointer to the string value of an SV, and sets C<*lp> to its length.
-If flags has the C<SV_GMAGIC> bit set, does an C<mg_get()> first.  Coerces C<sv> to a
-string if necessary.  Normally invoked via the C<SvPV_flags> macro.
-C<sv_2pv()> and C<sv_2pv_nomg> usually end up here too.
+The forms differ in that plain C<sv_2pvbyte> always processes 'get' magic; and
+C<sv_2pvbyte_flags> processes 'get' magic if and only if C<flags> contains
+C<SV_GMAGIC>.
+
+=for apidoc Amnh||SV_GMAGIC
 
 =cut
 */
 
 char *
-Perl_sv_2pv_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags)
+Perl_sv_2pv_flags(pTHX_ SV *const sv, STRLEN *const lp, const U32 flags)
 {
     char *s;
+    bool done_gmagic = FALSE;
 
     PERL_ARGS_ASSERT_SV_2PV_FLAGS;
 
     assert (SvTYPE(sv) != SVt_PVAV && SvTYPE(sv) != SVt_PVHV
-        && SvTYPE(sv) != SVt_PVFM);
-    if (SvGMAGICAL(sv) && (flags & SV_GMAGIC))
-       mg_get(sv);
+         && SvTYPE(sv) != SVt_PVFM);
+    if (SvGMAGICAL(sv) && (flags & SV_GMAGIC)) {
+        mg_get(sv);
+        done_gmagic = TRUE;
+    }
+
     if (SvROK(sv)) {
-       if (SvAMAGIC(sv)) {
-           SV *tmpstr;
-           if (flags & SV_SKIP_OVERLOAD)
-               return NULL;
-           tmpstr = AMG_CALLunary(sv, string_amg);
-           TAINT_IF(tmpstr && SvTAINTED(tmpstr));
-           if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
-               /* Unwrap this:  */
-               /* char *pv = lp ? SvPV(tmpstr, *lp) : SvPV_nolen(tmpstr);
-                */
-
-               char *pv;
-               if ((SvFLAGS(tmpstr) & (SVf_POK)) == SVf_POK) {
-                   if (flags & SV_CONST_RETURN) {
-                       pv = (char *) SvPVX_const(tmpstr);
-                   } else {
-                       pv = (flags & SV_MUTABLE_RETURN)
-                           ? SvPVX_mutable(tmpstr) : SvPVX(tmpstr);
-                   }
-                   if (lp)
-                       *lp = SvCUR(tmpstr);
-               } else {
-                   pv = sv_2pv_flags(tmpstr, lp, flags);
-               }
-               if (SvUTF8(tmpstr))
-                   SvUTF8_on(sv);
-               else
-                   SvUTF8_off(sv);
-               return pv;
-           }
-       }
-       {
-           STRLEN len;
-           char *retval;
-           char *buffer;
-           SV *const referent = SvRV(sv);
-
-           if (!referent) {
-               len = 7;
-               retval = buffer = savepvn("NULLREF", len);
-           } else if (SvTYPE(referent) == SVt_REGEXP &&
-                      (!(PL_curcop->cop_hints & HINT_NO_AMAGIC) ||
-                       amagic_is_enabled(string_amg))) {
-               REGEXP * const re = (REGEXP *)MUTABLE_PTR(referent);
-
-               assert(re);
-                       
-               /* If the regex is UTF-8 we want the containing scalar to
-                  have an UTF-8 flag too */
-               if (RX_UTF8(re))
-                   SvUTF8_on(sv);
-               else
-                   SvUTF8_off(sv);     
-
-               if (lp)
-                   *lp = RX_WRAPLEN(re);
-               return RX_WRAPPED(re);
-           } else {
-               const char *const typestr = sv_reftype(referent, 0);
-               const STRLEN typelen = strlen(typestr);
-               UV addr = PTR2UV(referent);
-               const char *stashname = NULL;
-               STRLEN stashnamelen = 0; /* hush, gcc */
-               const char *buffer_end;
-
-               if (SvOBJECT(referent)) {
-                   const HEK *const name = HvNAME_HEK(SvSTASH(referent));
-
-                   if (name) {
-                       stashname = HEK_KEY(name);
-                       stashnamelen = HEK_LEN(name);
-
-                       if (HEK_UTF8(name)) {
-                           SvUTF8_on(sv);
-                       } else {
-                           SvUTF8_off(sv);
-                       }
-                   } else {
-                       stashname = "__ANON__";
-                       stashnamelen = 8;
-                   }
-                   len = stashnamelen + 1 /* = */ + typelen + 3 /* (0x */
-                       + 2 * sizeof(UV) + 2 /* )\0 */;
-               } else {
-                   len = typelen + 3 /* (0x */
-                       + 2 * sizeof(UV) + 2 /* )\0 */;
-               }
-
-               Newx(buffer, len, char);
-               buffer_end = retval = buffer + len;
-
-               /* Working backwards  */
-               *--retval = '\0';
-               *--retval = ')';
-               do {
-                   *--retval = PL_hexdigit[addr & 15];
-               } while (addr >>= 4);
-               *--retval = 'x';
-               *--retval = '0';
-               *--retval = '(';
-
-               retval -= typelen;
-               memcpy(retval, typestr, typelen);
-
-               if (stashname) {
-                   *--retval = '=';
-                   retval -= stashnamelen;
-                   memcpy(retval, stashname, stashnamelen);
-               }
-               /* retval may not necessarily have reached the start of the
-                  buffer here.  */
-               assert (retval >= buffer);
-
-               len = buffer_end - retval - 1; /* -1 for that \0  */
-           }
-           if (lp)
-               *lp = len;
-           SAVEFREEPV(buffer);
-           return retval;
-       }
+        if (SvAMAGIC(sv)) {
+            SV *tmpstr;
+            SV *nsv= (SV *)sv;
+            if (flags & SV_SKIP_OVERLOAD)
+                return NULL;
+            if (done_gmagic)
+                nsv = sv_mortalcopy_flags(sv,0);
+            tmpstr = AMG_CALLunary(nsv, string_amg);
+            TAINT_IF(tmpstr && SvTAINTED(tmpstr));
+            if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(nsv)))) {
+                /* Unwrap this:  */
+                /* char *pv = lp ? SvPV(tmpstr, *lp) : SvPV_nolen(tmpstr);
+                 */
+
+                char *pv;
+                if ((SvFLAGS(tmpstr) & (SVf_POK)) == SVf_POK) {
+                    if (flags & SV_CONST_RETURN) {
+                        pv = (char *) SvPVX_const(tmpstr);
+                    } else {
+                        pv = (flags & SV_MUTABLE_RETURN)
+                            ? SvPVX_mutable(tmpstr) : SvPVX(tmpstr);
+                    }
+                    if (lp)
+                        *lp = SvCUR(tmpstr);
+                } else {
+                    pv = sv_2pv_flags(tmpstr, lp, flags);
+                }
+                if (SvUTF8(tmpstr))
+                    SvUTF8_on(sv);
+                else
+                    SvUTF8_off(sv);
+                return pv;
+            }
+        }
+        {
+            STRLEN len;
+            char *retval;
+            char *buffer;
+            SV *const referent = SvRV(sv);
+
+            if (!referent) {
+                len = 7;
+                retval = buffer = savepvn("NULLREF", len);
+            } else if (SvTYPE(referent) == SVt_REGEXP &&
+                       (!(PL_curcop->cop_hints & HINT_NO_AMAGIC) ||
+                        amagic_is_enabled(string_amg))) {
+                REGEXP * const re = (REGEXP *)MUTABLE_PTR(referent);
+
+                assert(re);
+
+                /* If the regex is UTF-8 we want the containing scalar to
+                   have an UTF-8 flag too */
+                if (RX_UTF8(re))
+                    SvUTF8_on(sv);
+                else
+                    SvUTF8_off(sv);
+
+                if (lp)
+                    *lp = RX_WRAPLEN(re);
+
+                return RX_WRAPPED(re);
+            } else {
+                const char *const typestring = sv_reftype(referent, 0);
+                const STRLEN typelen = strlen(typestring);
+                UV addr = PTR2UV(referent);
+                const char *stashname = NULL;
+                STRLEN stashnamelen = 0; /* hush, gcc */
+                const char *buffer_end;
+
+                if (SvOBJECT(referent)) {
+                    const HEK *const name = HvNAME_HEK(SvSTASH(referent));
+
+                    if (name) {
+                        stashname = HEK_KEY(name);
+                        stashnamelen = HEK_LEN(name);
+
+                        if (HEK_UTF8(name)) {
+                            SvUTF8_on(sv);
+                        } else {
+                            SvUTF8_off(sv);
+                        }
+                    } else {
+                        stashname = "__ANON__";
+                        stashnamelen = 8;
+                    }
+                    len = stashnamelen + 1 /* = */ + typelen + 3 /* (0x */
+                        + 2 * sizeof(UV) + 2 /* )\0 */;
+                } else {
+                    len = typelen + 3 /* (0x */
+                        + 2 * sizeof(UV) + 2 /* )\0 */;
+                }
+
+                Newx(buffer, len, char);
+                buffer_end = retval = buffer + len;
+
+                /* Working backwards  */
+                *--retval = '\0';
+                *--retval = ')';
+                do {
+                    *--retval = PL_hexdigit[addr & 15];
+                } while (addr >>= 4);
+                *--retval = 'x';
+                *--retval = '0';
+                *--retval = '(';
+
+                retval -= typelen;
+                memcpy(retval, typestring, typelen);
+
+                if (stashname) {
+                    *--retval = '=';
+                    retval -= stashnamelen;
+                    memcpy(retval, stashname, stashnamelen);
+                }
+                /* retval may not necessarily have reached the start of the
+                   buffer here.  */
+                assert (retval >= buffer);
+
+                len = buffer_end - retval - 1; /* -1 for that \0  */
+            }
+            if (lp)
+                *lp = len;
+            SAVEFREEPV(buffer);
+            return retval;
+        }
     }
 
     if (SvPOKp(sv)) {
-       if (lp)
-           *lp = SvCUR(sv);
-       if (flags & SV_MUTABLE_RETURN)
-           return SvPVX_mutable(sv);
-       if (flags & SV_CONST_RETURN)
-           return (char *)SvPVX_const(sv);
-       return SvPVX(sv);
+        if (lp)
+            *lp = SvCUR(sv);
+        if (flags & SV_MUTABLE_RETURN)
+            return SvPVX_mutable(sv);
+        if (flags & SV_CONST_RETURN)
+            return (char *)SvPVX_const(sv);
+        return SvPVX(sv);
     }
 
     if (SvIOK(sv)) {
-       /* I'm assuming that if both IV and NV are equally valid then
-          converting the IV is going to be more efficient */
-       const U32 isUIOK = SvIsUV(sv);
+        /* I'm assuming that if both IV and NV are equally valid then
+           converting the IV is going to be more efficient */
+        const U32 isUIOK = SvIsUV(sv);
         /* The purpose of this union is to ensure that arr is aligned on
            a 2 byte boundary, because that is what uiv_2buf() requires */
         union {
             char arr[TYPE_CHARS(UV)];
             U16 dummy;
         } buf;
-       char *ebuf, *ptr;
-       STRLEN len;
+        char *ebuf, *ptr;
+        STRLEN len;
 
-       if (SvTYPE(sv) < SVt_PVIV)
-           sv_upgrade(sv, SVt_PVIV);
+        if (SvTYPE(sv) < SVt_PVIV)
+            sv_upgrade(sv, SVt_PVIV);
         ptr = uiv_2buf(buf.arr, SvIVX(sv), SvUVX(sv), isUIOK, &ebuf);
-       len = ebuf - ptr;
-       /* inlined from sv_setpvn */
-       s = SvGROW_mutable(sv, len + 1);
-       Move(ptr, s, len, char);
-       s += len;
-       *s = '\0';
-        SvPOK_on(sv);
+        len = ebuf - ptr;
+        /* inlined from sv_setpvn */
+        s = SvGROW_mutable(sv, len + 1);
+        Move(ptr, s, len, char);
+        s += len;
+        *s = '\0';
+        /* We used to call SvPOK_on(). Whilst this is fine for (most) Perl code,
+           it means that after this stringification is cached, there is no way
+           to distinguish between values originally assigned as $a = 42; and
+           $a = "42"; (or results of string operators vs numeric operators)
+           where the value has subsequently been used in the other sense
+           and had a value cached.
+           This (somewhat) hack means that we retain the cached stringification,
+           but don't set SVf_POK. Hence if a value is SVf_IOK|SVf_POK then it
+           originated as "42", whereas if it's SVf_IOK then it originated as 42.
+           (ignore SVp_IOK and SVp_POK)
+           The SvPV macros are now updated to recognise this specific case
+           (and that there isn't overloading or magic that could alter the
+           cached value) and so return the cached value immediately without
+           re-entering this function, getting back here to this block of code,
+           and repeating the same conversion. */
+        SvPOKp_on(sv);
     }
     else if (SvNOK(sv)) {
-       if (SvTYPE(sv) < SVt_PVNV)
-           sv_upgrade(sv, SVt_PVNV);
-       if (SvNVX(sv) == 0.0
+        if (SvTYPE(sv) < SVt_PVNV)
+            sv_upgrade(sv, SVt_PVNV);
+        if (SvNVX(sv) == 0.0
 #if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
-           && !Perl_isnan(SvNVX(sv))
+            && !Perl_isnan(SvNVX(sv))
 #endif
-       ) {
-           s = SvGROW_mutable(sv, 2);
-           *s++ = '0';
-           *s = '\0';
-       } else {
+        ) {
+            s = SvGROW_mutable(sv, 2);
+            *s++ = '0';
+            *s = '\0';
+        } else {
             STRLEN len;
             STRLEN size = 5; /* "-Inf\0" */
 
@@ -3165,7 +3116,7 @@ Perl_sv_2pv_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags)
             len = S_infnan_2pv(SvNVX(sv), s, size, 0);
             if (len > 0) {
                 s += len;
-                SvPOK_on(sv);
+                SvPOKp_on(sv);
             }
             else {
                 /* some Xenix systems wipe out errno here */
@@ -3185,14 +3136,14 @@ Perl_sv_2pv_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags)
 #ifndef USE_LOCALE_NUMERIC
                 SNPRINTF_G(SvNVX(sv), s, SvLEN(sv), NV_DIG);
 
-                SvPOK_on(sv);
+                SvPOKp_on(sv);
 #else
                 {
                     bool local_radix;
                     DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
                     STORE_LC_NUMERIC_SET_TO_NEEDED();
 
-                    local_radix = _NOT_IN_NUMERIC_STANDARD;
+                    local_radix = NOT_IN_NUMERIC_STANDARD_;
                     if (local_radix && SvCUR(PL_numeric_radix_sv) > 1) {
                         size += SvCUR(PL_numeric_radix_sv) - 1;
                         s = SvGROW_mutable(sv, size);
@@ -3220,70 +3171,67 @@ Perl_sv_2pv_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags)
                 RESTORE_ERRNO;
             }
             while (*s) s++;
-       }
+        }
     }
     else if (isGV_with_GP(sv)) {
-       GV *const gv = MUTABLE_GV(sv);
-       SV *const buffer = sv_newmortal();
+        GV *const gv = MUTABLE_GV(sv);
+        SV *const buffer = sv_newmortal();
 
-       gv_efullname3(buffer, gv, "*");
+        gv_efullname3(buffer, gv, "*");
 
-       assert(SvPOK(buffer));
-       if (SvUTF8(buffer))
-           SvUTF8_on(sv);
+        assert(SvPOK(buffer));
+        if (SvUTF8(buffer))
+            SvUTF8_on(sv);
         else
             SvUTF8_off(sv);
-       if (lp)
-           *lp = SvCUR(buffer);
-       return SvPVX(buffer);
+        if (lp)
+            *lp = SvCUR(buffer);
+        return SvPVX(buffer);
     }
     else {
-       if (lp)
-           *lp = 0;
-       if (flags & SV_UNDEF_RETURNS_NULL)
-           return NULL;
-       if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
-           report_uninit(sv);
-       /* Typically the caller expects that sv_any is not NULL now.  */
-       if (!SvREADONLY(sv) && SvTYPE(sv) < SVt_PV)
-           sv_upgrade(sv, SVt_PV);
-       return (char *)"";
+        if (lp)
+            *lp = 0;
+        if (flags & SV_UNDEF_RETURNS_NULL)
+            return NULL;
+        if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
+            report_uninit(sv);
+        /* Typically the caller expects that sv_any is not NULL now.  */
+        if (!SvREADONLY(sv) && SvTYPE(sv) < SVt_PV)
+            sv_upgrade(sv, SVt_PV);
+        return (char *)"";
     }
 
     {
-       const STRLEN len = s - SvPVX_const(sv);
-       if (lp) 
-           *lp = len;
-       SvCUR_set(sv, len);
+        const STRLEN len = s - SvPVX_const(sv);
+        if (lp)
+            *lp = len;
+        SvCUR_set(sv, len);
     }
     DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%" UVxf " 2pv(%s)\n",
-                         PTR2UV(sv),SvPVX_const(sv)));
+                          PTR2UV(sv),SvPVX_const(sv)));
     if (flags & SV_CONST_RETURN)
-       return (char *)SvPVX_const(sv);
+        return (char *)SvPVX_const(sv);
     if (flags & SV_MUTABLE_RETURN)
-       return SvPVX_mutable(sv);
+        return SvPVX_mutable(sv);
     return SvPVX(sv);
 }
 
 /*
 =for apidoc sv_copypv
+=for apidoc_item sv_copypv_flags
+=for apidoc_item sv_copypv_nomg
 
-Copies a stringified representation of the source SV into the
-destination SV.  Automatically performs any necessary C<mg_get> and
-coercion of numeric values into strings.  Guaranteed to preserve
-C<UTF8> flag even from overloaded objects.  Similar in nature to
-C<sv_2pv[_flags]> but operates directly on an SV instead of just the
-string.  Mostly uses C<sv_2pv_flags> to do its work, except when that
-would lose the UTF-8'ness of the PV.
-
-=for apidoc sv_copypv_nomg
-
-Like C<sv_copypv>, but doesn't invoke get magic first.
-
-=for apidoc sv_copypv_flags
+These copy a stringified representation of the source SV into the
+destination SV.  They automatically perform coercion of numeric values into
+strings.  Guaranteed to preserve the C<UTF8> flag even from overloaded objects.
+Similar in nature to C<sv_2pv[_flags]> but they operate directly on an SV
+instead of just the string.  Mostly they use L</C<sv_2pv_flags>> to
+do the work, except when that would lose the UTF-8'ness of the PV.
 
-Implementation of C<sv_copypv> and C<sv_copypv_nomg>.  Calls get magic iff flags
-has the C<SV_GMAGIC> bit set.
+The three forms differ only in whether or not they perform 'get magic' on
+C<sv>.  C<sv_copypv_nomg> skips 'get magic'; C<sv_copypv> performs it; and
+C<sv_copypv_flags> either performs it (if the C<SV_GMAGIC> bit is set in
+C<flags>) or doesn't (if that bit is cleared).
 
 =cut
 */
@@ -3299,19 +3247,28 @@ Perl_sv_copypv_flags(pTHX_ SV *const dsv, SV *const ssv, const I32 flags)
     s = SvPV_flags_const(ssv,len,(flags & SV_GMAGIC));
     sv_setpvn(dsv,s,len);
     if (SvUTF8(ssv))
-       SvUTF8_on(dsv);
+        SvUTF8_on(dsv);
     else
-       SvUTF8_off(dsv);
+        SvUTF8_off(dsv);
 }
 
 /*
-=for apidoc sv_2pvbyte
+=for apidoc      sv_2pvbyte
+=for apidoc_item sv_2pvbyte_flags
 
-Return a pointer to the byte-encoded representation of the SV, and set C<*lp>
-to its length.  May cause the SV to be downgraded from UTF-8 as a
-side-effect.
+These implement the various forms of the L<perlapi/C<SvPVbyte>> macros.
+The macros are the preferred interface.
 
-Usually accessed via the C<SvPVbyte> macro.
+These return a pointer to the byte-encoded representation of the SV, and set
+C<*lp> to its length.  If the SV is marked as being encoded as UTF-8, it will
+be downgraded, if possible, to a byte string.  If the SV cannot be downgraded,
+they croak.
+
+The forms differ in that plain C<sv_2pvbyte> always processes 'get' magic; and
+C<sv_2pvbyte_flags> processes 'get' magic if and only if C<flags> contains
+C<SV_GMAGIC>.
+
+=for apidoc Amnh||SV_GMAGIC
 
 =cut
 */
@@ -3325,21 +3282,28 @@ Perl_sv_2pvbyte_flags(pTHX_ SV *sv, STRLEN *const lp, const U32 flags)
         mg_get(sv);
     if (((SvREADONLY(sv) || SvFAKE(sv)) && !SvIsCOW(sv))
      || isGV_with_GP(sv) || SvROK(sv)) {
-       SV *sv2 = sv_newmortal();
-       sv_copypv_nomg(sv2,sv);
-       sv = sv2;
+        SV *sv2 = sv_newmortal();
+        sv_copypv_nomg(sv2,sv);
+        sv = sv2;
     }
     sv_utf8_downgrade_nomg(sv,0);
     return lp ? SvPV_nomg(sv,*lp) : SvPV_nomg_nolen(sv);
 }
 
 /*
-=for apidoc sv_2pvutf8
+=for apidoc      sv_2pvutf8
+=for apidoc_item sv_2pvutf8_flags
+
+These implement the various forms of the L<perlapi/C<SvPVutf8>> macros.
+The macros are the preferred interface.
 
-Return a pointer to the UTF-8-encoded representation of the SV, and set C<*lp>
-to its length.  May cause the SV to be upgraded to UTF-8 as a side-effect.
+These return a pointer to the UTF-8-encoded representation of the SV, and set
+C<*lp> to its length in bytes.  They may cause the SV to be upgraded to UTF-8
+as a side-effect.
 
-Usually accessed via the C<SvPVutf8> macro.
+The forms differ in that plain C<sv_2pvutf8> always processes 'get' magic; and
+C<sv_2pvutf8_flags> processes 'get' magic if and only if C<flags> contains
+C<SV_GMAGIC>.
 
 =cut
 */
@@ -3388,11 +3352,11 @@ Perl_sv_2bool_flags(pTHX_ SV *sv, I32 flags)
     if(flags & SV_GMAGIC) SvGETMAGIC(sv);
 
     if (!SvOK(sv))
-       return 0;
+        return 0;
     if (SvROK(sv)) {
-       if (SvAMAGIC(sv)) {
-           SV * const tmpsv = AMG_CALLunary(sv, bool__amg);
-           if (tmpsv && (!SvROK(tmpsv) || (SvRV(tmpsv) != SvRV(sv)))) {
+        if (SvAMAGIC(sv)) {
+            SV * const tmpsv = AMG_CALLunary(sv, bool__amg);
+            if (tmpsv && (!SvROK(tmpsv) || (SvRV(tmpsv) != SvRV(sv)))) {
                 bool svb;
                 sv = tmpsv;
                 if(SvGMAGICAL(sv)) {
@@ -3416,64 +3380,52 @@ Perl_sv_2bool_flags(pTHX_ SV *sv, I32 flags)
                 }
                 return cBOOL(svb);
             }
-       }
-       assert(SvRV(sv));
-       return TRUE;
+        }
+        assert(SvRV(sv));
+        return TRUE;
     }
     if (isREGEXP(sv))
-       return
-         RX_WRAPLEN(sv) > 1 || (RX_WRAPLEN(sv) && *RX_WRAPPED(sv) != '0');
+        return
+          RX_WRAPLEN(sv) > 1 || (RX_WRAPLEN(sv) && *RX_WRAPPED(sv) != '0');
 
     if (SvNOK(sv) && !SvPOK(sv))
         return SvNVX(sv) != 0.0;
 
-    return SvTRUE_common(sv, isGV_with_GP(sv) ? 1 : 0);
+    return SvTRUE_common(sv, 0);
 }
 
 /*
 =for apidoc sv_utf8_upgrade
-
-Converts the PV of an SV to its UTF-8-encoded form.
-Forces the SV to string form if it is not already.
-Will C<mg_get> on C<sv> if appropriate.
-Always sets the C<SvUTF8> flag to avoid future validity checks even
-if the whole string is the same in UTF-8 as not.
-Returns the number of bytes in the converted string
-
-This is not a general purpose byte encoding to Unicode interface:
-use the Encode extension for that.
-
-=for apidoc sv_utf8_upgrade_nomg
-
-Like C<sv_utf8_upgrade>, but doesn't do magic on C<sv>.
-
-=for apidoc sv_utf8_upgrade_flags
-
-Converts the PV of an SV to its UTF-8-encoded form.
-Forces the SV to string form if it is not already.
-Always sets the SvUTF8 flag to avoid future validity checks even
-if all the bytes are invariant in UTF-8.
-If C<flags> has C<SV_GMAGIC> bit set,
-will C<mg_get> on C<sv> if appropriate, else not.
+=for apidoc_item sv_utf8_upgrade_flags
+=for apidoc_item sv_utf8_upgrade_flags_grow
+=for apidoc_item sv_utf8_upgrade_nomg
+
+These convert the PV of an SV to its UTF-8-encoded form.
+The SV is forced to string form if it is not already.
+They always set the C<SvUTF8> flag to avoid future validity checks even if the
+whole string is the same in UTF-8 as not.
+They return the number of bytes in the converted string
+
+The forms differ in just two ways.  The main difference is whether or not they
+perform 'get magic' on C<sv>.  C<sv_utf8_upgrade_nomg> skips 'get magic';
+C<sv_utf8_upgrade> performs it; and C<sv_utf8_upgrade_flags> and
+C<sv_utf8_upgrade_flags_grow> either perform it (if the C<SV_GMAGIC> bit is set
+in C<flags>) or don't (if that bit is cleared).
+
+The other difference is that C<sv_utf8_upgrade_flags_grow> has an additional
+parameter, C<extra>, which allows the caller to specify an amount of space to
+be reserved as spare beyond what is needed for the actual conversion.  This is
+used when the caller knows it will soon be needing yet more space, and it is
+more efficient to request space from the system in a single call.
+This form is otherwise identical to C<sv_utf8_upgrade_flags>.
+
+These are not a general purpose byte encoding to Unicode interface: use the
+Encode extension for that.
 
 The C<SV_FORCE_UTF8_UPGRADE> flag is now ignored.
 
-Returns the number of bytes in the converted string.
-
-This is not a general purpose byte encoding to Unicode interface:
-use the Encode extension for that.
-
-=for apidoc sv_utf8_upgrade_flags_grow
-
-Like C<sv_utf8_upgrade_flags>, but has an additional parameter C<extra>, which is
-the number of unused bytes the string of C<sv> is guaranteed to have free after
-it upon return.  This allows the caller to reserve extra space that it intends
-to fill, to avoid extra grows.
-
-C<sv_utf8_upgrade>, C<sv_utf8_upgrade_nomg>, and C<sv_utf8_upgrade_flags>
-are implemented in terms of this function.
-
-Returns the number of bytes in the converted string (not including the spares).
+=for apidoc Amnh||SV_GMAGIC|
+=for apidoc Amnh||SV_FORCE_UTF8_UPGRADE|
 
 =cut
 
@@ -3489,18 +3441,18 @@ Perl_sv_utf8_upgrade_flags_grow(pTHX_ SV *const sv, const I32 flags, STRLEN extr
     PERL_ARGS_ASSERT_SV_UTF8_UPGRADE_FLAGS_GROW;
 
     if (sv == &PL_sv_undef)
-       return 0;
+        return 0;
     if (!SvPOK_nog(sv)) {
-       STRLEN len = 0;
-       if (SvREADONLY(sv) && (SvPOKp(sv) || SvIOKp(sv) || SvNOKp(sv))) {
-           (void) sv_2pv_flags(sv,&len, flags);
-           if (SvUTF8(sv)) {
-               if (extra) SvGROW(sv, SvCUR(sv) + extra);
-               return len;
-           }
-       } else {
-           (void) SvPV_force_flags(sv,len,flags & SV_GMAGIC);
-       }
+        STRLEN len = 0;
+        if (SvREADONLY(sv) && (SvPOKp(sv) || SvIOKp(sv) || SvNOKp(sv))) {
+            (void) sv_2pv_flags(sv,&len, flags);
+            if (SvUTF8(sv)) {
+                if (extra) SvGROW(sv, SvCUR(sv) + extra);
+                return len;
+            }
+        } else {
+            (void) SvPV_force_flags(sv,len,flags & SV_GMAGIC);
+        }
     }
 
     /* SVt_REGEXP's shouldn't be upgraded to UTF8 - they're already
@@ -3509,8 +3461,8 @@ Perl_sv_utf8_upgrade_flags_grow(pTHX_ SV *const sv, const I32 flags, STRLEN extr
      * PVX of a REGEXP should be grown or we should just croak, I don't
      * know - DAPM */
     if (SvUTF8(sv) || isREGEXP(sv)) {
-       if (extra) SvGROW(sv, SvCUR(sv) + extra);
-       return SvCUR(sv);
+        if (extra) SvGROW(sv, SvCUR(sv) + extra);
+        return SvCUR(sv);
     }
 
     if (SvIsCOW(sv)) {
@@ -3521,13 +3473,13 @@ Perl_sv_utf8_upgrade_flags_grow(pTHX_ SV *const sv, const I32 flags, STRLEN extr
         if (extra) SvGROW(sv, extra + 1); /* Make sure is room for a trailing
                                              byte */
     } else { /* Assume Latin-1/EBCDIC */
-       /* This function could be much more efficient if we
-        * had a FLAG in SVs to signal if there are any variant
-        * chars in the PV.  Given that there isn't such a flag
-        * make the loop as fast as possible. */
-       U8 * s = (U8 *) SvPVX_const(sv);
-       U8 *t = s;
-       
+        /* This function could be much more efficient if we
+         * had a FLAG in SVs to signal if there are any variant
+         * chars in the PV.  Given that there isn't such a flag
+         * make the loop as fast as possible. */
+        U8 * s = (U8 *) SvPVX_const(sv);
+        U8 *t = s;
+
         if (is_utf8_invariant_string_loc(s, SvCUR(sv), (const U8 **) &t)) {
 
             /* utf8 conversion not needed because all are invariants.  Mark
@@ -3543,9 +3495,9 @@ Perl_sv_utf8_upgrade_flags_grow(pTHX_ SV *const sv, const I32 flags, STRLEN extr
          *
          * Note that the incoming SV may not have a trailing '\0', as certain
          * code in pp_formline can send us partially built SVs.
-        *
-        * There are two main ways to convert.  One is to create a new string
-        * and go through the input starting from the beginning, appending each
+         *
+         * There are two main ways to convert.  One is to create a new string
+         * and go through the input starting from the beginning, appending each
          * converted value onto the new string as we go along.  Going this
          * route, it's probably best to initially allocate enough space in the
          * string rather than possibly running out of space and having to
@@ -3555,13 +3507,13 @@ Perl_sv_utf8_upgrade_flags_grow(pTHX_ SV *const sv, const I32 flags, STRLEN extr
          * space, one could use the worst case scenario, where every remaining
          * byte expands to two under UTF-8, or one could parse it and count
          * exactly how many do expand.
-        *
+         *
          * The other way is to unconditionally parse the remainder of the
          * string to figure out exactly how big the expanded string will be,
          * growing if needed.  Then start at the end of the string and place
          * the character there at the end of the unfilled space in the expanded
          * one, working backwards until reaching 't'.
-        *
+         *
          * The problem with assuming the worst case scenario is that for very
          * long strings, we could allocate much more memory than actually
          * needed, which can create performance problems.  If we have to parse
@@ -3571,7 +3523,7 @@ Perl_sv_utf8_upgrade_flags_grow(pTHX_ SV *const sv, const I32 flags, STRLEN extr
          * ASCII platforms, the second method is used exclusively, eliminating
          * some code that no longer has to be maintained. */
 
-       {
+        {
             /* Count the total number of variants there are.  We can start
              * just beyond the first one, which is known to be at 't' */
             const Size_t invariant_length = t - s;
@@ -3615,21 +3567,21 @@ Perl_sv_utf8_upgrade_flags_grow(pTHX_ SV *const sv, const I32 flags, STRLEN extr
                 e--;
             }
 
-           if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-               /* Update pos. We do it at the end rather than during
-                * the upgrade, to avoid slowing down the common case
-                * (upgrade without pos).
-                * pos can be stored as either bytes or characters.  Since
-                * this was previously a byte string we can just turn off
-                * the bytes flag. */
-               MAGIC * mg = mg_find(sv, PERL_MAGIC_regex_global);
-               if (mg) {
-                   mg->mg_flags &= ~MGf_BYTES;
-               }
-               if ((mg = mg_find(sv, PERL_MAGIC_utf8)))
-                   magic_setutf8(sv,mg); /* clear UTF8 cache */
-           }
-       }
+            if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
+                /* Update pos. We do it at the end rather than during
+                 * the upgrade, to avoid slowing down the common case
+                 * (upgrade without pos).
+                 * pos can be stored as either bytes or characters.  Since
+                 * this was previously a byte string we can just turn off
+                 * the bytes flag. */
+                MAGIC * mg = mg_find(sv, PERL_MAGIC_regex_global);
+                if (mg) {
+                    mg->mg_flags &= ~MGf_BYTES;
+                }
+                if ((mg = mg_find(sv, PERL_MAGIC_utf8)))
+                    magic_setutf8(sv,mg); /* clear UTF8 cache */
+            }
+        }
     }
 
     SvUTF8_on(sv);
@@ -3638,26 +3590,24 @@ Perl_sv_utf8_upgrade_flags_grow(pTHX_ SV *const sv, const I32 flags, STRLEN extr
 
 /*
 =for apidoc sv_utf8_downgrade
+=for apidoc_item sv_utf8_downgrade_flags
+=for apidoc_item sv_utf8_downgrade_nomg
 
-Attempts to convert the PV of an SV from characters to bytes.
-If the PV contains a character that cannot fit
-in a byte, this conversion will fail;
-in this case, either returns false or, if C<fail_ok> is not
-true, croaks.
+These attempt to convert the PV of an SV from characters to bytes.  If the PV
+contains a character that cannot fit in a byte, this conversion will fail; in
+this case, C<FALSE> is returned if C<fail_ok> is true; otherwise they croak.
 
-This is not a general purpose Unicode to byte encoding interface:
+They are not a general purpose Unicode to byte encoding interface:
 use the C<Encode> extension for that.
 
-This function process get magic on C<sv>.
-
-=for apidoc sv_utf8_downgrade_nomg
+They differ only in that:
 
-Like C<sv_utf8_downgrade>, but does not process get magic on C<sv>.
+C<sv_utf8_downgrade> processes 'get' magic on C<sv>.
 
-=for apidoc sv_utf8_downgrade_flags
+C<sv_utf8_downgrade_nomg> does not.
 
-Like C<sv_utf8_downgrade>, but with additional C<flags>.
-If C<flags> has C<SV_GMAGIC> bit set, processes get magic on C<sv>.
+C<sv_utf8_downgrade_flags> has an additional C<flags> parameter in which you can specify
+C<SV_GMAGIC> to process 'get' magic, or leave it cleared to not process 'get' magic.
 
 =cut
 */
@@ -3669,40 +3619,40 @@ Perl_sv_utf8_downgrade_flags(pTHX_ SV *const sv, const bool fail_ok, const U32 f
 
     if (SvPOKp(sv) && SvUTF8(sv)) {
         if (SvCUR(sv)) {
-           U8 *s;
-           STRLEN len;
+            U8 *s;
+            STRLEN len;
             U32 mg_flags = flags & SV_GMAGIC;
 
             if (SvIsCOW(sv)) {
                 S_sv_uncow(aTHX_ sv, 0);
             }
-           if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-               /* update pos */
-               MAGIC * mg = mg_find(sv, PERL_MAGIC_regex_global);
-               if (mg && mg->mg_len > 0 && mg->mg_flags & MGf_BYTES) {
-                       mg->mg_len = sv_pos_b2u_flags(sv, mg->mg_len,
-                                               mg_flags|SV_CONST_RETURN);
-                       mg_flags = 0; /* sv_pos_b2u does get magic */
-               }
-               if ((mg = mg_find(sv, PERL_MAGIC_utf8)))
-                   magic_setutf8(sv,mg); /* clear UTF8 cache */
-
-           }
-           s = (U8 *) SvPV_flags(sv, len, mg_flags);
-
-           if (!utf8_to_bytes(s, &len)) {
-               if (fail_ok)
-                   return FALSE;
-               else {
-                   if (PL_op)
-                       Perl_croak(aTHX_ "Wide character in %s",
-                                  OP_DESC(PL_op));
-                   else
-                       Perl_croak(aTHX_ "Wide character");
-               }
-           }
-           SvCUR_set(sv, len);
-       }
+            if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
+                /* update pos */
+                MAGIC * mg = mg_find(sv, PERL_MAGIC_regex_global);
+                if (mg && mg->mg_len > 0 && mg->mg_flags & MGf_BYTES) {
+                        mg->mg_len = sv_pos_b2u_flags(sv, mg->mg_len,
+                                                mg_flags|SV_CONST_RETURN);
+                        mg_flags = 0; /* sv_pos_b2u does get magic */
+                }
+                if ((mg = mg_find(sv, PERL_MAGIC_utf8)))
+                    magic_setutf8(sv,mg); /* clear UTF8 cache */
+
+            }
+            s = (U8 *) SvPV_flags(sv, len, mg_flags);
+
+            if (!utf8_to_bytes(s, &len)) {
+                if (fail_ok)
+                    return FALSE;
+                else {
+                    if (PL_op)
+                        Perl_croak(aTHX_ "Wide character in %s",
+                                   OP_DESC(PL_op));
+                    else
+                        Perl_croak(aTHX_ "Wide character");
+                }
+            }
+            SvCUR_set(sv, len);
+        }
     }
     SvUTF8_off(sv);
     return TRUE;
@@ -3723,7 +3673,7 @@ Perl_sv_utf8_encode(pTHX_ SV *const sv)
     PERL_ARGS_ASSERT_SV_UTF8_ENCODE;
 
     if (SvREADONLY(sv)) {
-       sv_force_normal_flags(sv, 0);
+        sv_force_normal_flags(sv, 0);
     }
     (void) sv_utf8_upgrade(sv);
     SvUTF8_off(sv);
@@ -3749,11 +3699,11 @@ Perl_sv_utf8_decode(pTHX_ SV *const sv)
     if (SvPOKp(sv)) {
         const U8 *start, *c, *first_variant;
 
-       /* The octets may have got themselves encoded - get them back as
-        * bytes
-        */
-       if (!sv_utf8_downgrade(sv, TRUE))
-           return FALSE;
+        /* The octets may have got themselves encoded - get them back as
+         * bytes
+         */
+        if (!sv_utf8_downgrade(sv, TRUE))
+            return FALSE;
 
         /* it is actually just a matter of turning the utf8 flag on, but
          * we want to make sure everything inside is valid utf8 first.
@@ -3764,62 +3714,59 @@ Perl_sv_utf8_decode(pTHX_ SV *const sv)
                 return FALSE;
             SvUTF8_on(sv);
         }
-       if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-           /* XXX Is this dead code?  XS_utf8_decode calls SvSETMAGIC
-                  after this, clearing pos.  Does anything on CPAN
-                  need this? */
-           /* adjust pos to the start of a UTF8 char sequence */
-           MAGIC * mg = mg_find(sv, PERL_MAGIC_regex_global);
-           if (mg) {
-               I32 pos = mg->mg_len;
-               if (pos > 0) {
-                   for (c = start + pos; c > start; c--) {
-                       if (UTF8_IS_START(*c))
-                           break;
-                   }
-                   mg->mg_len  = c - start;
-               }
-           }
-           if ((mg = mg_find(sv, PERL_MAGIC_utf8)))
-               magic_setutf8(sv,mg); /* clear UTF8 cache */
-       }
+        if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
+            /* XXX Is this dead code?  XS_utf8_decode calls SvSETMAGIC
+                   after this, clearing pos.  Does anything on CPAN
+                   need this? */
+            /* adjust pos to the start of a UTF8 char sequence */
+            MAGIC * mg = mg_find(sv, PERL_MAGIC_regex_global);
+            if (mg) {
+                SSize_t pos = mg->mg_len;
+                if (pos > 0) {
+                    for (c = start + pos; c > start; c--) {
+                        if (UTF8_IS_START(*c))
+                            break;
+                    }
+                    mg->mg_len  = c - start;
+                }
+            }
+            if ((mg = mg_find(sv, PERL_MAGIC_utf8)))
+                magic_setutf8(sv,mg); /* clear UTF8 cache */
+        }
     }
     return TRUE;
 }
 
 /*
 =for apidoc sv_setsv
+=for apidoc_item sv_setsv_flags
+=for apidoc_item sv_setsv_mg
+=for apidoc_item sv_setsv_nomg
+
+These copy the contents of the source SV C<ssv> into the destination SV C<dsv>.
+C<ssv> may be destroyed if it is mortal, so don't use these functions if
+the source SV needs to be reused.
+Loosely speaking, they perform a copy-by-value, obliterating any previous
+content of the destination.
 
-Copies the contents of the source SV C<ssv> into the destination SV
-C<dsv>.  The source SV may be destroyed if it is mortal, so don't use this
-function if the source SV needs to be reused.  Does not handle 'set' magic on
-destination SV.  Calls 'get' magic on source SV.  Loosely speaking, it
-performs a copy-by-value, obliterating any previous content of the
-destination.
+They differ only in that:
 
-You probably want to use one of the assortment of wrappers, such as
-C<SvSetSV>, C<SvSetSV_nosteal>, C<SvSetMagicSV> and
-C<SvSetMagicSV_nosteal>.
+C<sv_setsv> calls 'get' magic on C<ssv>, but skips 'set' magic on C<dsv>.
 
-=for apidoc sv_setsv_flags
+C<sv_setsv_mg> calls both 'get' magic on C<ssv> and 'set' magic on C<dsv>.
 
-Copies the contents of the source SV C<ssv> into the destination SV
-C<dsv>.  The source SV may be destroyed if it is mortal, so don't use this
-function if the source SV needs to be reused.  Does not handle 'set' magic.
-Loosely speaking, it performs a copy-by-value, obliterating any previous
-content of the destination.
-If the C<flags> parameter has the C<SV_GMAGIC> bit set, will C<mg_get> on
-C<ssv> if appropriate, else not.  If the C<flags>
-parameter has the C<SV_NOSTEAL> bit set then the
-buffers of temps will not be stolen.  C<sv_setsv>
-and C<sv_setsv_nomg> are implemented in terms of this function.
+C<sv_setsv_nomg> skips all magic.
 
-You probably want to use one of the assortment of wrappers, such as
-C<SvSetSV>, C<SvSetSV_nosteal>, C<SvSetMagicSV> and
-C<SvSetMagicSV_nosteal>.
+C<sv_setsv_flags> has a C<flags> parameter which you can use to specify any
+combination of magic handling, and also you can specify C<SV_NOSTEAL> so that
+the buffers of temps will not be stolen.
 
-This is the primary function for copying scalars, and most other
-copy-ish functions and macros use this underneath.
+You probably want to instead use one of the assortment of wrappers, such as
+C<L</SvSetSV>>, C<L</SvSetSV_nosteal>>, C<L</SvSetMagicSV>> and
+C<L</SvSetMagicSV_nosteal>>.
+
+C<sv_setsv_flags> is the primary function for copying scalars, and most other
+copy-ish functions and macros use it underneath.
 
 =for apidoc Amnh||SV_NOSTEAL
 
@@ -3827,46 +3774,46 @@ copy-ish functions and macros use this underneath.
 */
 
 static void
-S_glob_assign_glob(pTHX_ SV *const dstr, SV *const sstr, const int dtype)
+S_glob_assign_glob(pTHX_ SV *const dsv, SV *const ssv, const int dtype)
 {
     I32 mro_changes = 0; /* 1 = method, 2 = isa, 3 = recursive isa */
     HV *old_stash = NULL;
 
     PERL_ARGS_ASSERT_GLOB_ASSIGN_GLOB;
 
-    if (dtype != SVt_PVGV && !isGV_with_GP(dstr)) {
-       const char * const name = GvNAME(sstr);
-       const STRLEN len = GvNAMELEN(sstr);
-       {
-           if (dtype >= SVt_PV) {
-               SvPV_free(dstr);
-               SvPV_set(dstr, 0);
-               SvLEN_set(dstr, 0);
-               SvCUR_set(dstr, 0);
-           }
-           SvUPGRADE(dstr, SVt_PVGV);
-           (void)SvOK_off(dstr);
-           isGV_with_GP_on(dstr);
-       }
-       GvSTASH(dstr) = GvSTASH(sstr);
-       if (GvSTASH(dstr))
-           Perl_sv_add_backref(aTHX_ MUTABLE_SV(GvSTASH(dstr)), dstr);
-        gv_name_set(MUTABLE_GV(dstr), name, len,
-                        GV_ADD | (GvNAMEUTF8(sstr) ? SVf_UTF8 : 0 ));
-       SvFAKE_on(dstr);        /* can coerce to non-glob */
-    }
-
-    if(GvGP(MUTABLE_GV(sstr))) {
+    if (dtype != SVt_PVGV && !isGV_with_GP(dsv)) {
+        const char * const name = GvNAME(ssv);
+        const STRLEN len = GvNAMELEN(ssv);
+        {
+            if (dtype >= SVt_PV) {
+                SvPV_free(dsv);
+                SvPV_set(dsv, 0);
+                SvLEN_set(dsv, 0);
+                SvCUR_set(dsv, 0);
+            }
+            SvUPGRADE(dsv, SVt_PVGV);
+            (void)SvOK_off(dsv);
+            isGV_with_GP_on(dsv);
+        }
+        GvSTASH(dsv) = GvSTASH(ssv);
+        if (GvSTASH(dsv))
+            Perl_sv_add_backref(aTHX_ MUTABLE_SV(GvSTASH(dsv)), dsv);
+        gv_name_set(MUTABLE_GV(dsv), name, len,
+                        GV_ADD | (GvNAMEUTF8(ssv) ? SVf_UTF8 : 0 ));
+        SvFAKE_on(dsv);        /* can coerce to non-glob */
+    }
+
+    if(GvGP(MUTABLE_GV(ssv))) {
         /* If source has method cache entry, clear it */
-        if(GvCVGEN(sstr)) {
-            SvREFCNT_dec(GvCV(sstr));
-            GvCV_set(sstr, NULL);
-            GvCVGEN(sstr) = 0;
+        if(GvCVGEN(ssv)) {
+            SvREFCNT_dec(GvCV(ssv));
+            GvCV_set(ssv, NULL);
+            GvCVGEN(ssv) = 0;
         }
         /* If source has a real method, then a method is
            going to change */
         else if(
-         GvCV((const GV *)sstr) && GvSTASH(dstr) && HvENAME(GvSTASH(dstr))
+         GvCV((const GV *)ssv) && GvSTASH(dsv) && HvHasENAME(GvSTASH(dsv))
         ) {
             mro_changes = 1;
         }
@@ -3874,8 +3821,8 @@ S_glob_assign_glob(pTHX_ SV *const dstr, SV *const sstr, const int dtype)
 
     /* If dest already had a real method, that's a change as well */
     if(
-        !mro_changes && GvGP(MUTABLE_GV(dstr)) && GvCVu((const GV *)dstr)
-     && GvSTASH(dstr) && HvENAME(GvSTASH(dstr))
+        !mro_changes && GvGP(MUTABLE_GV(dsv)) && GvCVu((const GV *)dsv)
+     && GvSTASH(dsv) && HvHasENAME(GvSTASH(dsv))
     ) {
         mro_changes = 1;
     }
@@ -3883,12 +3830,12 @@ S_glob_assign_glob(pTHX_ SV *const dstr, SV *const sstr, const int dtype)
     /* We don't need to check the name of the destination if it was not a
        glob to begin with. */
     if(dtype == SVt_PVGV) {
-        const char * const name = GvNAME((const GV *)dstr);
-        const STRLEN len = GvNAMELEN(dstr);
+        const char * const name = GvNAME((const GV *)dsv);
+        const STRLEN len = GvNAMELEN(dsv);
         if(memEQs(name, len, "ISA")
          /* The stash may have been detached from the symbol table, so
             check its name. */
-         && GvSTASH(dstr) && HvENAME(GvSTASH(dstr))
+         && GvSTASH(dsv) && HvHasENAME(GvSTASH(dsv))
         )
             mro_changes = 2;
         else {
@@ -3898,7 +3845,7 @@ S_glob_assign_glob(pTHX_ SV *const dstr, SV *const sstr, const int dtype)
 
                 /* Set aside the old stash, so we can reset isa caches on
                    its subclasses. */
-                if((old_stash = GvHV(dstr)))
+                if((old_stash = GvHV(dsv)))
                     /* Make sure we do not lose it early. */
                     SvREFCNT_inc_simple_void_NN(
                      sv_2mortal((SV *)old_stash)
@@ -3906,69 +3853,71 @@ S_glob_assign_glob(pTHX_ SV *const dstr, SV *const sstr, const int dtype)
             }
         }
 
-        SvREFCNT_inc_simple_void_NN(sv_2mortal(dstr));
+        SvREFCNT_inc_simple_void_NN(sv_2mortal(dsv));
     }
 
-    /* freeing dstr's GP might free sstr (e.g. *x = $x),
+    /* freeing dsv's GP might free ssv (e.g. *x = $x),
      * so temporarily protect it */
     ENTER;
-    SAVEFREESV(SvREFCNT_inc_simple_NN(sstr));
-    gp_free(MUTABLE_GV(dstr));
-    GvINTRO_off(dstr);         /* one-shot flag */
-    GvGP_set(dstr, gp_ref(GvGP(sstr)));
+    SAVEFREESV(SvREFCNT_inc_simple_NN(ssv));
+    gp_free(MUTABLE_GV(dsv));
+    GvINTRO_off(dsv);          /* one-shot flag */
+    GvGP_set(dsv, gp_ref(GvGP(ssv)));
     LEAVE;
 
-    if (SvTAINTED(sstr))
-       SvTAINT(dstr);
-    if (GvIMPORTED(dstr) != GVf_IMPORTED
-       && CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
-       {
-           GvIMPORTED_on(dstr);
-       }
-    GvMULTI_on(dstr);
+    if (SvTAINTED(ssv))
+        SvTAINT(dsv);
+    if (GvIMPORTED(dsv) != GVf_IMPORTED
+        && CopSTASH_ne(PL_curcop, GvSTASH(dsv)))
+        {
+            GvIMPORTED_on(dsv);
+        }
+    GvMULTI_on(dsv);
     if(mro_changes == 2) {
-      if (GvAV((const GV *)sstr)) {
-       MAGIC *mg;
-       SV * const sref = (SV *)GvAV((const GV *)dstr);
-       if (SvSMAGICAL(sref) && (mg = mg_find(sref, PERL_MAGIC_isa))) {
-           if (SvTYPE(mg->mg_obj) != SVt_PVAV) {
-               AV * const ary = newAV();
-               av_push(ary, mg->mg_obj); /* takes the refcount */
-               mg->mg_obj = (SV *)ary;
-           }
-           av_push((AV *)mg->mg_obj, SvREFCNT_inc_simple_NN(dstr));
-       }
-       else sv_magic(sref, dstr, PERL_MAGIC_isa, NULL, 0);
+      if (GvAV((const GV *)ssv)) {
+        MAGIC *mg;
+        SV * const sref = (SV *)GvAV((const GV *)dsv);
+        if (SvSMAGICAL(sref) && (mg = mg_find(sref, PERL_MAGIC_isa))) {
+            if (SvTYPE(mg->mg_obj) != SVt_PVAV) {
+                AV * const ary = newAV_alloc_x(2);
+                av_push_simple(ary, mg->mg_obj); /* takes the refcount */
+                av_push_simple(ary, SvREFCNT_inc_simple_NN(dsv));
+                mg->mg_obj = (SV *)ary;
+            } else {
+                av_push((AV *)mg->mg_obj, SvREFCNT_inc_simple_NN(dsv));
+            }
+        }
+        else sv_magic(sref, dsv, PERL_MAGIC_isa, NULL, 0);
       }
-      mro_isa_changed_in(GvSTASH(dstr));
+      mro_isa_changed_in(GvSTASH(dsv));
     }
     else if(mro_changes == 3) {
-       HV * const stash = GvHV(dstr);
-       if(old_stash ? (HV *)HvENAME_get(old_stash) : stash)
-           mro_package_moved(
-               stash, old_stash,
-               (GV *)dstr, 0
-           );
-    }
-    else if(mro_changes) mro_method_changed_in(GvSTASH(dstr));
-    if (GvIO(dstr) && dtype == SVt_PVGV) {
-       DEBUG_o(Perl_deb(aTHX_
-                       "glob_assign_glob clearing PL_stashcache\n"));
-       /* It's a cache. It will rebuild itself quite happily.
-          It's a lot of effort to work out exactly which key (or keys)
-          might be invalidated by the creation of the this file handle.
-        */
-       hv_clear(PL_stashcache);
+        HV * const stash = GvHV(dsv);
+        if(old_stash ? HvHasENAME(old_stash) : cBOOL(stash))
+            mro_package_moved(
+                stash, old_stash,
+                (GV *)dsv, 0
+            );
+    }
+    else if(mro_changes) mro_method_changed_in(GvSTASH(dsv));
+    if (GvIO(dsv) && dtype == SVt_PVGV) {
+        DEBUG_o(Perl_deb(aTHX_
+                        "glob_assign_glob clearing PL_stashcache\n"));
+        /* It's a cache. It will rebuild itself quite happily.
+           It's a lot of effort to work out exactly which key (or keys)
+           might be invalidated by the creation of the this file handle.
+         */
+        hv_clear(PL_stashcache);
     }
     return;
 }
 
 void
-Perl_gv_setref(pTHX_ SV *const dstr, SV *const sstr)
+Perl_gv_setref(pTHX_ SV *const dsv, SV *const ssv)
 {
-    SV * const sref = SvRV(sstr);
+    SV * const sref = SvRV(ssv);
     SV *dref;
-    const int intro = GvINTRO(dstr);
+    const int intro = GvINTRO(dsv);
     SV **location;
     U8 import_flag = 0;
     const U32 stype = SvTYPE(sref);
@@ -3976,174 +3925,174 @@ Perl_gv_setref(pTHX_ SV *const dstr, SV *const sstr)
     PERL_ARGS_ASSERT_GV_SETREF;
 
     if (intro) {
-       GvINTRO_off(dstr);      /* one-shot flag */
-       GvLINE(dstr) = CopLINE(PL_curcop);
-       GvEGV(dstr) = MUTABLE_GV(dstr);
+        GvINTRO_off(dsv);      /* one-shot flag */
+        GvLINE(dsv) = CopLINE(PL_curcop);
+        GvEGV(dsv) = MUTABLE_GV(dsv);
     }
-    GvMULTI_on(dstr);
+    GvMULTI_on(dsv);
     switch (stype) {
     case SVt_PVCV:
-       location = (SV **) &(GvGP(dstr)->gp_cv); /* XXX bypassing GvCV_set */
-       import_flag = GVf_IMPORTED_CV;
-       goto common;
+        location = (SV **) &(GvGP(dsv)->gp_cv); /* XXX bypassing GvCV_set */
+        import_flag = GVf_IMPORTED_CV;
+        goto common;
     case SVt_PVHV:
-       location = (SV **) &GvHV(dstr);
-       import_flag = GVf_IMPORTED_HV;
-       goto common;
+        location = (SV **) &GvHV(dsv);
+        import_flag = GVf_IMPORTED_HV;
+        goto common;
     case SVt_PVAV:
-       location = (SV **) &GvAV(dstr);
-       import_flag = GVf_IMPORTED_AV;
-       goto common;
+        location = (SV **) &GvAV(dsv);
+        import_flag = GVf_IMPORTED_AV;
+        goto common;
     case SVt_PVIO:
-       location = (SV **) &GvIOp(dstr);
-       goto common;
+        location = (SV **) &GvIOp(dsv);
+        goto common;
     case SVt_PVFM:
-       location = (SV **) &GvFORM(dstr);
-       goto common;
+        location = (SV **) &GvFORM(dsv);
+        goto common;
     default:
-       location = &GvSV(dstr);
-       import_flag = GVf_IMPORTED_SV;
+        location = &GvSV(dsv);
+        import_flag = GVf_IMPORTED_SV;
     common:
-       if (intro) {
-           if (stype == SVt_PVCV) {
-               /*if (GvCVGEN(dstr) && (GvCV(dstr) != (const CV *)sref || GvCVGEN(dstr))) {*/
-               if (GvCVGEN(dstr)) {
-                   SvREFCNT_dec(GvCV(dstr));
-                   GvCV_set(dstr, NULL);
-                   GvCVGEN(dstr) = 0; /* Switch off cacheness. */
-               }
-           }
-           /* SAVEt_GVSLOT takes more room on the savestack and has more
-              overhead in leave_scope than SAVEt_GENERIC_SV.  But for CVs
-              leave_scope needs access to the GV so it can reset method
-              caches.  We must use SAVEt_GVSLOT whenever the type is
-              SVt_PVCV, even if the stash is anonymous, as the stash may
-              gain a name somehow before leave_scope. */
-           if (stype == SVt_PVCV) {
-               /* There is no save_pushptrptrptr.  Creating it for this
-                  one call site would be overkill.  So inline the ss add
-                  routines here. */
+        if (intro) {
+            if (stype == SVt_PVCV) {
+                /*if (GvCVGEN(dsv) && (GvCV(dsv) != (const CV *)sref || GvCVGEN(dsv))) {*/
+                if (GvCVGEN(dsv)) {
+                    SvREFCNT_dec(GvCV(dsv));
+                    GvCV_set(dsv, NULL);
+                    GvCVGEN(dsv) = 0; /* Switch off cacheness. */
+                }
+            }
+            /* SAVEt_GVSLOT takes more room on the savestack and has more
+               overhead in leave_scope than SAVEt_GENERIC_SV.  But for CVs
+               leave_scope needs access to the GV so it can reset method
+               caches.  We must use SAVEt_GVSLOT whenever the type is
+               SVt_PVCV, even if the stash is anonymous, as the stash may
+               gain a name somehow before leave_scope. */
+            if (stype == SVt_PVCV) {
+                /* There is no save_pushptrptrptr.  Creating it for this
+                   one call site would be overkill.  So inline the ss add
+                   routines here. */
                 dSS_ADD;
-               SS_ADD_PTR(dstr);
-               SS_ADD_PTR(location);
-               SS_ADD_PTR(SvREFCNT_inc(*location));
-               SS_ADD_UV(SAVEt_GVSLOT);
-               SS_ADD_END(4);
-           }
-           else SAVEGENERICSV(*location);
-       }
-       dref = *location;
-       if (stype == SVt_PVCV && (*location != sref || GvCVGEN(dstr))) {
-           CV* const cv = MUTABLE_CV(*location);
-           if (cv) {
-               if (!GvCVGEN((const GV *)dstr) &&
-                   (CvROOT(cv) || CvXSUB(cv)) &&
-                   /* redundant check that avoids creating the extra SV
-                      most of the time: */
-                   (CvCONST(cv) || ckWARN(WARN_REDEFINE)))
-                   {
-                       SV * const new_const_sv =
-                           CvCONST((const CV *)sref)
-                                ? cv_const_sv((const CV *)sref)
-                                : NULL;
-                        HV * const stash = GvSTASH((const GV *)dstr);
-                       report_redefined_cv(
-                          sv_2mortal(
+                SS_ADD_PTR(dsv);
+                SS_ADD_PTR(location);
+                SS_ADD_PTR(SvREFCNT_inc(*location));
+                SS_ADD_UV(SAVEt_GVSLOT);
+                SS_ADD_END(4);
+            }
+            else SAVEGENERICSV(*location);
+        }
+        dref = *location;
+        if (stype == SVt_PVCV && (*location != sref || GvCVGEN(dsv))) {
+            CV* const cv = MUTABLE_CV(*location);
+            if (cv) {
+                if (!GvCVGEN((const GV *)dsv) &&
+                    (CvROOT(cv) || CvXSUB(cv)) &&
+                    /* redundant check that avoids creating the extra SV
+                       most of the time: */
+                    (CvCONST(cv) || (ckWARN(WARN_REDEFINE) && !intro)))
+                    {
+                        SV * const new_const_sv =
+                            CvCONST((const CV *)sref)
+                                 ? cv_const_sv_or_av((const CV *)sref)
+                                 : NULL;
+                        HV * const stash = GvSTASH((const GV *)dsv);
+                        report_redefined_cv(
+                           sv_2mortal(
                              stash
                                ? Perl_newSVpvf(aTHX_
-                                   "%" HEKf "::%" HEKf,
-                                   HEKfARG(HvNAME_HEK(stash)),
-                                   HEKfARG(GvENAME_HEK(MUTABLE_GV(dstr))))
+                                    "%" HEKf "::%" HEKf,
+                                    HEKfARG(HvNAME_HEK(stash)),
+                                    HEKfARG(GvENAME_HEK(MUTABLE_GV(dsv))))
                                : Perl_newSVpvf(aTHX_
-                                   "%" HEKf,
-                                   HEKfARG(GvENAME_HEK(MUTABLE_GV(dstr))))
-                          ),
-                          cv,
-                          CvCONST((const CV *)sref) ? &new_const_sv : NULL
-                       );
-                   }
-               if (!intro)
-                   cv_ckproto_len_flags(cv, (const GV *)dstr,
-                                  SvPOK(sref) ? CvPROTO(sref) : NULL,
-                                  SvPOK(sref) ? CvPROTOLEN(sref) : 0,
+                                    "%" HEKf,
+                                    HEKfARG(GvENAME_HEK(MUTABLE_GV(dsv))))
+                           ),
+                           cv,
+                           CvCONST((const CV *)sref) ? &new_const_sv : NULL
+                        );
+                    }
+                if (!intro)
+                    cv_ckproto_len_flags(cv, (const GV *)dsv,
+                                   SvPOK(sref) ? CvPROTO(sref) : NULL,
+                                   SvPOK(sref) ? CvPROTOLEN(sref) : 0,
                                    SvPOK(sref) ? SvUTF8(sref) : 0);
-           }
-           GvCVGEN(dstr) = 0; /* Switch off cacheness. */
-           GvASSUMECV_on(dstr);
-           if(GvSTASH(dstr)) { /* sub foo { 1 } sub bar { 2 } *bar = \&foo */
-               if (intro && GvREFCNT(dstr) > 1) {
-                   /* temporary remove extra savestack's ref */
-                   --GvREFCNT(dstr);
-                   gv_method_changed(dstr);
-                   ++GvREFCNT(dstr);
-               }
-               else gv_method_changed(dstr);
-           }
-       }
-       *location = SvREFCNT_inc_simple_NN(sref);
-       if (import_flag && !(GvFLAGS(dstr) & import_flag)
-           && CopSTASH_ne(PL_curcop, GvSTASH(dstr))) {
-           GvFLAGS(dstr) |= import_flag;
-       }
-
-       if (stype == SVt_PVHV) {
-           const char * const name = GvNAME((GV*)dstr);
-           const STRLEN len = GvNAMELEN(dstr);
-           if (
-               (
-                  (len > 1 && name[len-2] == ':' && name[len-1] == ':')
-               || (len == 1 && name[0] == ':')
-               )
-            && (!dref || HvENAME_get(dref))
-           ) {
-               mro_package_moved(
-                   (HV *)sref, (HV *)dref,
-                   (GV *)dstr, 0
-               );
-           }
-       }
-       else if (
-           stype == SVt_PVAV && sref != dref
-        && memEQs(GvNAME((GV*)dstr), GvNAMELEN((GV*)dstr), "ISA")
-        /* The stash may have been detached from the symbol table, so
-           check its name before doing anything. */
-        && GvSTASH(dstr) && HvENAME(GvSTASH(dstr))
-       ) {
-           MAGIC *mg;
-           MAGIC * const omg = dref && SvSMAGICAL(dref)
-                                ? mg_find(dref, PERL_MAGIC_isa)
-                                : NULL;
-           if (SvSMAGICAL(sref) && (mg = mg_find(sref, PERL_MAGIC_isa))) {
-               if (SvTYPE(mg->mg_obj) != SVt_PVAV) {
-                   AV * const ary = newAV();
-                   av_push(ary, mg->mg_obj); /* takes the refcount */
-                   mg->mg_obj = (SV *)ary;
-               }
-               if (omg) {
-                   if (SvTYPE(omg->mg_obj) == SVt_PVAV) {
-                       SV **svp = AvARRAY((AV *)omg->mg_obj);
-                       I32 items = AvFILLp((AV *)omg->mg_obj) + 1;
-                       while (items--)
-                           av_push(
-                            (AV *)mg->mg_obj,
-                            SvREFCNT_inc_simple_NN(*svp++)
-                           );
-                   }
-                   else
-                       av_push(
-                        (AV *)mg->mg_obj,
-                        SvREFCNT_inc_simple_NN(omg->mg_obj)
-                       );
-               }
-               else
-                   av_push((AV *)mg->mg_obj,SvREFCNT_inc_simple_NN(dstr));
-           }
-           else
-           {
+            }
+            GvCVGEN(dsv) = 0; /* Switch off cacheness. */
+            GvASSUMECV_on(dsv);
+            if(GvSTASH(dsv)) { /* sub foo { 1 } sub bar { 2 } *bar = \&foo */
+                if (intro && GvREFCNT(dsv) > 1) {
+                    /* temporary remove extra savestack's ref */
+                    --GvREFCNT(dsv);
+                    gv_method_changed(dsv);
+                    ++GvREFCNT(dsv);
+                }
+                else gv_method_changed(dsv);
+            }
+        }
+        *location = SvREFCNT_inc_simple_NN(sref);
+        if (import_flag && !(GvFLAGS(dsv) & import_flag)
+            && CopSTASH_ne(PL_curcop, GvSTASH(dsv))) {
+            GvFLAGS(dsv) |= import_flag;
+        }
+
+        if (stype == SVt_PVHV) {
+            const char * const name = GvNAME((GV*)dsv);
+            const STRLEN len = GvNAMELEN(dsv);
+            if (
+                (
+                   (len > 1 && name[len-2] == ':' && name[len-1] == ':')
+                || (len == 1 && name[0] == ':')
+                )
+             && (!dref || HvHasENAME(dref))
+            ) {
+                mro_package_moved(
+                    (HV *)sref, (HV *)dref,
+                    (GV *)dsv, 0
+                );
+            }
+        }
+        else if (
+            stype == SVt_PVAV && sref != dref
+         && memEQs(GvNAME((GV*)dsv), GvNAMELEN((GV*)dsv), "ISA")
+         /* The stash may have been detached from the symbol table, so
+            check its name before doing anything. */
+         && GvSTASH(dsv) && HvHasENAME(GvSTASH(dsv))
+        ) {
+            MAGIC *mg;
+            MAGIC * const omg = dref && SvSMAGICAL(dref)
+                                 ? mg_find(dref, PERL_MAGIC_isa)
+                                 : NULL;
+            if (SvSMAGICAL(sref) && (mg = mg_find(sref, PERL_MAGIC_isa))) {
+                if (SvTYPE(mg->mg_obj) != SVt_PVAV) {
+                    AV * const ary = newAV_alloc_xz(4);
+                    av_push_simple(ary, mg->mg_obj); /* takes the refcount */
+                    mg->mg_obj = (SV *)ary;
+                }
+                if (omg) {
+                    if (SvTYPE(omg->mg_obj) == SVt_PVAV) {
+                        SV **svp = AvARRAY((AV *)omg->mg_obj);
+                        I32 items = AvFILLp((AV *)omg->mg_obj) + 1;
+                        while (items--)
+                            av_push(
+                             (AV *)mg->mg_obj,
+                             SvREFCNT_inc_simple_NN(*svp++)
+                            );
+                    }
+                    else
+                        av_push(
+                         (AV *)mg->mg_obj,
+                         SvREFCNT_inc_simple_NN(omg->mg_obj)
+                        );
+                }
+                else
+                    av_push((AV *)mg->mg_obj,SvREFCNT_inc_simple_NN(dsv));
+            }
+            else
+            {
                 SSize_t i;
-               sv_magic(
-                sref, omg ? omg->mg_obj : dstr, PERL_MAGIC_isa, NULL, 0
-               );
+                sv_magic(
+                 sref, omg ? omg->mg_obj : dsv, PERL_MAGIC_isa, NULL, 0
+                );
                 for (i = 0; i <= AvFILL(sref); ++i) {
                     SV **elem = av_fetch ((AV*)sref, i, 0);
                     if (elem) {
@@ -4152,15 +4101,15 @@ Perl_gv_setref(pTHX_ SV *const dstr, SV *const sstr)
                         );
                     }
                 }
-               mg = mg_find(sref, PERL_MAGIC_isa);
-           }
-           /* Since the *ISA assignment could have affected more than
-              one stash, don't call mro_isa_changed_in directly, but let
-              magic_clearisa do it for us, as it already has the logic for
-              dealing with globs vs arrays of globs. */
-           assert(mg);
-           Perl_magic_clearisa(aTHX_ NULL, mg);
-       }
+                mg = mg_find(sref, PERL_MAGIC_isa);
+            }
+            /* Since the *ISA assignment could have affected more than
+               one stash, don't call mro_isa_changed_in directly, but let
+               magic_clearisa do it for us, as it already has the logic for
+               dealing with globs vs arrays of globs. */
+            assert(mg);
+            Perl_magic_clearisa(aTHX_ NULL, mg);
+        }
         else if (stype == SVt_PVIO) {
             DEBUG_o(Perl_deb(aTHX_ "gv_setref clearing PL_stashcache\n"));
             /* It's a cache. It will rebuild itself quite happily.
@@ -4169,11 +4118,11 @@ Perl_gv_setref(pTHX_ SV *const dstr, SV *const sstr)
             */
             hv_clear(PL_stashcache);
         }
-       break;
+        break;
     }
     if (!intro) SvREFCNT_dec(dref);
-    if (SvTAINTED(sstr))
-       SvTAINT(dstr);
+    if (SvTAINTED(ssv))
+        SvTAINT(dsv);
     return;
 }
 
@@ -4191,27 +4140,27 @@ void
 Perl_sv_buf_to_ro(pTHX_ SV *sv)
 {
     struct perl_memory_debug_header * const header =
-       (struct perl_memory_debug_header *)(SvPVX(sv)-PERL_MEMORY_DEBUG_HEADER_SIZE);
+        (struct perl_memory_debug_header *)(SvPVX(sv)-PERL_MEMORY_DEBUG_HEADER_SIZE);
     const MEM_SIZE len = header->size;
     PERL_ARGS_ASSERT_SV_BUF_TO_RO;
 # ifdef PERL_TRACK_MEMPOOL
     if (!header->readonly) header->readonly = 1;
 # endif
     if (mprotect(header, len, PROT_READ))
-       Perl_warn(aTHX_ "mprotect RW for COW string %p %lu failed with %d",
-                        header, len, errno);
+        Perl_warn(aTHX_ "mprotect RW for COW string %p %lu failed with %d",
+                         header, len, errno);
 }
 
 static void
 S_sv_buf_to_rw(pTHX_ SV *sv)
 {
     struct perl_memory_debug_header * const header =
-       (struct perl_memory_debug_header *)(SvPVX(sv)-PERL_MEMORY_DEBUG_HEADER_SIZE);
+        (struct perl_memory_debug_header *)(SvPVX(sv)-PERL_MEMORY_DEBUG_HEADER_SIZE);
     const MEM_SIZE len = header->size;
     PERL_ARGS_ASSERT_SV_BUF_TO_RW;
     if (mprotect(header, len, PROT_READ|PROT_WRITE))
-       Perl_warn(aTHX_ "mprotect for COW string %p %lu failed with %d",
-                        header, len, errno);
+        Perl_warn(aTHX_ "mprotect for COW string %p %lu failed with %d",
+                         header, len, errno);
 # ifdef PERL_TRACK_MEMPOOL
     header->readonly = 0;
 # endif
@@ -4223,7 +4172,7 @@ S_sv_buf_to_rw(pTHX_ SV *sv)
 #endif
 
 void
-Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags)
+Perl_sv_setsv_flags(pTHX_ SV *dsv, SV* ssv, const I32 flags)
 {
     U32 sflags;
     int dtype;
@@ -4232,388 +4181,417 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags)
 
     PERL_ARGS_ASSERT_SV_SETSV_FLAGS;
 
-    if (UNLIKELY( sstr == dstr ))
-       return;
+    if (UNLIKELY( ssv == dsv ))
+        return;
 
-    if (UNLIKELY( !sstr ))
-       sstr = &PL_sv_undef;
+    if (UNLIKELY( !ssv ))
+        ssv = &PL_sv_undef;
 
-    stype = SvTYPE(sstr);
-    dtype = SvTYPE(dstr);
+    stype = SvTYPE(ssv);
+    dtype = SvTYPE(dsv);
     both_type = (stype | dtype);
 
     /* with these values, we can check that both SVs are NULL/IV (and not
      * freed) just by testing the or'ed types */
     STATIC_ASSERT_STMT(SVt_NULL == 0);
     STATIC_ASSERT_STMT(SVt_IV   == 1);
+    STATIC_ASSERT_STMT(SVt_NV   == 2);
+#if NVSIZE <= IVSIZE
+    if (both_type <= 2) {
+#else
     if (both_type <= 1) {
-        /* both src and dst are UNDEF/IV/RV, so we can do a lot of
-         * special-casing */
+#endif
+        /* both src and dst are UNDEF/IV/RV - maybe NV depending on config,
+         * so we can do a lot of special-casing */
         U32 sflags;
         U32 new_dflags;
         SV *old_rv = NULL;
 
-        /* minimal subset of SV_CHECK_THINKFIRST_COW_DROP(dstr) */
-        if (SvREADONLY(dstr))
+        /* minimal subset of SV_CHECK_THINKFIRST_COW_DROP(dsv) */
+        if (SvREADONLY(dsv))
             Perl_croak_no_modify();
-        if (SvROK(dstr)) {
-            if (SvWEAKREF(dstr))
-                sv_unref_flags(dstr, 0);
+        if (SvROK(dsv)) {
+            if (SvWEAKREF(dsv))
+                sv_unref_flags(dsv, 0);
             else
-                old_rv = SvRV(dstr);
+                old_rv = SvRV(dsv);
+            SvROK_off(dsv);
         }
 
-        assert(!SvGMAGICAL(sstr));
-        assert(!SvGMAGICAL(dstr));
+        assert(!SvGMAGICAL(ssv));
+        assert(!SvGMAGICAL(dsv));
 
-        sflags = SvFLAGS(sstr);
+        sflags = SvFLAGS(ssv);
         if (sflags & (SVf_IOK|SVf_ROK)) {
-            SET_SVANY_FOR_BODYLESS_IV(dstr);
+            SET_SVANY_FOR_BODYLESS_IV(dsv);
             new_dflags = SVt_IV;
 
             if (sflags & SVf_ROK) {
-                dstr->sv_u.svu_rv = SvREFCNT_inc(SvRV(sstr));
+                dsv->sv_u.svu_rv = SvREFCNT_inc(SvRV(ssv));
                 new_dflags |= SVf_ROK;
             }
             else {
                 /* both src and dst are <= SVt_IV, so sv_any points to the
                  * head; so access the head directly
                  */
-                assert(    &(sstr->sv_u.svu_iv)
-                        == &(((XPVIV*) SvANY(sstr))->xiv_iv));
-                assert(    &(dstr->sv_u.svu_iv)
-                        == &(((XPVIV*) SvANY(dstr))->xiv_iv));
-                dstr->sv_u.svu_iv = sstr->sv_u.svu_iv;
+                assert(    &(ssv->sv_u.svu_iv)
+                        == &(((XPVIV*) SvANY(ssv))->xiv_iv));
+                assert(    &(dsv->sv_u.svu_iv)
+                        == &(((XPVIV*) SvANY(dsv))->xiv_iv));
+                dsv->sv_u.svu_iv = ssv->sv_u.svu_iv;
                 new_dflags |= (SVf_IOK|SVp_IOK|(sflags & SVf_IVisUV));
             }
         }
+#if NVSIZE <= IVSIZE
+        else if (sflags & SVf_NOK) {
+            SET_SVANY_FOR_BODYLESS_NV(dsv);
+            new_dflags = (SVt_NV|SVf_NOK|SVp_NOK);
+
+            /* both src and dst are <= SVt_MV, so sv_any points to the
+             * head; so access the head directly
+             */
+            assert(    &(ssv->sv_u.svu_nv)
+                    == &(((XPVNV*) SvANY(ssv))->xnv_u.xnv_nv));
+            assert(    &(dsv->sv_u.svu_nv)
+                    == &(((XPVNV*) SvANY(dsv))->xnv_u.xnv_nv));
+            dsv->sv_u.svu_nv = ssv->sv_u.svu_nv;
+        }
+#endif
         else {
             new_dflags = dtype; /* turn off everything except the type */
         }
-        SvFLAGS(dstr) = new_dflags;
-        SvREFCNT_dec(old_rv);
+        /* Should preserve some dsv flags - at least SVs_TEMP, */
+        /* so cannot just set SvFLAGS(dsv) = new_dflags        */
+        /* First clear the flags that we do want to clobber    */
+        (void)SvOK_off(dsv);
+        SvFLAGS(dsv) &= ~SVTYPEMASK;
+        /* Now set the new flags */
+        SvFLAGS(dsv) |= new_dflags;
 
+        SvREFCNT_dec(old_rv);
         return;
     }
 
     if (UNLIKELY(both_type == SVTYPEMASK)) {
-        if (SvIS_FREED(dstr)) {
+        if (SvIS_FREED(dsv)) {
             Perl_croak(aTHX_ "panic: attempt to copy value %" SVf
-                       " to a freed scalar %p", SVfARG(sstr), (void *)dstr);
+                       " to a freed scalar %p", SVfARG(ssv), (void *)dsv);
         }
-        if (SvIS_FREED(sstr)) {
+        if (SvIS_FREED(ssv)) {
             Perl_croak(aTHX_ "panic: attempt to copy freed scalar %p to %p",
-                       (void*)sstr, (void*)dstr);
+                       (void*)ssv, (void*)dsv);
         }
     }
 
 
 
-    SV_CHECK_THINKFIRST_COW_DROP(dstr);
-    dtype = SvTYPE(dstr); /* THINKFIRST may have changed type */
+    SV_CHECK_THINKFIRST_COW_DROP(dsv);
+    dtype = SvTYPE(dsv); /* THINKFIRST may have changed type */
 
-    /* There's a lot of redundancy below but we're going for speed here */
+    /* There's a lot of redundancy below but we're going for speed here
+     * Note: some of the cases below do return; rather than break; so the
+     * if-elseif-else logic below this switch does not see all cases. */
 
     switch (stype) {
     case SVt_NULL:
       undef_sstr:
-       if (LIKELY( dtype != SVt_PVGV && dtype != SVt_PVLV )) {
-           (void)SvOK_off(dstr);
-           return;
-       }
-       break;
+        if (LIKELY( dtype != SVt_PVGV && dtype != SVt_PVLV )) {
+            (void)SvOK_off(dsv);
+            return;
+        }
+        break;
     case SVt_IV:
-       if (SvIOK(sstr)) {
-           switch (dtype) {
-           case SVt_NULL:
-               /* For performance, we inline promoting to type SVt_IV. */
-               /* We're starting from SVt_NULL, so provided that define is
-                * actual 0, we don't have to unset any SV type flags
-                * to promote to SVt_IV. */
-               STATIC_ASSERT_STMT(SVt_NULL == 0);
-               SET_SVANY_FOR_BODYLESS_IV(dstr);
-               SvFLAGS(dstr) |= SVt_IV;
-               break;
-           case SVt_NV:
-           case SVt_PV:
-               sv_upgrade(dstr, SVt_PVIV);
-               break;
-           case SVt_PVGV:
-           case SVt_PVLV:
-               goto end_of_first_switch;
-           }
-           (void)SvIOK_only(dstr);
-           SvIV_set(dstr,  SvIVX(sstr));
-           if (SvIsUV(sstr))
-               SvIsUV_on(dstr);
-           /* SvTAINTED can only be true if the SV has taint magic, which in
-              turn means that the SV type is PVMG (or greater). This is the
-              case statement for SVt_IV, so this cannot be true (whatever gcov
-              may say).  */
-           assert(!SvTAINTED(sstr));
-           return;
-       }
-       if (!SvROK(sstr))
-           goto undef_sstr;
-       if (dtype < SVt_PV && dtype != SVt_IV)
-           sv_upgrade(dstr, SVt_IV);
-       break;
+        if (SvIOK(ssv)) {
+            switch (dtype) {
+            case SVt_NULL:
+                /* For performance, we inline promoting to type SVt_IV. */
+                /* We're starting from SVt_NULL, so provided that define is
+                 * actual 0, we don't have to unset any SV type flags
+                 * to promote to SVt_IV. */
+                STATIC_ASSERT_STMT(SVt_NULL == 0);
+                SET_SVANY_FOR_BODYLESS_IV(dsv);
+                SvFLAGS(dsv) |= SVt_IV;
+                break;
+            case SVt_NV:
+            case SVt_PV:
+                sv_upgrade(dsv, SVt_PVIV);
+                break;
+            case SVt_PVGV:
+            case SVt_PVLV:
+                goto end_of_first_switch;
+            }
+            (void)SvIOK_only(dsv);
+            SvIV_set(dsv,  SvIVX(ssv));
+            if (SvIsUV(ssv))
+                SvIsUV_on(dsv);
+            /* SvTAINTED can only be true if the SV has taint magic, which in
+               turn means that the SV type is PVMG (or greater). This is the
+               case statement for SVt_IV, so this cannot be true (whatever gcov
+               may say).  */
+            assert(!SvTAINTED(ssv));
+            return;
+        }
+        if (!SvROK(ssv))
+            goto undef_sstr;
+        if (dtype < SVt_PV && dtype != SVt_IV)
+            sv_upgrade(dsv, SVt_IV);
+        break;
 
     case SVt_NV:
-       if (LIKELY( SvNOK(sstr) )) {
-           switch (dtype) {
-           case SVt_NULL:
-           case SVt_IV:
-               sv_upgrade(dstr, SVt_NV);
-               break;
-           case SVt_PV:
-           case SVt_PVIV:
-               sv_upgrade(dstr, SVt_PVNV);
-               break;
-           case SVt_PVGV:
-           case SVt_PVLV:
-               goto end_of_first_switch;
-           }
-           SvNV_set(dstr, SvNVX(sstr));
-           (void)SvNOK_only(dstr);
-           /* SvTAINTED can only be true if the SV has taint magic, which in
-              turn means that the SV type is PVMG (or greater). This is the
-              case statement for SVt_NV, so this cannot be true (whatever gcov
-              may say).  */
-           assert(!SvTAINTED(sstr));
-           return;
-       }
-       goto undef_sstr;
+        if (LIKELY( SvNOK(ssv) )) {
+            switch (dtype) {
+            case SVt_NULL:
+            case SVt_IV:
+                sv_upgrade(dsv, SVt_NV);
+                break;
+            case SVt_PV:
+            case SVt_PVIV:
+                sv_upgrade(dsv, SVt_PVNV);
+                break;
+            case SVt_PVGV:
+            case SVt_PVLV:
+                goto end_of_first_switch;
+            }
+            SvNV_set(dsv, SvNVX(ssv));
+            (void)SvNOK_only(dsv);
+            /* SvTAINTED can only be true if the SV has taint magic, which in
+               turn means that the SV type is PVMG (or greater). This is the
+               case statement for SVt_NV, so this cannot be true (whatever gcov
+               may say).  */
+            assert(!SvTAINTED(ssv));
+            return;
+        }
+        goto undef_sstr;
 
     case SVt_PV:
-       if (dtype < SVt_PV)
-           sv_upgrade(dstr, SVt_PV);
-       break;
+        if (dtype < SVt_PV)
+            sv_upgrade(dsv, SVt_PV);
+        break;
     case SVt_PVIV:
-       if (dtype < SVt_PVIV)
-           sv_upgrade(dstr, SVt_PVIV);
-       break;
+        if (dtype < SVt_PVIV)
+            sv_upgrade(dsv, SVt_PVIV);
+        break;
     case SVt_PVNV:
-       if (dtype < SVt_PVNV)
-           sv_upgrade(dstr, SVt_PVNV);
-       break;
+        if (dtype < SVt_PVNV)
+            sv_upgrade(dsv, SVt_PVNV);
+        break;
 
     case SVt_INVLIST:
-        invlist_clone(sstr, dstr);
-        break;
+        invlist_clone(ssv, dsv);
+        return;
     default:
-       {
-       const char * const type = sv_reftype(sstr,0);
-       if (PL_op)
-           /* diag_listed_as: Bizarre copy of %s */
-           Perl_croak(aTHX_ "Bizarre copy of %s in %s", type, OP_DESC(PL_op));
-       else
-           Perl_croak(aTHX_ "Bizarre copy of %s", type);
-       }
-       NOT_REACHED; /* NOTREACHED */
+        {
+        const char * const type = sv_reftype(ssv,0);
+        if (PL_op)
+            /* diag_listed_as: Bizarre copy of %s */
+            Perl_croak(aTHX_ "Bizarre copy of %s in %s", type, OP_DESC(PL_op));
+        else
+            Perl_croak(aTHX_ "Bizarre copy of %s", type);
+        }
+        NOT_REACHED; /* NOTREACHED */
 
     case SVt_REGEXP:
       upgregexp:
-       if (dtype < SVt_REGEXP)
-           sv_upgrade(dstr, SVt_REGEXP);
-       break;
+        if (dtype < SVt_REGEXP)
+            sv_upgrade(dsv, SVt_REGEXP);
+        break;
 
     case SVt_PVLV:
     case SVt_PVGV:
     case SVt_PVMG:
-       if (SvGMAGICAL(sstr) && (flags & SV_GMAGIC)) {
-           mg_get(sstr);
-           if (SvTYPE(sstr) != stype)
-               stype = SvTYPE(sstr);
-       }
-       if (isGV_with_GP(sstr) && dtype <= SVt_PVLV) {
-                   glob_assign_glob(dstr, sstr, dtype);
-                   return;
-       }
-       if (stype == SVt_PVLV)
-       {
-           if (isREGEXP(sstr)) goto upgregexp;
-           SvUPGRADE(dstr, SVt_PVNV);
-       }
-       else
-           SvUPGRADE(dstr, (svtype)stype);
+        if (SvGMAGICAL(ssv) && (flags & SV_GMAGIC)) {
+            mg_get(ssv);
+            if (SvTYPE(ssv) != stype)
+                stype = SvTYPE(ssv);
+        }
+        if (isGV_with_GP(ssv) && dtype <= SVt_PVLV) {
+                    glob_assign_glob(dsv, ssv, dtype);
+                    return;
+        }
+        if (stype == SVt_PVLV)
+        {
+            if (isREGEXP(ssv)) goto upgregexp;
+            SvUPGRADE(dsv, SVt_PVNV);
+        }
+        else
+            SvUPGRADE(dsv, (svtype)stype);
     }
  end_of_first_switch:
 
-    /* dstr may have been upgraded.  */
-    dtype = SvTYPE(dstr);
-    sflags = SvFLAGS(sstr);
+    /* dsv may have been upgraded.  */
+    dtype = SvTYPE(dsv);
+    sflags = SvFLAGS(ssv);
 
     if (UNLIKELY( dtype == SVt_PVCV )) {
-       /* Assigning to a subroutine sets the prototype.  */
-       if (SvOK(sstr)) {
-           STRLEN len;
-           const char *const ptr = SvPV_const(sstr, len);
-
-            SvGROW(dstr, len + 1);
-            Copy(ptr, SvPVX(dstr), len + 1, char);
-            SvCUR_set(dstr, len);
-           SvPOK_only(dstr);
-           SvFLAGS(dstr) |= sflags & SVf_UTF8;
-           CvAUTOLOAD_off(dstr);
-       } else {
-           SvOK_off(dstr);
-       }
+        /* Assigning to a subroutine sets the prototype.  */
+        if (SvOK(ssv)) {
+            STRLEN len;
+            const char *const ptr = SvPV_const(ssv, len);
+
+            SvGROW(dsv, len + 1);
+            Copy(ptr, SvPVX(dsv), len + 1, char);
+            SvCUR_set(dsv, len);
+            SvPOK_only(dsv);
+            SvFLAGS(dsv) |= sflags & SVf_UTF8;
+            CvAUTOLOAD_off(dsv);
+        } else {
+            SvOK_off(dsv);
+        }
     }
     else if (UNLIKELY(dtype == SVt_PVAV || dtype == SVt_PVHV
              || dtype == SVt_PVFM))
     {
-       const char * const type = sv_reftype(dstr,0);
-       if (PL_op)
-           /* diag_listed_as: Cannot copy to %s */
-           Perl_croak(aTHX_ "Cannot copy to %s in %s", type, OP_DESC(PL_op));
-       else
-           Perl_croak(aTHX_ "Cannot copy to %s", type);
+        const char * const type = sv_reftype(dsv,0);
+        if (PL_op)
+            /* diag_listed_as: Cannot copy to %s */
+            Perl_croak(aTHX_ "Cannot copy to %s in %s", type, OP_DESC(PL_op));
+        else
+            Perl_croak(aTHX_ "Cannot copy to %s", type);
     } else if (sflags & SVf_ROK) {
-       if (isGV_with_GP(dstr)
-           && SvTYPE(SvRV(sstr)) == SVt_PVGV && isGV_with_GP(SvRV(sstr))) {
-           sstr = SvRV(sstr);
-           if (sstr == dstr) {
-               if (GvIMPORTED(dstr) != GVf_IMPORTED
-                   && CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
-               {
-                   GvIMPORTED_on(dstr);
-               }
-               GvMULTI_on(dstr);
-               return;
-           }
-           glob_assign_glob(dstr, sstr, dtype);
-           return;
-       }
-
-       if (dtype >= SVt_PV) {
-           if (isGV_with_GP(dstr)) {
-               gv_setref(dstr, sstr);
-               return;
-           }
-           if (SvPVX_const(dstr)) {
-               SvPV_free(dstr);
-               SvLEN_set(dstr, 0);
-                SvCUR_set(dstr, 0);
-           }
-       }
-       (void)SvOK_off(dstr);
-       SvRV_set(dstr, SvREFCNT_inc(SvRV(sstr)));
-       SvFLAGS(dstr) |= sflags & SVf_ROK;
-       assert(!(sflags & SVp_NOK));
-       assert(!(sflags & SVp_IOK));
-       assert(!(sflags & SVf_NOK));
-       assert(!(sflags & SVf_IOK));
-    }
-    else if (isGV_with_GP(dstr)) {
-       if (!(sflags & SVf_OK)) {
-           Perl_ck_warner(aTHX_ packWARN(WARN_MISC),
-                          "Undefined value assigned to typeglob");
-       }
-       else {
-           GV *gv = gv_fetchsv_nomg(sstr, GV_ADD, SVt_PVGV);
-           if (dstr != (const SV *)gv) {
-               const char * const name = GvNAME((const GV *)dstr);
-               const STRLEN len = GvNAMELEN(dstr);
-               HV *old_stash = NULL;
-               bool reset_isa = FALSE;
-               if ((len > 1 && name[len-2] == ':' && name[len-1] == ':')
-                || (len == 1 && name[0] == ':')) {
-                   /* Set aside the old stash, so we can reset isa caches
-                      on its subclasses. */
-                   if((old_stash = GvHV(dstr))) {
-                       /* Make sure we do not lose it early. */
-                       SvREFCNT_inc_simple_void_NN(
-                        sv_2mortal((SV *)old_stash)
-                       );
-                   }
-                   reset_isa = TRUE;
-               }
-
-               if (GvGP(dstr)) {
-                   SvREFCNT_inc_simple_void_NN(sv_2mortal(dstr));
-                   gp_free(MUTABLE_GV(dstr));
-               }
-               GvGP_set(dstr, gp_ref(GvGP(gv)));
-
-               if (reset_isa) {
-                   HV * const stash = GvHV(dstr);
-                   if(
-                       old_stash ? (HV *)HvENAME_get(old_stash) : stash
-                   )
-                       mro_package_moved(
-                        stash, old_stash,
-                        (GV *)dstr, 0
-                       );
-               }
-           }
-       }
+        if (isGV_with_GP(dsv)
+            && SvTYPE(SvRV(ssv)) == SVt_PVGV && isGV_with_GP(SvRV(ssv))) {
+            ssv = SvRV(ssv);
+            if (ssv == dsv) {
+                if (GvIMPORTED(dsv) != GVf_IMPORTED
+                    && CopSTASH_ne(PL_curcop, GvSTASH(dsv)))
+                {
+                    GvIMPORTED_on(dsv);
+                }
+                GvMULTI_on(dsv);
+                return;
+            }
+            glob_assign_glob(dsv, ssv, dtype);
+            return;
+        }
+
+        if (dtype >= SVt_PV) {
+            if (isGV_with_GP(dsv)) {
+                gv_setref(dsv, ssv);
+                return;
+            }
+            if (SvPVX_const(dsv)) {
+                SvPV_free(dsv);
+                SvLEN_set(dsv, 0);
+                SvCUR_set(dsv, 0);
+            }
+        }
+        (void)SvOK_off(dsv);
+        SvRV_set(dsv, SvREFCNT_inc(SvRV(ssv)));
+        SvFLAGS(dsv) |= sflags & SVf_ROK;
+        assert(!(sflags & SVp_NOK));
+        assert(!(sflags & SVp_IOK));
+        assert(!(sflags & SVf_NOK));
+        assert(!(sflags & SVf_IOK));
+    }
+    else if (isGV_with_GP(dsv)) {
+        if (!(sflags & SVf_OK)) {
+            Perl_ck_warner(aTHX_ packWARN(WARN_MISC),
+                           "Undefined value assigned to typeglob");
+        }
+        else {
+            GV *gv = gv_fetchsv_nomg(ssv, GV_ADD, SVt_PVGV);
+            if (dsv != (const SV *)gv) {
+                const char * const name = GvNAME((const GV *)dsv);
+                const STRLEN len = GvNAMELEN(dsv);
+                HV *old_stash = NULL;
+                bool reset_isa = FALSE;
+                if ((len > 1 && name[len-2] == ':' && name[len-1] == ':')
+                 || (len == 1 && name[0] == ':')) {
+                    /* Set aside the old stash, so we can reset isa caches
+                       on its subclasses. */
+                    if((old_stash = GvHV(dsv))) {
+                        /* Make sure we do not lose it early. */
+                        SvREFCNT_inc_simple_void_NN(
+                         sv_2mortal((SV *)old_stash)
+                        );
+                    }
+                    reset_isa = TRUE;
+                }
+
+                if (GvGP(dsv)) {
+                    SvREFCNT_inc_simple_void_NN(sv_2mortal(dsv));
+                    gp_free(MUTABLE_GV(dsv));
+                }
+                GvGP_set(dsv, gp_ref(GvGP(gv)));
+
+                if (reset_isa) {
+                    HV * const stash = GvHV(dsv);
+                    if(
+                        old_stash ? HvHasENAME(old_stash) : cBOOL(stash)
+                    )
+                        mro_package_moved(
+                         stash, old_stash,
+                         (GV *)dsv, 0
+                        );
+                }
+            }
+        }
     }
     else if ((dtype == SVt_REGEXP || dtype == SVt_PVLV)
-         && (stype == SVt_REGEXP || isREGEXP(sstr))) {
-       reg_temp_copy((REGEXP*)dstr, (REGEXP*)sstr);
+          && (stype == SVt_REGEXP || isREGEXP(ssv))) {
+        reg_temp_copy((REGEXP*)dsv, (REGEXP*)ssv);
     }
     else if (sflags & SVp_POK) {
-       const STRLEN cur = SvCUR(sstr);
-       const STRLEN len = SvLEN(sstr);
-
-       /*
-        * We have three basic ways to copy the string:
-        *
-        *  1. Swipe
-        *  2. Copy-on-write
-        *  3. Actual copy
-        * 
-        * Which we choose is based on various factors.  The following
-        * things are listed in order of speed, fastest to slowest:
-        *  - Swipe
-        *  - Copying a short string
-        *  - Copy-on-write bookkeeping
-        *  - malloc
-        *  - Copying a long string
-        * 
-        * We swipe the string (steal the string buffer) if the SV on the
-        * rhs is about to be freed anyway (TEMP and refcnt==1).  This is a
-        * big win on long strings.  It should be a win on short strings if
-        * SvPVX_const(dstr) has to be allocated.  If not, it should not 
-        * slow things down, as SvPVX_const(sstr) would have been freed
-        * soon anyway.
-        * 
-        * We also steal the buffer from a PADTMP (operator target) if it
-        * is â€˜long enough’.  For short strings, a swipe does not help
-        * here, as it causes more malloc calls the next time the target
-        * is used.  Benchmarks show that even if SvPVX_const(dstr) has to
-        * be allocated it is still not worth swiping PADTMPs for short
-        * strings, as the savings here are small.
-        * 
-        * If swiping is not an option, then we see whether it is
-        * worth using copy-on-write.  If the lhs already has a buf-
-        * fer big enough and the string is short, we skip it and fall back
-        * to method 3, since memcpy is faster for short strings than the
-        * later bookkeeping overhead that copy-on-write entails.
-
-        * If the rhs is not a copy-on-write string yet, then we also
-        * consider whether the buffer is too large relative to the string
-        * it holds.  Some operations such as readline allocate a large
-        * buffer in the expectation of reusing it.  But turning such into
-        * a COW buffer is counter-productive because it increases memory
-        * usage by making readline allocate a new large buffer the sec-
-        * ond time round.  So, if the buffer is too large, again, we use
-        * method 3 (copy).
-        * 
-        * Finally, if there is no buffer on the left, or the buffer is too 
-        * small, then we use copy-on-write and make both SVs share the
-        * string buffer.
-        *
-        */
-
-       /* Whichever path we take through the next code, we want this true,
-          and doing it now facilitates the COW check.  */
-       (void)SvPOK_only(dstr);
-
-       if (
+        const STRLEN cur = SvCUR(ssv);
+        const STRLEN len = SvLEN(ssv);
+
+        /*
+         * We have three basic ways to copy the string:
+         *
+         *  1. Swipe
+         *  2. Copy-on-write
+         *  3. Actual copy
+         *
+         * Which we choose is based on various factors.  The following
+         * things are listed in order of speed, fastest to slowest:
+         *  - Swipe
+         *  - Copying a short string
+         *  - Copy-on-write bookkeeping
+         *  - malloc
+         *  - Copying a long string
+         *
+         * We swipe the string (steal the string buffer) if the SV on the
+         * rhs is about to be freed anyway (TEMP and refcnt==1).  This is a
+         * big win on long strings.  It should be a win on short strings if
+         * SvPVX_const(dsv) has to be allocated.  If not, it should not
+         * slow things down, as SvPVX_const(ssv) would have been freed
+         * soon anyway.
+         *
+         * We also steal the buffer from a PADTMP (operator target) if it
+         * is â€˜long enough’.  For short strings, a swipe does not help
+         * here, as it causes more malloc calls the next time the target
+         * is used.  Benchmarks show that even if SvPVX_const(dsv) has to
+         * be allocated it is still not worth swiping PADTMPs for short
+         * strings, as the savings here are small.
+         *
+         * If swiping is not an option, then we see whether it is worth using
+         * copy-on-write.  If the lhs already has a buffer big enough and the
+         * string is short, we skip it and fall back to method 3, since memcpy
+         * is faster for short strings than the later bookkeeping overhead that
+         * copy-on-write entails.
+
+         * If the rhs is not a copy-on-write string yet, then we also
+         * consider whether the buffer is too large relative to the string
+         * it holds.  Some operations such as readline allocate a large
+         * buffer in the expectation of reusing it.  But turning such into
+         * a COW buffer is counter-productive because it increases memory
+         * usage by making readline allocate a new large buffer the sec-
+         * ond time round.  So, if the buffer is too large, again, we use
+         * method 3 (copy).
+         *
+         * Finally, if there is no buffer on the left, or the buffer is too
+         * small, then we use copy-on-write and make both SVs share the
+         * string buffer.
+         *
+         */
+
+        /* Whichever path we take through the next code, we want this true,
+           and doing it now facilitates the COW check.  */
+        (void)SvPOK_only(dsv);
+
+        if (
                  (              /* Either ... */
-                               /* slated for free anyway (and not COW)? */
+                                /* slated for free anyway (and not COW)? */
                     (sflags & (SVs_TEMP|SVf_IsCOW)) == SVs_TEMP
                                 /* or a swipable TARG */
                  || ((sflags &
@@ -4624,70 +4602,82 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags)
                     )
                  ) &&
                  !(sflags & SVf_OOK) &&   /* and not involved in OOK hack? */
-                (!(flags & SV_NOSTEAL)) &&
-                                       /* and we're allowed to steal temps */
-                 SvREFCNT(sstr) == 1 &&   /* and no other references to it? */
+                 (!(flags & SV_NOSTEAL)) &&
+                                        /* and we're allowed to steal temps */
+                 SvREFCNT(ssv) == 1 &&   /* and no other references to it? */
                  len)             /* and really is a string */
-       {       /* Passes the swipe test.  */
-           if (SvPVX_const(dstr))      /* we know that dtype >= SVt_PV */
-               SvPV_free(dstr);
-           SvPV_set(dstr, SvPVX_mutable(sstr));
-           SvLEN_set(dstr, SvLEN(sstr));
-           SvCUR_set(dstr, SvCUR(sstr));
-
-           SvTEMP_off(dstr);
-           (void)SvOK_off(sstr);       /* NOTE: nukes most SvFLAGS on sstr */
-           SvPV_set(sstr, NULL);
-           SvLEN_set(sstr, 0);
-           SvCUR_set(sstr, 0);
-           SvTEMP_off(sstr);
-        }
-       else if (flags & SV_COW_SHARED_HASH_KEYS
-             &&
+        {      /* Passes the swipe test.  */
+            if (SvPVX_const(dsv))      /* we know that dtype >= SVt_PV */
+                SvPV_free(dsv);
+            SvPV_set(dsv, SvPVX_mutable(ssv));
+            SvLEN_set(dsv, SvLEN(ssv));
+            SvCUR_set(dsv, SvCUR(ssv));
+
+            SvTEMP_off(dsv);
+            (void)SvOK_off(ssv);       /* NOTE: nukes most SvFLAGS on ssv */
+            SvPV_set(ssv, NULL);
+            SvLEN_set(ssv, 0);
+            SvCUR_set(ssv, 0);
+            SvTEMP_off(ssv);
+        }
+        /* We must check for SvIsCOW_static() even without
+         * SV_COW_SHARED_HASH_KEYS being set or else we'll break SvIsBOOL()
+         */
+        else if (SvIsCOW_static(ssv)) {
+            if (SvPVX_const(dsv)) {     /* we know that dtype >= SVt_PV */
+                SvPV_free(dsv);
+            }
+            SvPV_set(dsv, SvPVX(ssv));
+            SvLEN_set(dsv, 0);
+            SvCUR_set(dsv, cur);
+            SvFLAGS(dsv) |= (SVf_IsCOW|SVppv_STATIC);
+        }
+        else if (flags & SV_COW_SHARED_HASH_KEYS
+              &&
 #ifdef PERL_COPY_ON_WRITE
-                (sflags & SVf_IsCOW
-                  ? (!len ||
-                       (  (CHECK_COWBUF_THRESHOLD(cur,len) || SvLEN(dstr) < cur+1)
-                         /* If this is a regular (non-hek) COW, only so
-                            many COW "copies" are possible. */
-                      && CowREFCNT(sstr) != SV_COW_REFCNT_MAX  ))
-                  : (  (sflags & CAN_COW_MASK) == CAN_COW_FLAGS
-                    && !(SvFLAGS(dstr) & SVf_BREAK)
+                 (sflags & SVf_IsCOW
+                   ? (!len ||
+                       (  (CHECK_COWBUF_THRESHOLD(cur,len) || SvLEN(dsv) < cur+1)
+                          /* If this is a regular (non-hek) COW, only so
+                             many COW "copies" are possible. */
+                       && CowREFCNT(ssv) != SV_COW_REFCNT_MAX  ))
+                   : (  (sflags & CAN_COW_MASK) == CAN_COW_FLAGS
+                     && !(SvFLAGS(dsv) & SVf_BREAK)
                      && CHECK_COW_THRESHOLD(cur,len) && cur+1 < len
-                     && (CHECK_COWBUF_THRESHOLD(cur,len) || SvLEN(dstr) < cur+1)
-                   ))
+                     && (CHECK_COWBUF_THRESHOLD(cur,len) || SvLEN(dsv) < cur+1)
+                    ))
 #else
-                sflags & SVf_IsCOW
-             && !(SvFLAGS(dstr) & SVf_BREAK)
+                 sflags & SVf_IsCOW
+              && !(SvFLAGS(dsv) & SVf_BREAK)
 #endif
             ) {
             /* Either it's a shared hash key, or it's suitable for
                copy-on-write.  */
 #ifdef DEBUGGING
             if (DEBUG_C_TEST) {
-                PerlIO_printf(Perl_debug_log, "Copy on write: sstr --> dstr\n");
-                sv_dump(sstr);
-                sv_dump(dstr);
+                PerlIO_printf(Perl_debug_log, "Copy on write: ssv --> dsv\n");
+                sv_dump(ssv);
+                sv_dump(dsv);
             }
 #endif
 #ifdef PERL_ANY_COW
             if (!(sflags & SVf_IsCOW)) {
-                    SvIsCOW_on(sstr);
-                   CowREFCNT(sstr) = 0;
+                    SvIsCOW_on(ssv);
+                    CowREFCNT(ssv) = 0;
             }
 #endif
-           if (SvPVX_const(dstr)) {    /* we know that dtype >= SVt_PV */
-               SvPV_free(dstr);
-           }
+            if (SvPVX_const(dsv)) {    /* we know that dtype >= SVt_PV */
+                SvPV_free(dsv);
+            }
 
 #ifdef PERL_ANY_COW
-           if (len) {
-                   if (sflags & SVf_IsCOW) {
-                       sv_buf_to_rw(sstr);
-                   }
-                   CowREFCNT(sstr)++;
-                    SvPV_set(dstr, SvPVX_mutable(sstr));
-                    sv_buf_to_ro(sstr);
+            if (len) {
+                    if (sflags & SVf_IsCOW) {
+                        sv_buf_to_rw(ssv);
+                    }
+                    CowREFCNT(ssv)++;
+                    SvPV_set(dsv, SvPVX_mutable(ssv));
+                    sv_buf_to_ro(ssv);
             } else
 #endif
             {
@@ -4695,59 +4685,75 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags)
                     DEBUG_C(PerlIO_printf(Perl_debug_log,
                                           "Copy on write: Sharing hash\n"));
 
-                   assert (SvTYPE(dstr) >= SVt_PV);
-                    SvPV_set(dstr,
-                            HEK_KEY(share_hek_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sstr)))));
-           }
-           SvLEN_set(dstr, len);
-           SvCUR_set(dstr, cur);
-           SvIsCOW_on(dstr);
-       } else {
-           /* Failed the swipe test, and we cannot do copy-on-write either.
-              Have to copy the string.  */
-           SvGROW(dstr, cur + 1);      /* inlined from sv_setpvn */
-           Move(SvPVX_const(sstr),SvPVX(dstr),cur,char);
-           SvCUR_set(dstr, cur);
-           *SvEND(dstr) = '\0';
-        }
-       if (sflags & SVp_NOK) {
-           SvNV_set(dstr, SvNVX(sstr));
-       }
-       if (sflags & SVp_IOK) {
-           SvIV_set(dstr, SvIVX(sstr));
-           if (sflags & SVf_IVisUV)
-               SvIsUV_on(dstr);
-       }
-       SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_NOK|SVp_NOK|SVf_UTF8);
-       {
-           const MAGIC * const smg = SvVSTRING_mg(sstr);
-           if (smg) {
-               sv_magic(dstr, NULL, PERL_MAGIC_vstring,
-                        smg->mg_ptr, smg->mg_len);
-               SvRMAGICAL_on(dstr);
-           }
-       }
+                    assert (SvTYPE(dsv) >= SVt_PV);
+                    SvPV_set(dsv,
+                             HEK_KEY(share_hek_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(ssv)))));
+            }
+            SvLEN_set(dsv, len);
+            SvCUR_set(dsv, cur);
+            SvIsCOW_on(dsv);
+        } else {
+            /* Failed the swipe test, and we cannot do copy-on-write either.
+               Have to copy the string.  */
+            SvGROW(dsv, cur + 1);      /* inlined from sv_setpvn */
+            Move(SvPVX_const(ssv),SvPVX(dsv),cur,char);
+            SvCUR_set(dsv, cur);
+            *SvEND(dsv) = '\0';
+        }
+        if (sflags & SVp_NOK) {
+            SvNV_set(dsv, SvNVX(ssv));
+            if ((sflags & SVf_NOK) && !(sflags & SVf_POK)) {
+                /* Source was SVf_NOK|SVp_NOK|SVp_POK but not SVf_POK, meaning
+                   a value set as floating point and later stringified, where
+                  the value happens to be one of the few that we know aren't
+                  affected by the numeric locale, hence we can cache the
+                  stringification. Currently that's  +Inf, -Inf and NaN, but
+                  conceivably we might extend this to -9 .. +9 (excluding -0).
+                  So mark destination the same: */
+                SvFLAGS(dsv) &= ~SVf_POK;
+            }
+        }
+        if (sflags & SVp_IOK) {
+            SvIV_set(dsv, SvIVX(ssv));
+            if (sflags & SVf_IVisUV)
+                SvIsUV_on(dsv);
+            if ((sflags & SVf_IOK) && !(sflags & SVf_POK)) {
+                /* Source was SVf_IOK|SVp_IOK|SVp_POK but not SVf_POK, meaning
+                   a value set as an integer and later stringified. So mark
+                   destination the same: */
+                SvFLAGS(dsv) &= ~SVf_POK;
+            }
+        }
+        SvFLAGS(dsv) |= sflags & (SVf_IOK|SVp_IOK|SVf_NOK|SVp_NOK|SVf_UTF8);
+        {
+            const MAGIC * const smg = SvVSTRING_mg(ssv);
+            if (smg) {
+                sv_magic(dsv, NULL, PERL_MAGIC_vstring,
+                         smg->mg_ptr, smg->mg_len);
+                SvRMAGICAL_on(dsv);
+            }
+        }
     }
     else if (sflags & (SVp_IOK|SVp_NOK)) {
-       (void)SvOK_off(dstr);
-       SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_IVisUV|SVf_NOK|SVp_NOK);
-       if (sflags & SVp_IOK) {
-           /* XXXX Do we want to set IsUV for IV(ROK)?  Be extra safe... */
-           SvIV_set(dstr, SvIVX(sstr));
-       }
-       if (sflags & SVp_NOK) {
-           SvNV_set(dstr, SvNVX(sstr));
-       }
+        (void)SvOK_off(dsv);
+        SvFLAGS(dsv) |= sflags & (SVf_IOK|SVp_IOK|SVf_IVisUV|SVf_NOK|SVp_NOK);
+        if (sflags & SVp_IOK) {
+            /* XXXX Do we want to set IsUV for IV(ROK)?  Be extra safe... */
+            SvIV_set(dsv, SvIVX(ssv));
+        }
+        if (sflags & SVp_NOK) {
+            SvNV_set(dsv, SvNVX(ssv));
+        }
     }
     else {
-       if (isGV_with_GP(sstr)) {
-           gv_efullname3(dstr, MUTABLE_GV(sstr), "*");
-       }
-       else
-           (void)SvOK_off(dstr);
-    }
-    if (SvTAINTED(sstr))
-       SvTAINT(dstr);
+        if (isGV_with_GP(ssv)) {
+            gv_efullname3(dsv, MUTABLE_GV(ssv), "*");
+        }
+        else
+            (void)SvOK_off(dsv);
+    }
+    if (SvTAINTED(ssv))
+        SvTAINT(dsv);
 }
 
 
@@ -4811,98 +4817,155 @@ Perl_sv_set_undef(pTHX_ SV *sv)
         SvOK_off(sv);
 }
 
+/*
+=for apidoc sv_set_true
+
+Equivalent to C<sv_setsv(sv, &PL_sv_yes)>, but may be made more
+efficient in the future. Doesn't handle set magic.
+
+The perl equivalent is C<$sv = !0;>.
+
+Introduced in perl 5.35.11.
+
+=cut
+*/
+
+void
+Perl_sv_set_true(pTHX_ SV *sv)
+{
+    PERL_ARGS_ASSERT_SV_SET_TRUE;
+    sv_setsv(sv, &PL_sv_yes);
+}
+
+/*
+=for apidoc sv_set_false
+
+Equivalent to C<sv_setsv(sv, &PL_sv_no)>, but may be made more
+efficient in the future. Doesn't handle set magic.
+
+The perl equivalent is C<$sv = !1;>.
+
+Introduced in perl 5.35.11.
+
+=cut
+*/
 
+void
+Perl_sv_set_false(pTHX_ SV *sv)
+{
+    PERL_ARGS_ASSERT_SV_SET_FALSE;
+    sv_setsv(sv, &PL_sv_no);
+}
 
 /*
-=for apidoc sv_setsv_mg
+=for apidoc sv_set_bool
 
-Like C<sv_setsv>, but also handles 'set' magic.
+Equivalent to C<sv_setsv(sv, bool_val ? &Pl_sv_yes : &PL_sv_no)>, but
+may be made more efficient in the future. Doesn't handle set magic.
+
+The perl equivalent is C<$sv = !!$expr;>.
+
+Introduced in perl 5.35.11.
 
 =cut
 */
 
 void
-Perl_sv_setsv_mg(pTHX_ SV *const dstr, SV *const sstr)
+Perl_sv_set_bool(pTHX_ SV *sv, const bool bool_val)
+{
+    PERL_ARGS_ASSERT_SV_SET_BOOL;
+    sv_setsv(sv, bool_val ? &PL_sv_yes : &PL_sv_no);
+}
+
+
+void
+Perl_sv_setsv_mg(pTHX_ SV *const dsv, SV *const ssv)
 {
     PERL_ARGS_ASSERT_SV_SETSV_MG;
 
-    sv_setsv(dstr,sstr);
-    SvSETMAGIC(dstr);
+    sv_setsv(dsv,ssv);
+    SvSETMAGIC(dsv);
 }
 
 #ifdef PERL_ANY_COW
 #  define SVt_COW SVt_PV
 SV *
-Perl_sv_setsv_cow(pTHX_ SV *dstr, SV *sstr)
+Perl_sv_setsv_cow(pTHX_ SV *dsv, SV *ssv)
 {
-    STRLEN cur = SvCUR(sstr);
-    STRLEN len = SvLEN(sstr);
+    STRLEN cur = SvCUR(ssv);
+    STRLEN len = SvLEN(ssv);
     char *new_pv;
+    U32 new_flags = (SVt_COW|SVf_POK|SVp_POK|SVf_IsCOW);
 #if defined(PERL_DEBUG_READONLY_COW) && defined(PERL_COPY_ON_WRITE)
-    const bool already = cBOOL(SvIsCOW(sstr));
+    const bool already = cBOOL(SvIsCOW(ssv));
 #endif
 
     PERL_ARGS_ASSERT_SV_SETSV_COW;
 #ifdef DEBUGGING
     if (DEBUG_C_TEST) {
-       PerlIO_printf(Perl_debug_log, "Fast copy on write: %p -> %p\n",
-                     (void*)sstr, (void*)dstr);
-       sv_dump(sstr);
-       if (dstr)
-                   sv_dump(dstr);
+        PerlIO_printf(Perl_debug_log, "Fast copy on write: %p -> %p\n",
+                      (void*)ssv, (void*)dsv);
+        sv_dump(ssv);
+        if (dsv)
+                    sv_dump(dsv);
     }
 #endif
-    if (dstr) {
-       if (SvTHINKFIRST(dstr))
-           sv_force_normal_flags(dstr, SV_COW_DROP_PV);
-       else if (SvPVX_const(dstr))
-           Safefree(SvPVX_mutable(dstr));
+    if (dsv) {
+        if (SvTHINKFIRST(dsv))
+            sv_force_normal_flags(dsv, SV_COW_DROP_PV);
+        else if (SvPVX_const(dsv))
+            Safefree(SvPVX_mutable(dsv));
+        SvUPGRADE(dsv, SVt_COW);
     }
     else
-       new_SV(dstr);
-    SvUPGRADE(dstr, SVt_COW);
-
-    assert (SvPOK(sstr));
-    assert (SvPOKp(sstr));
-
-    if (SvIsCOW(sstr)) {
-
-       if (SvLEN(sstr) == 0) {
-           /* source is a COW shared hash key.  */
-           DEBUG_C(PerlIO_printf(Perl_debug_log,
-                                 "Fast copy on write: Sharing hash\n"));
-           new_pv = HEK_KEY(share_hek_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sstr))));
-           goto common_exit;
-       }
-       assert(SvCUR(sstr)+1 < SvLEN(sstr));
-       assert(CowREFCNT(sstr) < SV_COW_REFCNT_MAX);
+        dsv = newSV_type(SVt_COW);
+
+    assert (SvPOK(ssv));
+    assert (SvPOKp(ssv));
+
+    if (SvIsCOW(ssv)) {
+        if (SvIsCOW_shared_hash(ssv)) {
+            /* source is a COW shared hash key.  */
+            DEBUG_C(PerlIO_printf(Perl_debug_log,
+                                  "Fast copy on write: Sharing hash\n"));
+            new_pv = HEK_KEY(share_hek_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(ssv))));
+            goto common_exit;
+        }
+        else if (SvIsCOW_static(ssv)) {
+            /* source is static constant; preserve this */
+            new_pv = SvPVX(ssv);
+            new_flags |= SVppv_STATIC;
+            goto common_exit;
+        }
+        assert(SvCUR(ssv)+1 < SvLEN(ssv));
+        assert(CowREFCNT(ssv) < SV_COW_REFCNT_MAX);
     } else {
-       assert ((SvFLAGS(sstr) & CAN_COW_MASK) == CAN_COW_FLAGS);
-       SvUPGRADE(sstr, SVt_COW);
-       SvIsCOW_on(sstr);
-       DEBUG_C(PerlIO_printf(Perl_debug_log,
-                             "Fast copy on write: Converting sstr to COW\n"));
-       CowREFCNT(sstr) = 0;    
+        assert ((SvFLAGS(ssv) & CAN_COW_MASK) == CAN_COW_FLAGS);
+        SvUPGRADE(ssv, SVt_COW);
+        SvIsCOW_on(ssv);
+        DEBUG_C(PerlIO_printf(Perl_debug_log,
+                              "Fast copy on write: Converting ssv to COW\n"));
+        CowREFCNT(ssv) = 0;
     }
 #  ifdef PERL_DEBUG_READONLY_COW
-    if (already) sv_buf_to_rw(sstr);
+    if (already) sv_buf_to_rw(ssv);
 #  endif
-    CowREFCNT(sstr)++; 
-    new_pv = SvPVX_mutable(sstr);
-    sv_buf_to_ro(sstr);
+    CowREFCNT(ssv)++;
+    new_pv = SvPVX_mutable(ssv);
+    sv_buf_to_ro(ssv);
 
   common_exit:
-    SvPV_set(dstr, new_pv);
-    SvFLAGS(dstr) = (SVt_COW|SVf_POK|SVp_POK|SVf_IsCOW);
-    if (SvUTF8(sstr))
-       SvUTF8_on(dstr);
-    SvLEN_set(dstr, len);
-    SvCUR_set(dstr, cur);
+    SvPV_set(dsv, new_pv);
+    SvFLAGS(dsv) = new_flags;
+    if (SvUTF8(ssv))
+        SvUTF8_on(dsv);
+    SvLEN_set(dsv, len);
+    SvCUR_set(dsv, cur);
 #ifdef DEBUGGING
     if (DEBUG_C_TEST)
-               sv_dump(dstr);
+                sv_dump(dsv);
 #endif
-    return dstr;
+    return dsv;
 }
 #endif
 
@@ -4936,12 +4999,39 @@ Perl_sv_setpv_bufsize(pTHX_ SV *const sv, const STRLEN cur, const STRLEN len)
 }
 
 /*
-=for apidoc sv_setpvn
+=for apidoc            sv_setpv
+=for apidoc_item       sv_setpv_mg
+=for apidoc_item       sv_setpvn
+=for apidoc_item       sv_setpvn_fresh
+=for apidoc_item       sv_setpvn_mg
+=for apidoc_item |void|sv_setpvs|SV* sv|"literal string"
+=for apidoc_item |void|sv_setpvs_mg|SV* sv|"literal string"
+
+These copy a string into the SV C<sv>, making sure it is C<L</SvPOK_only>>.
 
-Copies a string (possibly containing embedded C<NUL> characters) into an SV.
-The C<len> parameter indicates the number of
-bytes to be copied.  If the C<ptr> argument is NULL the SV will become
-undefined.  Does not handle 'set' magic.  See C<L</sv_setpvn_mg>>.
+In the C<pvs> forms, the string must be a C literal string, enclosed in double
+quotes.
+
+In the C<pvn> forms, the first byte of the string is pointed to by C<ptr>, and
+C<len> indicates the number of bytes to be copied, potentially including
+embedded C<NUL> characters.
+
+In the plain C<pv> forms, C<ptr> points to a NUL-terminated C string.  That is,
+it points to the first byte of the string, and the copy proceeds up through the
+first encountered C<NUL> byte.
+
+In the forms that take a C<ptr> argument, if it is NULL, the SV will become
+undefined.
+
+B<The UTF-8 flag is not changed by these functions.>
+
+A terminating NUL byte is guaranteed in the result.
+
+The C<_mg> forms handle 'set' magic; the other forms skip all magic.
+
+C<sv_setpvn_fresh> is a cut-down alternative to C<sv_setpvn>, intended ONLY
+to be used with a fresh sv that has been upgraded to a SVt_PV, SVt_PVIV,
+SVt_PVNV, or SVt_PVMG.
 
 =cut
 */
@@ -4955,17 +5045,17 @@ Perl_sv_setpvn(pTHX_ SV *const sv, const char *const ptr, const STRLEN len)
 
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     if (isGV_with_GP(sv))
-       Perl_croak_no_modify();
+        Perl_croak_no_modify();
     if (!ptr) {
-       (void)SvOK_off(sv);
-       return;
+        (void)SvOK_off(sv);
+        return;
     }
     else {
         /* len is STRLEN which is unsigned, need to copy to signed */
-       const IV iv = len;
-       if (iv < 0)
-           Perl_croak(aTHX_ "panic: sv_setpvn called with negative strlen %"
-                      IVdf, iv);
+        const IV iv = len;
+        if (iv < 0)
+            Perl_croak(aTHX_ "panic: sv_setpvn called with negative strlen %"
+                       IVdf, iv);
     }
     SvUPGRADE(sv, SVt_PV);
 
@@ -4978,14 +5068,6 @@ Perl_sv_setpvn(pTHX_ SV *const sv, const char *const ptr, const STRLEN len)
     if (SvTYPE(sv) == SVt_PVCV) CvAUTOLOAD_off(sv);
 }
 
-/*
-=for apidoc sv_setpvn_mg
-
-Like C<sv_setpvn>, but also handles 'set' magic.
-
-=cut
-*/
-
 void
 Perl_sv_setpvn_mg(pTHX_ SV *const sv, const char *const ptr, const STRLEN len)
 {
@@ -4995,15 +5077,31 @@ Perl_sv_setpvn_mg(pTHX_ SV *const sv, const char *const ptr, const STRLEN len)
     SvSETMAGIC(sv);
 }
 
-/*
-=for apidoc sv_setpv
+void
+Perl_sv_setpvn_fresh(pTHX_ SV *const sv, const char *const ptr, const STRLEN len)
+{
+    char *dptr;
 
-Copies a string into an SV.  The string must be terminated with a C<NUL>
-character, and not contain embeded C<NUL>'s.
-Does not handle 'set' magic.  See C<L</sv_setpv_mg>>.
+    PERL_ARGS_ASSERT_SV_SETPVN_FRESH;
+    assert(SvTYPE(sv) >= SVt_PV && SvTYPE(sv) <= SVt_PVMG);
+    assert(!SvTHINKFIRST(sv));
+    assert(!isGV_with_GP(sv));
 
-=cut
-*/
+    if (ptr) {
+        const IV iv = len;
+        /* len is STRLEN which is unsigned, need to copy to signed */
+        if (iv < 0)
+            Perl_croak(aTHX_ "panic: sv_setpvn_fresh called with negative strlen %"
+                       IVdf, iv);
+
+        dptr = sv_grow_fresh(sv, len + 1);
+        Move(ptr,dptr,len,char);
+        dptr[len] = '\0';
+        SvCUR_set(sv, len);
+        SvPOK_on(sv);
+        SvTAINT(sv);
+    }
+}
 
 void
 Perl_sv_setpv(pTHX_ SV *const sv, const char *const ptr)
@@ -5014,8 +5112,8 @@ Perl_sv_setpv(pTHX_ SV *const sv, const char *const ptr)
 
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     if (!ptr) {
-       (void)SvOK_off(sv);
-       return;
+        (void)SvOK_off(sv);
+        return;
     }
     len = strlen(ptr);
     SvUPGRADE(sv, SVt_PV);
@@ -5028,14 +5126,6 @@ Perl_sv_setpv(pTHX_ SV *const sv, const char *const ptr)
     if (SvTYPE(sv) == SVt_PVCV) CvAUTOLOAD_off(sv);
 }
 
-/*
-=for apidoc sv_setpv_mg
-
-Like C<sv_setpv>, but also handles 'set' magic.
-
-=cut
-*/
-
 void
 Perl_sv_setpv_mg(pTHX_ SV *const sv, const char *const ptr)
 {
@@ -5051,66 +5141,77 @@ Perl_sv_sethek(pTHX_ SV *const sv, const HEK *const hek)
     PERL_ARGS_ASSERT_SV_SETHEK;
 
     if (!hek) {
-       return;
+        return;
     }
 
     if (HEK_LEN(hek) == HEf_SVKEY) {
-       sv_setsv(sv, *(SV**)HEK_KEY(hek));
+        sv_setsv(sv, *(SV**)HEK_KEY(hek));
         return;
     } else {
-       const int flags = HEK_FLAGS(hek);
-       if (flags & HVhek_WASUTF8) {
-           STRLEN utf8_len = HEK_LEN(hek);
-           char *as_utf8 = (char *)bytes_to_utf8((U8*)HEK_KEY(hek), &utf8_len);
-           sv_usepvn_flags(sv, as_utf8, utf8_len, SV_HAS_TRAILING_NUL);
-           SvUTF8_on(sv);
+        const int flags = HEK_FLAGS(hek);
+        if (flags & HVhek_WASUTF8) {
+            STRLEN utf8_len = HEK_LEN(hek);
+            char *as_utf8 = (char *)bytes_to_utf8((U8*)HEK_KEY(hek), &utf8_len);
+            sv_usepvn_flags(sv, as_utf8, utf8_len, SV_HAS_TRAILING_NUL);
+            SvUTF8_on(sv);
             return;
-        } else if (flags & HVhek_UNSHARED) {
-           sv_setpvn(sv, HEK_KEY(hek), HEK_LEN(hek));
-           if (HEK_UTF8(hek))
-               SvUTF8_on(sv);
-           else SvUTF8_off(sv);
+        } else if (flags & HVhek_NOTSHARED) {
+            sv_setpvn(sv, HEK_KEY(hek), HEK_LEN(hek));
+            if (HEK_UTF8(hek))
+                SvUTF8_on(sv);
+            else SvUTF8_off(sv);
             return;
-       }
+        }
         {
-           SV_CHECK_THINKFIRST_COW_DROP(sv);
-           SvUPGRADE(sv, SVt_PV);
-           SvPV_free(sv);
-           SvPV_set(sv,(char *)HEK_KEY(share_hek_hek(hek)));
-           SvCUR_set(sv, HEK_LEN(hek));
-           SvLEN_set(sv, 0);
-           SvIsCOW_on(sv);
-           SvPOK_on(sv);
-           if (HEK_UTF8(hek))
-               SvUTF8_on(sv);
-           else SvUTF8_off(sv);
+            SV_CHECK_THINKFIRST_COW_DROP(sv);
+            SvUPGRADE(sv, SVt_PV);
+            SvPV_free(sv);
+            SvPV_set(sv,(char *)HEK_KEY(share_hek_hek(hek)));
+            SvCUR_set(sv, HEK_LEN(hek));
+            SvLEN_set(sv, 0);
+            SvIsCOW_on(sv);
+            SvPOK_on(sv);
+            if (HEK_UTF8(hek))
+                SvUTF8_on(sv);
+            else SvUTF8_off(sv);
             return;
-       }
+        }
     }
 }
 
 
 /*
-=for apidoc sv_usepvn_flags
+=for apidoc      sv_usepvn
+=for apidoc_item sv_usepvn_flags
+=for apidoc_item sv_usepvn_mg
+
+These tell an SV to use C<ptr> for its string value.  Normally SVs have
+their string stored inside the SV, but these tell the SV to use an
+external string instead.
 
-Tells an SV to use C<ptr> to find its string value.  Normally the
-string is stored inside the SV, but sv_usepvn allows the SV to use an
-outside string.  C<ptr> should point to memory that was allocated
-by L<C<Newx>|perlclib/Memory Management and String Handling>.  It must be
+C<ptr> should point to memory that was allocated
+by L</C<Newx>>.  It must be
 the start of a C<Newx>-ed block of memory, and not a pointer to the
 middle of it (beware of L<C<OOK>|perlguts/Offsets> and copy-on-write),
 and not be from a non-C<Newx> memory allocator like C<malloc>.  The
 string length, C<len>, must be supplied.  By default this function
-will C<Renew> (i.e. realloc, move) the memory pointed to by C<ptr>,
-so that pointer should not be freed or used by the programmer after
-giving it to C<sv_usepvn>, and neither should any pointers from "behind"
-that pointer (e.g. ptr + 1) be used.
+will L</C<Renew>> (i.e. realloc, move) the memory pointed to by C<ptr>,
+so that the pointer should not be freed or used by the programmer after giving
+it to C<sv_usepvn>, and neither should any pointers from "behind" that pointer
+(I<e.g.>, S<C<ptr> + 1>) be used.
+
+In the C<sv_usepvn_flags> form, if S<C<flags & SV_SMAGIC>> is true,
+C<SvSETMAGIC> is called before returning.
+And if S<C<flags & SV_HAS_TRAILING_NUL>> is true, then C<ptr[len]> must be
+C<NUL>, and the realloc will be skipped (I<i.e.>, the buffer is actually at
+least 1 byte longer than C<len>, and already meets the requirements for storing
+in C<SvPVX>).
 
-If S<C<flags & SV_SMAGIC>> is true, will call C<SvSETMAGIC>.  If
-S<C<flags & SV_HAS_TRAILING_NUL>> is true, then C<ptr[len]> must be C<NUL>,
-and the realloc
-will be skipped (i.e. the buffer is actually at least 1 byte longer than
-C<len>, and already meets the requirements for storing in C<SvPVX>).
+C<sv_usepvn> is merely C<sv_usepvn_flags> with C<flags> set to 0, so 'set'
+magic is skipped.
+
+C<sv_usepvn_mg> is merely C<sv_usepvn_flags> with C<flags> set to C<SV_SMAGIC>,
+so 'set' magic is performed.
 
 =for apidoc Amnh||SV_SMAGIC
 =for apidoc Amnh||SV_HAS_TRAILING_NUL
@@ -5128,39 +5229,39 @@ Perl_sv_usepvn_flags(pTHX_ SV *const sv, char *ptr, const STRLEN len, const U32
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     SvUPGRADE(sv, SVt_PV);
     if (!ptr) {
-       (void)SvOK_off(sv);
-       if (flags & SV_SMAGIC)
-           SvSETMAGIC(sv);
-       return;
+        (void)SvOK_off(sv);
+        if (flags & SV_SMAGIC)
+            SvSETMAGIC(sv);
+        return;
     }
     if (SvPVX_const(sv))
-       SvPV_free(sv);
+        SvPV_free(sv);
 
 #ifdef DEBUGGING
     if (flags & SV_HAS_TRAILING_NUL)
-       assert(ptr[len] == '\0');
+        assert(ptr[len] == '\0');
 #endif
 
     allocate = (flags & SV_HAS_TRAILING_NUL)
-       ? len + 1 :
+        ? len + 1 :
 #ifdef Perl_safesysmalloc_size
-       len + 1;
-#else 
-       PERL_STRLEN_ROUNDUP(len + 1);
+        len + 1;
+#else
+        PERL_STRLEN_ROUNDUP(len + 1);
 #endif
     if (flags & SV_HAS_TRAILING_NUL) {
-       /* It's long enough - do nothing.
-          Specifically Perl_newCONSTSUB is relying on this.  */
+        /* It's long enough - do nothing.
+           Specifically Perl_newCONSTSUB is relying on this.  */
     } else {
 #ifdef DEBUGGING
-       /* Force a move to shake out bugs in callers.  */
-       char *new_ptr = (char*)safemalloc(allocate);
-       Copy(ptr, new_ptr, len, char);
-       PoisonFree(ptr,len,char);
-       Safefree(ptr);
-       ptr = new_ptr;
+        /* Force a move to shake out bugs in callers.  */
+        char *new_ptr = (char*)safemalloc(allocate);
+        Copy(ptr, new_ptr, len, char);
+        PoisonFree(ptr,len,char);
+        Safefree(ptr);
+        ptr = new_ptr;
 #else
-       ptr = (char*) saferealloc (ptr, allocate);
+        ptr = (char*) saferealloc (ptr, allocate);
 #endif
     }
 #ifdef Perl_safesysmalloc_size
@@ -5171,12 +5272,12 @@ Perl_sv_usepvn_flags(pTHX_ SV *const sv, char *ptr, const STRLEN len, const U32
     SvCUR_set(sv, len);
     SvPV_set(sv, ptr);
     if (!(flags & SV_HAS_TRAILING_NUL)) {
-       ptr[len] = '\0';
+        ptr[len] = '\0';
     }
     (void)SvPOK_only_UTF8(sv);         /* validate pointer */
     SvTAINT(sv);
     if (flags & SV_SMAGIC)
-       SvSETMAGIC(sv);
+        SvSETMAGIC(sv);
 }
 
 
@@ -5186,9 +5287,10 @@ S_sv_uncow(pTHX_ SV * const sv, const U32 flags)
     assert(SvIsCOW(sv));
     {
 #ifdef PERL_ANY_COW
-       const char * const pvx = SvPVX_const(sv);
-       const STRLEN len = SvLEN(sv);
-       const STRLEN cur = SvCUR(sv);
+        const char * const pvx = SvPVX_const(sv);
+        const STRLEN len = SvLEN(sv);
+        const STRLEN cur = SvCUR(sv);
+        const bool was_shared_hek = SvIsCOW_shared_hash(sv);
 
 #ifdef DEBUGGING
         if (DEBUG_C_TEST) {
@@ -5200,25 +5302,25 @@ S_sv_uncow(pTHX_ SV * const sv, const U32 flags)
 #endif
         SvIsCOW_off(sv);
 # ifdef PERL_COPY_ON_WRITE
-       if (len) {
-           /* Must do this first, since the CowREFCNT uses SvPVX and
-           we need to write to CowREFCNT, or de-RO the whole buffer if we are
-           the only owner left of the buffer. */
-           sv_buf_to_rw(sv); /* NOOP if RO-ing not supported */
-           {
-               U8 cowrefcnt = CowREFCNT(sv);
-               if(cowrefcnt != 0) {
-                   cowrefcnt--;
-                   CowREFCNT(sv) = cowrefcnt;
-                   sv_buf_to_ro(sv);
-                   goto copy_over;
-               }
-           }
-           /* Else we are the only owner of the buffer. */
-        }
-       else
+        if (len) {
+            /* Must do this first, since the CowREFCNT uses SvPVX and
+            we need to write to CowREFCNT, or de-RO the whole buffer if we are
+            the only owner left of the buffer. */
+            sv_buf_to_rw(sv); /* NOOP if RO-ing not supported */
+            {
+                U8 cowrefcnt = CowREFCNT(sv);
+                if(cowrefcnt != 0) {
+                    cowrefcnt--;
+                    CowREFCNT(sv) = cowrefcnt;
+                    sv_buf_to_ro(sv);
+                    goto copy_over;
+                }
+            }
+            /* Else we are the only owner of the buffer. */
+        }
+        else
 # endif
-       {
+        {
             /* This SV doesn't own the buffer, so need to Newx() a new one:  */
             copy_over:
             SvPV_set(sv, NULL);
@@ -5233,29 +5335,29 @@ S_sv_uncow(pTHX_ SV * const sv, const U32 flags)
                 SvCUR_set(sv, cur);
                 *SvEND(sv) = '\0';
             }
-           if (! len) {
-                       unshare_hek(SvSHARED_HEK_FROM_PV(pvx));
-           }
+            if (was_shared_hek) {
+                        unshare_hek(SvSHARED_HEK_FROM_PV(pvx));
+            }
 #ifdef DEBUGGING
             if (DEBUG_C_TEST)
                 sv_dump(sv);
 #endif
-       }
+        }
 #else
-           const char * const pvx = SvPVX_const(sv);
-           const STRLEN len = SvCUR(sv);
-           SvIsCOW_off(sv);
-           SvPV_set(sv, NULL);
-           SvLEN_set(sv, 0);
-           if (flags & SV_COW_DROP_PV) {
-               /* OK, so we don't need to copy our buffer.  */
-               SvPOK_off(sv);
-           } else {
-               SvGROW(sv, len + 1);
-               Move(pvx,SvPVX(sv),len,char);
-               *SvEND(sv) = '\0';
-           }
-           unshare_hek(SvSHARED_HEK_FROM_PV(pvx));
+            const char * const pvx = SvPVX_const(sv);
+            const STRLEN len = SvCUR(sv);
+            SvIsCOW_off(sv);
+            SvPV_set(sv, NULL);
+            SvLEN_set(sv, 0);
+            if (flags & SV_COW_DROP_PV) {
+                /* OK, so we don't need to copy our buffer.  */
+                SvPOK_off(sv);
+            } else {
+                SvGROW(sv, len + 1);
+                Move(pvx,SvPVX(sv),len,char);
+                *SvEND(sv) = '\0';
+            }
+            unshare_hek(SvSHARED_HEK_FROM_PV(pvx));
 #endif
     }
 }
@@ -5292,32 +5394,32 @@ Perl_sv_force_normal_flags(pTHX_ SV *const sv, const U32 flags)
     PERL_ARGS_ASSERT_SV_FORCE_NORMAL_FLAGS;
 
     if (SvREADONLY(sv))
-       Perl_croak_no_modify();
+        Perl_croak_no_modify();
     else if (SvIsCOW(sv) && LIKELY(SvTYPE(sv) != SVt_PVHV))
-       S_sv_uncow(aTHX_ sv, flags);
+        S_sv_uncow(aTHX_ sv, flags);
     if (SvROK(sv))
-       sv_unref_flags(sv, flags);
+        sv_unref_flags(sv, flags);
     else if (SvFAKE(sv) && isGV_with_GP(sv))
-       sv_unglob(sv, flags);
+        sv_unglob(sv, flags);
     else if (SvFAKE(sv) && isREGEXP(sv)) {
-       /* Need to downgrade the REGEXP to a simple(r) scalar. This is analogous
-          to sv_unglob. We only need it here, so inline it.  */
-       const bool islv = SvTYPE(sv) == SVt_PVLV;
-       const svtype new_type =
-         islv ? SVt_NULL : SvMAGIC(sv) || SvSTASH(sv) ? SVt_PVMG : SVt_PV;
-       SV *const temp = newSV_type(new_type);
-       regexp *old_rx_body;
-
-       if (new_type == SVt_PVMG) {
-           SvMAGIC_set(temp, SvMAGIC(sv));
-           SvMAGIC_set(sv, NULL);
-           SvSTASH_set(temp, SvSTASH(sv));
-           SvSTASH_set(sv, NULL);
-       }
-       if (!islv)
+        /* Need to downgrade the REGEXP to a simple(r) scalar. This is analogous
+           to sv_unglob. We only need it here, so inline it.  */
+        const bool islv = SvTYPE(sv) == SVt_PVLV;
+        const svtype new_type =
+          islv ? SVt_NULL : SvMAGIC(sv) || SvSTASH(sv) ? SVt_PVMG : SVt_PV;
+        SV *const temp = newSV_type(new_type);
+        regexp *old_rx_body;
+
+        if (new_type == SVt_PVMG) {
+            SvMAGIC_set(temp, SvMAGIC(sv));
+            SvMAGIC_set(sv, NULL);
+            SvSTASH_set(temp, SvSTASH(sv));
+            SvSTASH_set(sv, NULL);
+        }
+        if (!islv)
             SvCUR_set(temp, SvCUR(sv));
-       /* Remember that SvPVX is in the head, not the body. */
-       assert(ReANY((REGEXP *)sv)->mother_re);
+        /* Remember that SvPVX is in the head, not the body. */
+        assert(ReANY((REGEXP *)sv)->mother_re);
 
         if (islv) {
             /* LV-as-regex has sv->sv_any pointing to an XPVLV body,
@@ -5329,34 +5431,37 @@ Perl_sv_force_normal_flags(pTHX_ SV *const sv, const U32 flags)
         else
             old_rx_body = ReANY((REGEXP *)sv);
 
-       /* Their buffer is already owned by someone else. */
-       if (flags & SV_COW_DROP_PV) {
-           /* SvLEN is already 0.  For SVt_REGEXP, we have a brand new
-              zeroed body.  For SVt_PVLV, we zeroed it above (len field
+        /* Their buffer is already owned by someone else. */
+        if (flags & SV_COW_DROP_PV) {
+            /* SvLEN is already 0.  For SVt_REGEXP, we have a brand new
+               zeroed body.  For SVt_PVLV, we zeroed it above (len field
                a union with xpvlenu_rx) */
-           assert(!SvLEN(islv ? sv : temp));
-           sv->sv_u.svu_pv = 0;
-       }
-       else {
-           sv->sv_u.svu_pv = savepvn(RX_WRAPPED((REGEXP *)sv), SvCUR(sv));
-           SvLEN_set(islv ? sv : temp, SvCUR(sv)+1);
-           SvPOK_on(sv);
-       }
-
-       /* Now swap the rest of the bodies. */
-
-       SvFAKE_off(sv);
-       if (!islv) {
-           SvFLAGS(sv) &= ~SVTYPEMASK;
-           SvFLAGS(sv) |= new_type;
-           SvANY(sv) = SvANY(temp);
-       }
-
-       SvFLAGS(temp) &= ~(SVTYPEMASK);
-       SvFLAGS(temp) |= SVt_REGEXP|SVf_FAKE;
-       SvANY(temp) = old_rx_body;
-
-       SvREFCNT_dec_NN(temp);
+            assert(!SvLEN(islv ? sv : temp));
+            sv->sv_u.svu_pv = 0;
+        }
+        else {
+            sv->sv_u.svu_pv = savepvn(RX_WRAPPED((REGEXP *)sv), SvCUR(sv));
+            SvLEN_set(islv ? sv : temp, SvCUR(sv)+1);
+            SvPOK_on(sv);
+        }
+
+        /* Now swap the rest of the bodies. */
+
+        SvFAKE_off(sv);
+        if (!islv) {
+            SvFLAGS(sv) &= ~SVTYPEMASK;
+            SvFLAGS(sv) |= new_type;
+            SvANY(sv) = SvANY(temp);
+        }
+
+        SvFLAGS(temp) &= ~(SVTYPEMASK);
+        SvFLAGS(temp) |= SVt_REGEXP|SVf_FAKE;
+        SvANY(temp) = old_rx_body;
+
+        /* temp is now rebuilt as a correctly structured SVt_REGEXP, so this
+         * will trigger a call to sv_clear() which will correctly free the
+         * body. */
+        SvREFCNT_dec_NN(temp);
     }
     else if (SvVOK(sv)) sv_unmagic(sv, PERL_MAGIC_vstring);
 }
@@ -5395,32 +5500,32 @@ Perl_sv_chop(pTHX_ SV *const sv, const char *const ptr)
     PERL_ARGS_ASSERT_SV_CHOP;
 
     if (!ptr || !SvPOKp(sv))
-       return;
+        return;
     delta = ptr - SvPVX_const(sv);
     if (!delta) {
-       /* Nothing to do.  */
-       return;
+        /* Nothing to do.  */
+        return;
     }
     max_delta = SvLEN(sv) ? SvLEN(sv) : SvCUR(sv);
     if (delta > max_delta)
-       Perl_croak(aTHX_ "panic: sv_chop ptr=%p, start=%p, end=%p",
-                  ptr, SvPVX_const(sv), SvPVX_const(sv) + max_delta);
+        Perl_croak(aTHX_ "panic: sv_chop ptr=%p, start=%p, end=%p",
+                   ptr, SvPVX_const(sv), SvPVX_const(sv) + max_delta);
     /* SvPVX(sv) may move in SV_CHECK_THINKFIRST(sv), so don't use ptr any more */
     SV_CHECK_THINKFIRST(sv);
     SvPOK_only_UTF8(sv);
 
     if (!SvOOK(sv)) {
-       if (!SvLEN(sv)) { /* make copy of shared string */
-           const char *pvx = SvPVX_const(sv);
-           const STRLEN len = SvCUR(sv);
-           SvGROW(sv, len + 1);
-           Move(pvx,SvPVX(sv),len,char);
-           *SvEND(sv) = '\0';
-       }
-       SvOOK_on(sv);
-       old_delta = 0;
+        if (!SvLEN(sv)) { /* make copy of shared string */
+            const char *pvx = SvPVX_const(sv);
+            const STRLEN len = SvCUR(sv);
+            SvGROW(sv, len + 1);
+            Move(pvx,SvPVX(sv),len,char);
+            *SvEND(sv) = '\0';
+        }
+        SvOOK_on(sv);
+        old_delta = 0;
     } else {
-       SvOOK_offset(sv, old_delta);
+        SvOOK_offset(sv, old_delta);
     }
     SvLEN_set(sv, SvLEN(sv) - delta);
     SvCUR_set(sv, SvCUR(sv) - delta);
@@ -5433,7 +5538,7 @@ Perl_sv_chop(pTHX_ SV *const sv, const char *const ptr)
        bytes, except for the part holding the new offset of course. */
     evacn = delta;
     if (old_delta)
-       evacn += (old_delta < 0x100 ? 1 : 1 + sizeof(STRLEN));
+        evacn += (old_delta < 0x100 ? 1 : 1 + sizeof(STRLEN));
     assert(evacn);
     assert(evacn <= delta + old_delta);
     evacp = p - evacn;
@@ -5448,46 +5553,56 @@ Perl_sv_chop(pTHX_ SV *const sv, const char *const ptr)
      * to that, using as many bytes as a STRLEN occupies.  Thus it overwrites a
      * portion of the chopped part of the string */
     if (delta < 0x100) {
-       *--p = (U8) delta;
+        *--p = (U8) delta;
     } else {
-       *--p = 0;
-       p -= sizeof(STRLEN);
-       Copy((U8*)&delta, p, sizeof(STRLEN), U8);
+        *--p = 0;
+        p -= sizeof(STRLEN);
+        Copy((U8*)&delta, p, sizeof(STRLEN), U8);
     }
 
 #ifdef DEBUGGING
     /* Fill the preceding buffer with sentinals to verify that no-one is
        using it.  */
     while (p > evacp) {
-       --p;
-       *p = (U8)PTR2UV(p);
+        --p;
+        *p = (U8)PTR2UV(p);
     }
 #endif
 }
 
 /*
 =for apidoc sv_catpvn
+=for apidoc_item sv_catpvn_flags
+=for apidoc_item sv_catpvn_mg
+=for apidoc_item sv_catpvn_nomg
+
+These concatenate the C<len> bytes of the string beginning at C<ptr> onto the
+end of the string which is in C<dsv>.  The caller must make sure C<ptr>
+contains at least C<len> bytes.
+
+For all but C<sv_catpvn_flags>, the string appended is assumed to be valid
+UTF-8 if the SV has the UTF-8 status set, and a string of bytes otherwise.
 
-Concatenates the string onto the end of the string which is in the SV.
-C<len> indicates number of bytes to copy.  If the SV has the UTF-8
-status set, then the bytes appended should be valid UTF-8.
-Handles 'get' magic, but not 'set' magic.  See C<L</sv_catpvn_mg>>.
+They differ in that:
 
-=for apidoc sv_catpvn_flags
+C<sv_catpvn_mg> performs both 'get' and 'set' magic on C<dsv>.
 
-Concatenates the string onto the end of the string which is in the SV.  The
-C<len> indicates number of bytes to copy.
+C<sv_catpvn> performs only 'get' magic.
 
-By default, the string appended is assumed to be valid UTF-8 if the SV has
-the UTF-8 status set, and a string of bytes otherwise.  One can force the
-appended string to be interpreted as UTF-8 by supplying the C<SV_CATUTF8>
-flag, and as bytes by supplying the C<SV_CATBYTES> flag; the SV or the
-string appended will be upgraded to UTF-8 if necessary.
+C<sv_catpvn_nomg> skips all magic.
 
-If C<flags> has the C<SV_SMAGIC> bit set, will
-C<mg_set> on C<dsv> afterwards if appropriate.
-C<sv_catpvn> and C<sv_catpvn_nomg> are implemented
-in terms of this function.
+C<sv_catpvn_flags> has an extra C<flags> parameter which allows you to specify
+any combination of magic handling (using C<SV_GMAGIC> and/or C<SV_SMAGIC>) and
+to also override the UTF-8 handling.  By supplying the C<SV_CATBYTES> flag, the
+appended string is interpreted as plain bytes; by supplying instead the
+C<SV_CATUTF8> flag, it will be interpreted as UTF-8, and the C<dsv> will be
+upgraded to UTF-8 if necessary.
+
+C<sv_catpvn>, C<sv_catpvn_mg>, and C<sv_catpvn_nomg> are implemented
+in terms of C<sv_catpvn_flags>.
+
+=for apidoc Amnh||SV_CATUTF8
+=for apidoc Amnh||SV_CATBYTES
 
 =cut
 */
@@ -5503,72 +5618,81 @@ Perl_sv_catpvn_flags(pTHX_ SV *const dsv, const char *sstr, const STRLEN slen, c
 
     if (!(flags & SV_CATBYTES) || !SvUTF8(dsv)) {
       if (flags & SV_CATUTF8 && !SvUTF8(dsv)) {
-        sv_utf8_upgrade_flags_grow(dsv, 0, slen + 1);
-        dlen = SvCUR(dsv);
+         sv_utf8_upgrade_flags_grow(dsv, 0, slen + 1);
+         dlen = SvCUR(dsv);
       }
       else SvGROW(dsv, dlen + slen + 3);
       if (sstr == dstr)
-       sstr = SvPVX_const(dsv);
+        sstr = SvPVX_const(dsv);
       Move(sstr, SvPVX(dsv) + dlen, slen, char);
       SvCUR_set(dsv, SvCUR(dsv) + slen);
     }
     else {
-       /* We inline bytes_to_utf8, to avoid an extra malloc. */
-       const char * const send = sstr + slen;
-       U8 *d;
+        /* We inline bytes_to_utf8, to avoid an extra malloc. */
+        const char * const send = sstr + slen;
+        U8 *d;
 
-       /* Something this code does not account for, which I think is
-          impossible; it would require the same pv to be treated as
-          bytes *and* utf8, which would indicate a bug elsewhere. */
-       assert(sstr != dstr);
+        /* Something this code does not account for, which I think is
+           impossible; it would require the same pv to be treated as
+           bytes *and* utf8, which would indicate a bug elsewhere. */
+        assert(sstr != dstr);
 
-       SvGROW(dsv, dlen + slen * 2 + 3);
-       d = (U8 *)SvPVX(dsv) + dlen;
+        SvGROW(dsv, dlen + slen * 2 + 3);
+        d = (U8 *)SvPVX(dsv) + dlen;
 
-       while (sstr < send) {
+        while (sstr < send) {
             append_utf8_from_native_byte(*sstr, &d);
-           sstr++;
-       }
-       SvCUR_set(dsv, d-(const U8 *)SvPVX(dsv));
+            sstr++;
+        }
+        SvCUR_set(dsv, d-(const U8 *)SvPVX(dsv));
     }
     *SvEND(dsv) = '\0';
     (void)SvPOK_only_UTF8(dsv);                /* validate pointer */
     SvTAINT(dsv);
     if (flags & SV_SMAGIC)
-       SvSETMAGIC(dsv);
+        SvSETMAGIC(dsv);
 }
 
 /*
 =for apidoc sv_catsv
+=for apidoc_item sv_catsv_flags
+=for apidoc_item sv_catsv_mg
+=for apidoc_item sv_catsv_nomg
+
+These concatenate the string from SV C<sstr> onto the end of the string in SV
+C<dsv>.  If C<sstr> is null, these are no-ops; otherwise only C<dsv> is
+modified.
 
-Concatenates the string from SV C<ssv> onto the end of the string in SV
-C<dsv>.  If C<ssv> is null, does nothing; otherwise modifies only C<dsv>.
-Handles 'get' magic on both SVs, but no 'set' magic.  See C<L</sv_catsv_mg>>
-and C<L</sv_catsv_nomg>>.
+They differ only in what magic they perform:
 
-=for apidoc sv_catsv_flags
+C<sv_catsv_mg> performs 'get' magic on both SVs before the copy, and 'set' magic
+on C<dsv> afterwards.
 
-Concatenates the string from SV C<ssv> onto the end of the string in SV
-C<dsv>.  If C<ssv> is null, does nothing; otherwise modifies only C<dsv>.
-If C<flags> has the C<SV_GMAGIC> bit set, will call C<mg_get> on both SVs if
-appropriate.  If C<flags> has the C<SV_SMAGIC> bit set, C<mg_set> will be called on
-the modified SV afterward, if appropriate.  C<sv_catsv>, C<sv_catsv_nomg>,
-and C<sv_catsv_mg> are implemented in terms of this function.
+C<sv_catsv> performs just 'get' magic, on both SVs.
+
+C<sv_catsv_nomg> skips all magic.
+
+C<sv_catsv_flags> has an extra C<flags> parameter which allows you to use
+C<SV_GMAGIC> and/or C<SV_SMAGIC> to specify any combination of magic handling
+(although either both or neither SV will have 'get' magic applied to it.)
+
+C<sv_catsv>, C<sv_catsv_mg>, and C<sv_catsv_nomg> are implemented
+in terms of C<sv_catsv_flags>.
 
 =cut */
 
 void
-Perl_sv_catsv_flags(pTHX_ SV *const dsv, SV *const ssv, const I32 flags)
+Perl_sv_catsv_flags(pTHX_ SV *const dsv, SV *const sstr, const I32 flags)
 {
     PERL_ARGS_ASSERT_SV_CATSV_FLAGS;
 
-    if (ssv) {
-       STRLEN slen;
-       const char *spv = SvPV_flags_const(ssv, slen, flags);
+    if (sstr) {
+        STRLEN slen;
+        const char *spv = SvPV_flags_const(sstr, slen, flags);
         if (flags & SV_GMAGIC)
                 SvGETMAGIC(dsv);
         sv_catpvn_flags(dsv, spv, slen,
-                           DO_UTF8(ssv) ? SV_CATUTF8 : SV_CATBYTES);
+                            DO_UTF8(sstr) ? SV_CATUTF8 : SV_CATBYTES);
         if (flags & SV_SMAGIC)
                 SvSETMAGIC(dsv);
     }
@@ -5576,17 +5700,35 @@ Perl_sv_catsv_flags(pTHX_ SV *const dsv, SV *const ssv, const I32 flags)
 
 /*
 =for apidoc sv_catpv
+=for apidoc_item sv_catpv_flags
+=for apidoc_item sv_catpv_mg
+=for apidoc_item sv_catpv_nomg
 
-Concatenates the C<NUL>-terminated string onto the end of the string which is
-in the SV.
+These concatenate the C<NUL>-terminated string C<sstr> onto the end of the
+string which is in the SV.
 If the SV has the UTF-8 status set, then the bytes appended should be
-valid UTF-8.  Handles 'get' magic, but not 'set' magic.  See
-C<L</sv_catpv_mg>>.
+valid UTF-8.
 
-=cut */
+They differ only in how they handle magic:
+
+C<sv_catpv_mg> performs both 'get' and 'set' magic.
+
+C<sv_catpv> performs only 'get' magic.
+
+C<sv_catpv_nomg> skips all magic.
+
+C<sv_catpv_flags> has an extra C<flags> parameter which allows you to specify
+any combination of magic handling (using C<SV_GMAGIC> and/or C<SV_SMAGIC>), and
+to also override the UTF-8 handling.  By supplying the C<SV_CATUTF8> flag, the
+appended string is forced to be interpreted as UTF-8; by supplying instead the
+C<SV_CATBYTES> flag, it will be interpreted as just bytes.  Either the SV or
+the string appended will be upgraded to UTF-8 if necessary.
+
+=cut
+*/
 
 void
-Perl_sv_catpv(pTHX_ SV *const sv, const char *ptr)
+Perl_sv_catpv(pTHX_ SV *const dsv, const char *sstr)
 {
     STRLEN len;
     STRLEN tlen;
@@ -5594,53 +5736,33 @@ Perl_sv_catpv(pTHX_ SV *const sv, const char *ptr)
 
     PERL_ARGS_ASSERT_SV_CATPV;
 
-    if (!ptr)
-       return;
-    junk = SvPV_force(sv, tlen);
-    len = strlen(ptr);
-    SvGROW(sv, tlen + len + 1);
-    if (ptr == junk)
-       ptr = SvPVX_const(sv);
-    Move(ptr,SvPVX(sv)+tlen,len+1,char);
-    SvCUR_set(sv, SvCUR(sv) + len);
-    (void)SvPOK_only_UTF8(sv);         /* validate pointer */
-    SvTAINT(sv);
+    if (!sstr)
+        return;
+    junk = SvPV_force(dsv, tlen);
+    len = strlen(sstr);
+    SvGROW(dsv, tlen + len + 1);
+    if (sstr == junk)
+        sstr = SvPVX_const(dsv);
+    Move(sstr,SvPVX(dsv)+tlen,len+1,char);
+    SvCUR_set(dsv, SvCUR(dsv) + len);
+    (void)SvPOK_only_UTF8(dsv);                /* validate pointer */
+    SvTAINT(dsv);
 }
 
-/*
-=for apidoc sv_catpv_flags
-
-Concatenates the C<NUL>-terminated string onto the end of the string which is
-in the SV.
-If the SV has the UTF-8 status set, then the bytes appended should
-be valid UTF-8.  If C<flags> has the C<SV_SMAGIC> bit set, will C<mg_set>
-on the modified SV if appropriate.
-
-=cut
-*/
-
 void
-Perl_sv_catpv_flags(pTHX_ SV *dstr, const char *sstr, const I32 flags)
+Perl_sv_catpv_flags(pTHX_ SV *dsv, const char *sstr, const I32 flags)
 {
     PERL_ARGS_ASSERT_SV_CATPV_FLAGS;
-    sv_catpvn_flags(dstr, sstr, strlen(sstr), flags);
+    sv_catpvn_flags(dsv, sstr, strlen(sstr), flags);
 }
 
-/*
-=for apidoc sv_catpv_mg
-
-Like C<sv_catpv>, but also handles 'set' magic.
-
-=cut
-*/
-
 void
-Perl_sv_catpv_mg(pTHX_ SV *const sv, const char *const ptr)
+Perl_sv_catpv_mg(pTHX_ SV *const dsv, const char *const sstr)
 {
     PERL_ARGS_ASSERT_SV_CATPV_MG;
 
-    sv_catpv(sv,ptr);
-    SvSETMAGIC(sv);
+    sv_catpv(dsv,sstr);
+    SvSETMAGIC(dsv);
 }
 
 /*
@@ -5665,9 +5787,11 @@ Perl_newSV(pTHX_ const STRLEN len)
 {
     SV *sv;
 
-    new_SV(sv);
-    if (len) {
-       sv_grow(sv, len + 1);
+    if (!len)
+        new_SV(sv);
+    else {
+        sv = newSV_type(SVt_PV);
+        sv_grow_fresh(sv, len + 1);
     }
     return sv;
 }
@@ -5690,8 +5814,8 @@ to contain an SV* and is stored as-is with its C<REFCNT> incremented.
 
 =cut
 */
-MAGIC *        
-Perl_sv_magicext(pTHX_ SV *const sv, SV *const obj, const int how, 
+MAGIC *
+Perl_sv_magicext(pTHX_ SV *const sv, SV *const obj, const int how,
                 const MGVTBL *const vtable, const char *const name, const I32 namlen)
 {
     MAGIC* mg;
@@ -5713,20 +5837,20 @@ Perl_sv_magicext(pTHX_ SV *const sv, SV *const obj, const int how,
 
     */
     if (!obj || obj == sv ||
-       how == PERL_MAGIC_arylen ||
+        how == PERL_MAGIC_arylen ||
         how == PERL_MAGIC_regdata ||
         how == PERL_MAGIC_regdatum ||
         how == PERL_MAGIC_symtab ||
-       (SvTYPE(obj) == SVt_PVGV &&
-           (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)))
+        (SvTYPE(obj) == SVt_PVGV &&
+            (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;
+        mg->mg_obj = obj;
     }
     else {
-       mg->mg_obj = SvREFCNT_inc_simple(obj);
-       mg->mg_flags |= MGf_REFCOUNTED;
+        mg->mg_obj = SvREFCNT_inc_simple(obj);
+        mg->mg_flags |= MGf_REFCOUNTED;
     }
 
     /* Normal self-ties simply pass a null object, and instead of
@@ -5746,16 +5870,16 @@ Perl_sv_magicext(pTHX_ SV *const sv, SV *const obj, const int how,
     mg->mg_type = how;
     mg->mg_len = namlen;
     if (name) {
-       if (namlen > 0)
-           mg->mg_ptr = savepvn(name, namlen);
-       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 aberation 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;
+        if (namlen > 0)
+            mg->mg_ptr = savepvn(name, namlen);
+        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 aberration 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;
 
@@ -5768,13 +5892,13 @@ Perl_sv_magicext_mglob(pTHX_ SV *sv)
 {
     PERL_ARGS_ASSERT_SV_MAGICEXT_MGLOB;
     if (SvTYPE(sv) == SVt_PVLV && LvTYPE(sv) == 'y') {
-       /* This sv is only a delegate.  //g magic must be attached to
-          its target. */
-       vivify_defelem(sv);
-       sv = LvTARG(sv);
+        /* This sv is only a delegate.  //g magic must be attached to
+           its target. */
+        vivify_defelem(sv);
+        sv = LvTARG(sv);
     }
     return sv_magicext(sv, NULL, PERL_MAGIC_regex_global,
-                      &PL_vtbl_mglob, 0, 0);
+                       &PL_vtbl_mglob, 0, 0);
 }
 
 /*
@@ -5805,10 +5929,10 @@ Perl_sv_magic(pTHX_ SV *const sv, SV *const obj, const int how,
     PERL_ARGS_ASSERT_SV_MAGIC;
 
     if (how < 0 || (unsigned)how >= C_ARRAY_LENGTH(PL_magic_data)
-       || ((flags = PL_magic_data[how]),
-           (vtable_index = flags & PERL_MAGIC_VTABLE_MASK)
-           > magic_vtable_max))
-       Perl_croak(aTHX_ "Don't know how to handle magic of type \\%o", how);
+        || ((flags = PL_magic_data[how]),
+            (vtable_index = flags & PERL_MAGIC_VTABLE_MASK)
+            > magic_vtable_max))
+        Perl_croak(aTHX_ "Don't know how to handle magic of type \\%o", how);
 
     /* PERL_MAGIC_ext is reserved for use by extensions not perl internals.
        Useful for attaching extension internal data to perl vars.
@@ -5816,35 +5940,25 @@ Perl_sv_magic(pTHX_ SV *const sv, SV *const obj, const int how,
        etc holding private data from one are passed to another. */
 
     vtable = (vtable_index == magic_vtable_max)
-       ? NULL : PL_magic_vtables + vtable_index;
+        ? NULL : PL_magic_vtables + vtable_index;
 
     if (SvREADONLY(sv)) {
-       if (
-           !PERL_MAGIC_TYPE_READONLY_ACCEPTABLE(how)
-          )
-       {
-           Perl_croak_no_modify();
-       }
+        if (
+            !PERL_MAGIC_TYPE_READONLY_ACCEPTABLE(how)
+           )
+        {
+            Perl_croak_no_modify();
+        }
     }
     if (SvMAGICAL(sv) || (how == PERL_MAGIC_taint && SvTYPE(sv) >= SVt_PVMG)) {
-       if (SvMAGIC(sv) && (mg = mg_find(sv, how))) {
-           /* sv_magic() refuses to add a magic of the same 'how' as an
-              existing one
-            */
-           if (how == PERL_MAGIC_taint)
-               mg->mg_len |= 1;
-           return;
-       }
-    }
-
-    /* Force pos to be stored as characters, not bytes. */
-    if (SvMAGICAL(sv) && DO_UTF8(sv)
-      && (mg = mg_find(sv, PERL_MAGIC_regex_global))
-      && mg->mg_len != -1
-      && mg->mg_flags & MGf_BYTES) {
-       mg->mg_len = (SSize_t)sv_pos_b2u_flags(sv, (STRLEN)mg->mg_len,
-                                              SV_CONST_RETURN);
-       mg->mg_flags &= ~MGf_BYTES;
+        if (SvMAGIC(sv) && (mg = mg_find(sv, how))) {
+            /* sv_magic() refuses to add a magic of the same 'how' as an
+               existing one
+             */
+            if (how == PERL_MAGIC_taint)
+                mg->mg_len |= 1;
+            return;
+        }
     }
 
     /* Rest of work is done else where */
@@ -5852,17 +5966,17 @@ Perl_sv_magic(pTHX_ SV *const sv, SV *const obj, const int how,
 
     switch (how) {
     case PERL_MAGIC_taint:
-       mg->mg_len = 1;
-       break;
+        mg->mg_len = 1;
+        break;
     case PERL_MAGIC_ext:
     case PERL_MAGIC_dbfile:
-       SvRMAGICAL_on(sv);
-       break;
+        SvRMAGICAL_on(sv);
+        break;
     }
 }
 
 static int
-S_sv_unmagicext_flags(pTHX_ SV *const sv, const int type, MGVTBL *vtbl, const U32 flags)
+S_sv_unmagicext_flags(pTHX_ SV *const sv, const int type, const MGVTBL *vtbl, const U32 flags)
 {
     MAGIC* mg;
     MAGIC** mgp;
@@ -5870,35 +5984,35 @@ S_sv_unmagicext_flags(pTHX_ SV *const sv, const int type, MGVTBL *vtbl, const U3
     assert(flags <= 1);
 
     if (SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv))
-       return 0;
+        return 0;
     mgp = &(((XPVMG*) SvANY(sv))->xmg_u.xmg_magic);
     for (mg = *mgp; mg; mg = *mgp) {
-       const MGVTBL* const virt = mg->mg_virtual;
-       if (mg->mg_type == type && (!flags || virt == vtbl)) {
-           *mgp = mg->mg_moremagic;
-           if (virt && virt->svt_free)
-               virt->svt_free(aTHX_ sv, mg);
-           if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
-               if (mg->mg_len > 0)
-                   Safefree(mg->mg_ptr);
-               else if (mg->mg_len == HEf_SVKEY)
-                   SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr));
-               else if (mg->mg_type == PERL_MAGIC_utf8)
-                   Safefree(mg->mg_ptr);
+        const MGVTBL* const virt = mg->mg_virtual;
+        if (mg->mg_type == type && (!flags || virt == vtbl)) {
+            *mgp = mg->mg_moremagic;
+            if (virt && virt->svt_free)
+                virt->svt_free(aTHX_ sv, mg);
+            if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
+                if (mg->mg_len > 0)
+                    Safefree(mg->mg_ptr);
+                else if (mg->mg_len == HEf_SVKEY)
+                    SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr));
+                else if (mg->mg_type == PERL_MAGIC_utf8)
+                    Safefree(mg->mg_ptr);
             }
-           if (mg->mg_flags & MGf_REFCOUNTED)
-               SvREFCNT_dec(mg->mg_obj);
-           Safefree(mg);
-       }
-       else
-           mgp = &mg->mg_moremagic;
+            if (mg->mg_flags & MGf_REFCOUNTED)
+                SvREFCNT_dec(mg->mg_obj);
+            Safefree(mg);
+        }
+        else
+            mgp = &mg->mg_moremagic;
     }
     if (SvMAGIC(sv)) {
-       if (SvMAGICAL(sv))      /* if we're under save_magic, wait for restore_magic; */
-           mg_magical(sv);     /*    else fix the flags now */
+        if (SvMAGICAL(sv))     /* if we're under save_magic, wait for restore_magic; */
+            mg_magical(sv);    /*    else fix the flags now */
     }
     else
-       SvMAGICAL_off(sv);
+        SvMAGICAL_off(sv);
 
     return 0;
 }
@@ -5927,7 +6041,7 @@ Removes all magic of type C<type> with the specified C<vtbl> from an SV.
 */
 
 int
-Perl_sv_unmagicext(pTHX_ SV *const sv, const int type, MGVTBL *vtbl)
+Perl_sv_unmagicext(pTHX_ SV *const sv, const int type, const MGVTBL *vtbl)
 {
     PERL_ARGS_ASSERT_SV_UNMAGICEXT;
     return S_sv_unmagicext_flags(aTHX_ sv, type, vtbl, 1);
@@ -5954,12 +6068,12 @@ Perl_sv_rvweaken(pTHX_ SV *const sv)
     PERL_ARGS_ASSERT_SV_RVWEAKEN;
 
     if (!SvOK(sv))  /* let undefs pass */
-       return sv;
+        return sv;
     if (!SvROK(sv))
-       Perl_croak(aTHX_ "Can't weaken a nonreference");
+        Perl_croak(aTHX_ "Can't weaken a nonreference");
     else if (SvWEAKREF(sv)) {
-       Perl_ck_warner(aTHX_ packWARN(WARN_MISC), "Reference is already weak");
-       return sv;
+        Perl_ck_warner(aTHX_ packWARN(WARN_MISC), "Reference is already weak");
+        return sv;
     }
     else if (SvREADONLY(sv)) croak_no_modify();
     tsv = SvRV(sv);
@@ -6032,7 +6146,7 @@ Perl_sv_get_backrefs(SV *const sv)
     /* find slot to store array or singleton backref */
 
     if (SvTYPE(sv) == SVt_PVHV) {
-        if (SvOOK(sv)) {
+        if (HvHasAUX(sv)) {
             struct xpvhv_aux * const iter = HvAUX((HV *)sv);
             backrefs = (SV *)iter->xhv_backreferences;
         }
@@ -6083,36 +6197,36 @@ Perl_sv_add_backref(pTHX_ SV *const tsv, SV *const sv)
     /* find slot to store array or singleton backref */
 
     if (SvTYPE(tsv) == SVt_PVHV) {
-       svp = (SV**)Perl_hv_backreferences_p(aTHX_ MUTABLE_HV(tsv));
+        svp = (SV**)Perl_hv_backreferences_p(aTHX_ MUTABLE_HV(tsv));
     } else {
         if (SvMAGICAL(tsv))
             mg = mg_find(tsv, PERL_MAGIC_backref);
-       if (!mg)
+        if (!mg)
             mg = sv_magicext(tsv, NULL, PERL_MAGIC_backref, &PL_vtbl_backref, NULL, 0);
-       svp = &(mg->mg_obj);
+        svp = &(mg->mg_obj);
     }
 
     /* create or retrieve the array */
 
     if (   (!*svp && SvTYPE(sv) == SVt_PVAV)
-       || (*svp && SvTYPE(*svp) != SVt_PVAV)
+        || (*svp && SvTYPE(*svp) != SVt_PVAV)
     ) {
-       /* create array */
-       if (mg)
-           mg->mg_flags |= MGf_REFCOUNTED;
-       av = newAV();
-       AvREAL_off(av);
-       SvREFCNT_inc_simple_void_NN(av);
-       /* av now has a refcnt of 2; see discussion above */
-       av_extend(av, *svp ? 2 : 1);
-       if (*svp) {
-           /* move single existing backref to the array */
-           AvARRAY(av)[++AvFILLp(av)] = *svp; /* av_push() */
-       }
-       *svp = (SV*)av;
+        /* create array */
+        if (mg)
+            mg->mg_flags |= MGf_REFCOUNTED;
+        av = newAV();
+        AvREAL_off(av);
+        SvREFCNT_inc_simple_void_NN(av);
+        /* av now has a refcnt of 2; see discussion above */
+        av_extend(av, *svp ? 2 : 1);
+        if (*svp) {
+            /* move single existing backref to the array */
+            AvARRAY(av)[++AvFILLp(av)] = *svp; /* av_push() */
+        }
+        *svp = (SV*)av;
     }
     else {
-       av = MUTABLE_AV(*svp);
+        av = MUTABLE_AV(*svp);
         if (!av) {
             /* optimisation: store single backref directly in HvAUX or mg_obj */
             *svp = sv;
@@ -6139,111 +6253,111 @@ Perl_sv_del_backref(pTHX_ SV *const tsv, SV *const sv)
     PERL_ARGS_ASSERT_SV_DEL_BACKREF;
 
     if (SvTYPE(tsv) == SVt_PVHV) {
-       if (SvOOK(tsv))
-           svp = (SV**)Perl_hv_backreferences_p(aTHX_ MUTABLE_HV(tsv));
+        if (HvHasAUX(tsv))
+            svp = (SV**)Perl_hv_backreferences_p(aTHX_ MUTABLE_HV(tsv));
     }
     else if (SvIS_FREED(tsv) && PL_phase == PERL_PHASE_DESTRUCT) {
-       /* It's possible for the the last (strong) reference to tsv to have
-          become freed *before* the last thing holding a weak reference.
-          If both survive longer than the backreferences array, then when
-          the referent's reference count drops to 0 and it is freed, it's
-          not able to chase the backreferences, so they aren't NULLed.
-
-          For example, a CV holds a weak reference to its stash. If both the
-          CV and the stash survive longer than the backreferences array,
-          and the CV gets picked for the SvBREAK() treatment first,
-          *and* it turns out that the stash is only being kept alive because
-          of an our variable in the pad of the CV, then midway during CV
-          destruction the stash gets freed, but CvSTASH() isn't set to NULL.
-          It ends up pointing to the freed HV. Hence it's chased in here, and
-          if this block wasn't here, it would hit the !svp panic just below.
-
-          I don't believe that "better" destruction ordering is going to help
-          here - during global destruction there's always going to be the
-          chance that something goes out of order. We've tried to make it
-          foolproof before, and it only resulted in evolutionary pressure on
-          fools. Which made us look foolish for our hubris. :-(
-       */
-       return;
+        /* It's possible for the last (strong) reference to tsv to have
+           become freed *before* the last thing holding a weak reference.
+           If both survive longer than the backreferences array, then when
+           the referent's reference count drops to 0 and it is freed, it's
+           not able to chase the backreferences, so they aren't NULLed.
+
+           For example, a CV holds a weak reference to its stash. If both the
+           CV and the stash survive longer than the backreferences array,
+           and the CV gets picked for the SvBREAK() treatment first,
+           *and* it turns out that the stash is only being kept alive because
+           of an our variable in the pad of the CV, then midway during CV
+           destruction the stash gets freed, but CvSTASH() isn't set to NULL.
+           It ends up pointing to the freed HV. Hence it's chased in here, and
+           if this block wasn't here, it would hit the !svp panic just below.
+
+           I don't believe that "better" destruction ordering is going to help
+           here - during global destruction there's always going to be the
+           chance that something goes out of order. We've tried to make it
+           foolproof before, and it only resulted in evolutionary pressure on
+           fools. Which made us look foolish for our hubris. :-(
+        */
+        return;
     }
     else {
-       MAGIC *const mg
-           = SvMAGICAL(tsv) ? mg_find(tsv, PERL_MAGIC_backref) : NULL;
-       svp =  mg ? &(mg->mg_obj) : NULL;
+        MAGIC *const mg
+            = SvMAGICAL(tsv) ? mg_find(tsv, PERL_MAGIC_backref) : NULL;
+        svp =  mg ? &(mg->mg_obj) : NULL;
     }
 
     if (!svp)
-       Perl_croak(aTHX_ "panic: del_backref, svp=0");
+        Perl_croak(aTHX_ "panic: del_backref, svp=0");
     if (!*svp) {
-       /* It's possible that sv is being freed recursively part way through the
-          freeing of tsv. If this happens, the backreferences array of tsv has
-          already been freed, and so svp will be NULL. If this is the case,
-          we should not panic. Instead, nothing needs doing, so return.  */
-       if (PL_phase == PERL_PHASE_DESTRUCT && SvREFCNT(tsv) == 0)
-           return;
-       Perl_croak(aTHX_ "panic: del_backref, *svp=%p phase=%s refcnt=%" UVuf,
-                  (void*)*svp, PL_phase_names[PL_phase], (UV)SvREFCNT(tsv));
+        /* It's possible that sv is being freed recursively part way through the
+           freeing of tsv. If this happens, the backreferences array of tsv has
+           already been freed, and so svp will be NULL. If this is the case,
+           we should not panic. Instead, nothing needs doing, so return.  */
+        if (PL_phase == PERL_PHASE_DESTRUCT && SvREFCNT(tsv) == 0)
+            return;
+        Perl_croak(aTHX_ "panic: del_backref, *svp=%p phase=%s refcnt=%" UVuf,
+                   (void*)*svp, PL_phase_names[PL_phase], (UV)SvREFCNT(tsv));
     }
 
     if (SvTYPE(*svp) == SVt_PVAV) {
 #ifdef DEBUGGING
-       int count = 1;
+        int count = 1;
 #endif
-       AV * const av = (AV*)*svp;
-       SSize_t fill;
-       assert(!SvIS_FREED(av));
-       fill = AvFILLp(av);
-       assert(fill > -1);
-       svp = AvARRAY(av);
-       /* for an SV with N weak references to it, if all those
-        * weak refs are deleted, then sv_del_backref will be called
-        * N times and O(N^2) compares will be done within the backref
-        * array. To ameliorate this potential slowness, we:
-        * 1) make sure this code is as tight as possible;
-        * 2) when looking for SV, look for it at both the head and tail of the
-        *    array first before searching the rest, since some create/destroy
-        *    patterns will cause the backrefs to be freed in order.
-        */
-       if (*svp == sv) {
-           AvARRAY(av)++;
-           AvMAX(av)--;
-       }
-       else {
-           SV **p = &svp[fill];
-           SV *const topsv = *p;
-           if (topsv != sv) {
+        AV * const av = (AV*)*svp;
+        SSize_t fill;
+        assert(!SvIS_FREED(av));
+        fill = AvFILLp(av);
+        assert(fill > -1);
+        svp = AvARRAY(av);
+        /* for an SV with N weak references to it, if all those
+         * weak refs are deleted, then sv_del_backref will be called
+         * N times and O(N^2) compares will be done within the backref
+         * array. To ameliorate this potential slowness, we:
+         * 1) make sure this code is as tight as possible;
+         * 2) when looking for SV, look for it at both the head and tail of the
+         *    array first before searching the rest, since some create/destroy
+         *    patterns will cause the backrefs to be freed in order.
+         */
+        if (*svp == sv) {
+            AvARRAY(av)++;
+            AvMAX(av)--;
+        }
+        else {
+            SV **p = &svp[fill];
+            SV *const topsv = *p;
+            if (topsv != sv) {
 #ifdef DEBUGGING
-               count = 0;
+                count = 0;
 #endif
-               while (--p > svp) {
-                   if (*p == sv) {
-                       /* We weren't the last entry.
-                          An unordered list has this property that you
-                          can take the last element off the end to fill
-                          the hole, and it's still an unordered list :-)
-                       */
-                       *p = topsv;
+                while (--p > svp) {
+                    if (*p == sv) {
+                        /* We weren't the last entry.
+                           An unordered list has this property that you
+                           can take the last element off the end to fill
+                           the hole, and it's still an unordered list :-)
+                        */
+                        *p = topsv;
 #ifdef DEBUGGING
-                       count++;
+                        count++;
 #else
-                       break; /* should only be one */
+                        break; /* should only be one */
 #endif
-                   }
-               }
-           }
-       }
-       assert(count ==1);
-       AvFILLp(av) = fill-1;
+                    }
+                }
+            }
+        }
+        assert(count ==1);
+        AvFILLp(av) = fill-1;
     }
     else if (SvIS_FREED(*svp) && PL_phase == PERL_PHASE_DESTRUCT) {
-       /* freed AV; skip */
+        /* freed AV; skip */
     }
     else {
-       /* optimisation: only a single backref, stored directly */
-       if (*svp != sv)
-           Perl_croak(aTHX_ "panic: del_backref, *svp=%p, sv=%p",
+        /* optimisation: only a single backref, stored directly */
+        if (*svp != sv)
+            Perl_croak(aTHX_ "panic: del_backref, *svp=%p, sv=%p",
                        (void*)*svp, (void*)sv);
-       *svp = NULL;
+        *svp = NULL;
     }
 
 }
@@ -6258,98 +6372,98 @@ Perl_sv_kill_backrefs(pTHX_ SV *const sv, AV *const av)
     PERL_ARGS_ASSERT_SV_KILL_BACKREFS;
 
     if (!av)
-       return;
+        return;
 
     /* after multiple passes through Perl_sv_clean_all() for a thingy
      * that has badly leaked, the backref array may have gotten freed,
      * since we only protect it against 1 round of cleanup */
     if (SvIS_FREED(av)) {
-       if (PL_in_clean_all) /* All is fair */
-           return;
-       Perl_croak(aTHX_
-                  "panic: magic_killbackrefs (freed backref AV/SV)");
+        if (PL_in_clean_all) /* All is fair */
+            return;
+        Perl_croak(aTHX_
+                   "panic: magic_killbackrefs (freed backref AV/SV)");
     }
 
 
     is_array = (SvTYPE(av) == SVt_PVAV);
     if (is_array) {
-       assert(!SvIS_FREED(av));
-       svp = AvARRAY(av);
-       if (svp)
-           last = svp + AvFILLp(av);
+        assert(!SvIS_FREED(av));
+        svp = AvARRAY(av);
+        if (svp)
+            last = svp + AvFILLp(av);
     }
     else {
-       /* optimisation: only a single backref, stored directly */
-       svp = (SV**)&av;
-       last = svp;
+        /* optimisation: only a single backref, stored directly */
+        svp = (SV**)&av;
+        last = svp;
     }
 
     if (svp) {
-       while (svp <= last) {
-           if (*svp) {
-               SV *const referrer = *svp;
-               if (SvWEAKREF(referrer)) {
-                   /* XXX Should we check that it hasn't changed? */
-                   assert(SvROK(referrer));
-                   SvRV_set(referrer, 0);
-                   SvOK_off(referrer);
-                   SvWEAKREF_off(referrer);
-                   SvSETMAGIC(referrer);
-               } else if (SvTYPE(referrer) == SVt_PVGV ||
-                          SvTYPE(referrer) == SVt_PVLV) {
-                   assert(SvTYPE(sv) == SVt_PVHV); /* stash backref */
-                   /* You lookin' at me?  */
-                   assert(GvSTASH(referrer));
-                   assert(GvSTASH(referrer) == (const HV *)sv);
-                   GvSTASH(referrer) = 0;
-               } else if (SvTYPE(referrer) == SVt_PVCV ||
-                          SvTYPE(referrer) == SVt_PVFM) {
-                   if (SvTYPE(sv) == SVt_PVHV) { /* stash backref */
-                       /* You lookin' at me?  */
-                       assert(CvSTASH(referrer));
-                       assert(CvSTASH(referrer) == (const HV *)sv);
-                       SvANY(MUTABLE_CV(referrer))->xcv_stash = 0;
-                   }
-                   else {
-                       assert(SvTYPE(sv) == SVt_PVGV);
-                       /* You lookin' at me?  */
-                       assert(CvGV(referrer));
-                       assert(CvGV(referrer) == (const GV *)sv);
-                       anonymise_cv_maybe(MUTABLE_GV(sv),
-                                               MUTABLE_CV(referrer));
-                   }
-
-               } else {
-                   Perl_croak(aTHX_
-                              "panic: magic_killbackrefs (flags=%" UVxf ")",
-                              (UV)SvFLAGS(referrer));
-               }
-
-               if (is_array)
-                   *svp = NULL;
-           }
-           svp++;
-       }
+        while (svp <= last) {
+            if (*svp) {
+                SV *const referrer = *svp;
+                if (SvWEAKREF(referrer)) {
+                    /* XXX Should we check that it hasn't changed? */
+                    assert(SvROK(referrer));
+                    SvRV_set(referrer, 0);
+                    SvOK_off(referrer);
+                    SvWEAKREF_off(referrer);
+                    SvSETMAGIC(referrer);
+                } else if (SvTYPE(referrer) == SVt_PVGV ||
+                           SvTYPE(referrer) == SVt_PVLV) {
+                    assert(SvTYPE(sv) == SVt_PVHV); /* stash backref */
+                    /* You lookin' at me?  */
+                    assert(GvSTASH(referrer));
+                    assert(GvSTASH(referrer) == (const HV *)sv);
+                    GvSTASH(referrer) = 0;
+                } else if (SvTYPE(referrer) == SVt_PVCV ||
+                           SvTYPE(referrer) == SVt_PVFM) {
+                    if (SvTYPE(sv) == SVt_PVHV) { /* stash backref */
+                        /* You lookin' at me?  */
+                        assert(CvSTASH(referrer));
+                        assert(CvSTASH(referrer) == (const HV *)sv);
+                        SvANY(MUTABLE_CV(referrer))->xcv_stash = 0;
+                    }
+                    else {
+                        assert(SvTYPE(sv) == SVt_PVGV);
+                        /* You lookin' at me?  */
+                        assert(CvGV(referrer));
+                        assert(CvGV(referrer) == (const GV *)sv);
+                        anonymise_cv_maybe(MUTABLE_GV(sv),
+                                                MUTABLE_CV(referrer));
+                    }
+
+                } else {
+                    Perl_croak(aTHX_
+                               "panic: magic_killbackrefs (flags=%" UVxf ")",
+                               (UV)SvFLAGS(referrer));
+                }
+
+                if (is_array)
+                    *svp = NULL;
+            }
+            svp++;
+        }
     }
     if (is_array) {
-       AvFILLp(av) = -1;
-       SvREFCNT_dec_NN(av); /* remove extra count added by sv_add_backref() */
+        AvFILLp(av) = -1;
+        SvREFCNT_dec_NN(av); /* remove extra count added by sv_add_backref() */
     }
     return;
 }
 
 /*
-=for apidoc sv_insert
+=for apidoc      sv_insert
+=for apidoc_item sv_insert_flags
 
-Inserts and/or replaces a string at the specified offset/length within the SV.
-Similar to the Perl C<substr()> function, with C<littlelen> bytes starting at
-C<little> replacing C<len> bytes of the string in C<bigstr> starting at
-C<offset>.  Handles get magic.
+These insert and/or replace a string at the specified offset/length within the
+SV.  Similar to the Perl C<substr()> function, with C<littlelen> bytes starting
+at C<little> replacing C<len> bytes of the string in C<bigstr> starting at
+C<offset>.  They handle get magic.
 
-=for apidoc sv_insert_flags
-
-Same as C<sv_insert>, but the extra C<flags> are passed to the
-C<SvPV_force_flags> that applies to C<bigstr>.
+C<sv_insert_flags> is identical to plain C<sv_insert>, but the extra C<flags>
+are passed to the C<SvPV_force_flags> operation that is internally applied to
+C<bigstr>.
 
 =cut
 */
@@ -6379,30 +6493,30 @@ Perl_sv_insert_flags(pTHX_ SV *const bigstr, const STRLEN offset, const STRLEN l
     }
 
     if (offset + len > curlen) {
-       SvGROW(bigstr, offset+len+1);
-       Zero(SvPVX(bigstr)+curlen, offset+len-curlen, char);
-       SvCUR_set(bigstr, offset+len);
+        SvGROW(bigstr, offset+len+1);
+        Zero(SvPVX(bigstr)+curlen, offset+len-curlen, char);
+        SvCUR_set(bigstr, offset+len);
     }
 
     SvTAINT(bigstr);
     i = littlelen - len;
     if (i > 0) {                       /* string might grow */
-       big = SvGROW(bigstr, SvCUR(bigstr) + i + 1);
-       mid = big + offset + len;
-       midend = bigend = big + SvCUR(bigstr);
-       bigend += i;
-       *bigend = '\0';
-       while (midend > mid)            /* shove everything down */
-           *--bigend = *--midend;
-       Move(little,big+offset,littlelen,char);
-       SvCUR_set(bigstr, SvCUR(bigstr) + i);
-       SvSETMAGIC(bigstr);
-       return;
+        big = SvGROW(bigstr, SvCUR(bigstr) + i + 1);
+        mid = big + offset + len;
+        midend = bigend = big + SvCUR(bigstr);
+        bigend += i;
+        *bigend = '\0';
+        while (midend > mid)           /* shove everything down */
+            *--bigend = *--midend;
+        Move(little,big+offset,littlelen,char);
+        SvCUR_set(bigstr, SvCUR(bigstr) + i);
+        SvSETMAGIC(bigstr);
+        return;
     }
     else if (i == 0) {
-       Move(little,SvPVX(bigstr)+offset,len,char);
-       SvSETMAGIC(bigstr);
-       return;
+        Move(little,SvPVX(bigstr)+offset,len,char);
+        SvSETMAGIC(bigstr);
+        return;
     }
 
     big = SvPVX(bigstr);
@@ -6411,37 +6525,37 @@ Perl_sv_insert_flags(pTHX_ SV *const bigstr, const STRLEN offset, const STRLEN l
     bigend = big + SvCUR(bigstr);
 
     if (midend > bigend)
-       Perl_croak(aTHX_ "panic: sv_insert, midend=%p, bigend=%p",
-                  midend, bigend);
+        Perl_croak(aTHX_ "panic: sv_insert, midend=%p, bigend=%p",
+                   midend, bigend);
 
     if (mid - big > bigend - midend) { /* faster to shorten from end */
-       if (littlelen) {
-           Move(little, mid, littlelen,char);
-           mid += littlelen;
-       }
-       i = bigend - midend;
-       if (i > 0) {
-           Move(midend, mid, i,char);
-           mid += i;
-       }
-       *mid = '\0';
-       SvCUR_set(bigstr, mid - big);
+        if (littlelen) {
+            Move(little, mid, littlelen,char);
+            mid += littlelen;
+        }
+        i = bigend - midend;
+        if (i > 0) {
+            Move(midend, mid, i,char);
+            mid += i;
+        }
+        *mid = '\0';
+        SvCUR_set(bigstr, mid - big);
     }
     else if ((i = mid - big)) {        /* faster from front */
-       midend -= littlelen;
-       mid = midend;
-       Move(big, midend - i, i, char);
-       sv_chop(bigstr,midend-i);
-       if (littlelen)
-           Move(little, mid, littlelen,char);
+        midend -= littlelen;
+        mid = midend;
+        Move(big, midend - i, i, char);
+        sv_chop(bigstr,midend-i);
+        if (littlelen)
+            Move(little, mid, littlelen,char);
     }
     else if (littlelen) {
-       midend -= littlelen;
-       sv_chop(bigstr,midend);
-       Move(little,midend,littlelen,char);
+        midend -= littlelen;
+        sv_chop(bigstr,midend);
+        Move(little,midend,littlelen,char);
     }
     else {
-       sv_chop(bigstr,midend);
+        sv_chop(bigstr,midend);
     }
     SvSETMAGIC(bigstr);
 }
@@ -6468,18 +6582,18 @@ Perl_sv_replace(pTHX_ SV *const sv, SV *const nsv)
 
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     if (SvREFCNT(nsv) != 1) {
-       Perl_croak(aTHX_ "panic: reference miscount on nsv in sv_replace()"
-                  " (%" UVuf " != 1)", (UV) SvREFCNT(nsv));
+        Perl_croak(aTHX_ "panic: reference miscount on nsv in sv_replace()"
+                   " (%" UVuf " != 1)", (UV) SvREFCNT(nsv));
     }
     if (SvMAGICAL(sv)) {
-       if (SvMAGICAL(nsv))
-           mg_free(nsv);
-       else
-           sv_upgrade(nsv, SVt_PVMG);
-       SvMAGIC_set(nsv, SvMAGIC(sv));
-       SvFLAGS(nsv) |= SvMAGICAL(sv);
-       SvMAGICAL_off(sv);
-       SvMAGIC_set(sv, NULL);
+        if (SvMAGICAL(nsv))
+            mg_free(nsv);
+        else
+            sv_upgrade(nsv, SVt_PVMG);
+        SvMAGIC_set(nsv, SvMAGIC(sv));
+        SvFLAGS(nsv) |= SvMAGICAL(sv);
+        SvMAGICAL_off(sv);
+        SvMAGIC_set(sv, NULL);
     }
     SvREFCNT(sv) = 0;
     sv_clear(sv);
@@ -6493,9 +6607,9 @@ Perl_sv_replace(pTHX_ SV *const sv, SV *const nsv)
     StructCopy(nsv,sv,SV);
 #endif
     if(SvTYPE(sv) == SVt_IV) {
-       SET_SVANY_FOR_BODYLESS_IV(sv);
+        SET_SVANY_FOR_BODYLESS_IV(sv);
     }
-       
+
 
     SvREFCNT(sv) = refcnt;
     SvFLAGS(nsv) |= SVTYPEMASK;                /* Mark as freed */
@@ -6525,12 +6639,12 @@ S_anonymise_cv_maybe(pTHX_ GV *gv, CV* cv)
 
     /* will the CV shortly be freed by gp_free() ? */
     if (GvCV(gv) == cv && GvGP(gv)->gp_refcnt < 2 && SvREFCNT(cv) < 2) {
-       SvANY(cv)->xcv_gv_u.xcv_gv = NULL;
-       return;
+        SvANY(cv)->xcv_gv_u.xcv_gv = NULL;
+        return;
     }
 
     /* if not, anonymise: */
-    gvname = (GvSTASH(gv) && HvNAME(GvSTASH(gv)) && HvENAME(GvSTASH(gv)))
+    gvname = (GvSTASH(gv) && HvHasNAME(GvSTASH(gv)) && HvHasENAME(GvSTASH(gv)))
                     ? newSVhek(HvENAME_HEK(GvSTASH(gv)))
                     : newSVpvn_flags( "__ANON__", 8, 0 );
     sv_catpvs(gvname, "::__ANON__");
@@ -6551,8 +6665,7 @@ and free the body itself.  The SV's head is I<not> freed, although
 its type is set to all 1's so that it won't inadvertently be assumed
 to be live during global destruction etc.
 This function should only be called when C<REFCNT> is zero.  Most of the time
-you'll want to call C<sv_free()> (or its macro wrapper C<SvREFCNT_dec>)
-instead.
+you'll want to call C<SvREFCNT_dec> instead.
 
 =cut
 */
@@ -6560,10 +6673,6 @@ instead.
 void
 Perl_sv_clear(pTHX_ SV *const orig_sv)
 {
-    dVAR;
-    HV *stash;
-    U32 type;
-    const struct body_details *sv_type_details;
     SV* iter_sv = NULL;
     SV* next_sv = NULL;
     SV *sv = orig_sv;
@@ -6577,339 +6686,422 @@ Perl_sv_clear(pTHX_ SV *const orig_sv)
      * over to provide more SVs */
 
     while (sv) {
+        U32 type = SvTYPE(sv);
+        HV *stash;
+
+        assert(SvREFCNT(sv) == 0);
+        assert(!SvIS_FREED(sv));
+#if NVSIZE <= IVSIZE
+        if (type <= SVt_NV) {
+#else
+        if (type <= SVt_IV) {
+#endif
+            /* Historically this check on type was needed so that the code to
+             * free bodies wasn't reached for these types, because the arena
+             * slots were re-used for HEs and pointer table entries. The
+             * metadata table `bodies_by_type` had the information for the sizes
+             * for HEs and PTEs, hence the code here had to have a special-case
+             * check to ensure that the "regular" body freeing code wasn't
+             * reached, and get confused by the "lies" in `bodies_by_type`.
+             *
+             * However, it hasn't actually been needed for that reason since
+             * Aug 2010 (commit 829cd18aa7f45221), because `bodies_by_type` was
+             * changed to always hold the accurate metadata for the SV types.
+             * This was possible because PTEs were no longer allocated from the
+             * "SVt_IV" arena, and the code to allocate HEs from the "SVt_NULL"
+             * arena is entirely in hv.c, so doesn't access the table.
+             *
+             * Some sort of check is still needed to handle SVt_IVs - pure RVs
+             * need to take one code path which is common with RVs stored in
+             * SVt_PV (or larger), but pure IVs mustn't take the "PV but not RV"
+             * path, as SvPVX() doesn't point to valid memory.
+             *
+             * Hence this code is still the most efficient way to handle this.
+             *
+             * Additionally, for bodyless NVs, riding this branch is more
+             * efficient than stepping through the general logic.
+             */
+
+            if (SvROK(sv))
+                goto free_rv;
+            SvFLAGS(sv) &= SVf_BREAK;
+            SvFLAGS(sv) |= SVTYPEMASK;
+            goto free_head;
+        }
+
+        /* objs are always >= MG, but pad names use the SVs_OBJECT flag
+           for another purpose  */
+        assert(!SvOBJECT(sv) || type >= SVt_PVMG);
 
-       type = SvTYPE(sv);
-
-       assert(SvREFCNT(sv) == 0);
-       assert(SvTYPE(sv) != (svtype)SVTYPEMASK);
-
-       if (type <= SVt_IV) {
-           /* See the comment in sv.h about the collusion between this
-            * early return and the overloading of the NULL slots in the
-            * size table.  */
-           if (SvROK(sv))
-               goto free_rv;
-           SvFLAGS(sv) &= SVf_BREAK;
-           SvFLAGS(sv) |= SVTYPEMASK;
-           goto free_head;
-       }
-
-       /* objs are always >= MG, but pad names use the SVs_OBJECT flag
-          for another purpose  */
-       assert(!SvOBJECT(sv) || type >= SVt_PVMG);
-
-       if (type >= SVt_PVMG) {
-           if (SvOBJECT(sv)) {
-               if (!curse(sv, 1)) goto get_next_sv;
-               type = SvTYPE(sv); /* destructor may have changed it */
-           }
-           /* Free back-references before magic, in case the magic calls
-            * Perl code that has weak references to sv. */
-           if (type == SVt_PVHV) {
-               Perl_hv_kill_backrefs(aTHX_ MUTABLE_HV(sv));
-               if (SvMAGIC(sv))
-                   mg_free(sv);
-           }
-           else if (SvMAGIC(sv)) {
-               /* Free back-references before other types of magic. */
-               sv_unmagic(sv, PERL_MAGIC_backref);
-               mg_free(sv);
-           }
-           SvMAGICAL_off(sv);
-       }
-       switch (type) {
-           /* case SVt_INVLIST: */
-       case SVt_PVIO:
-           if (IoIFP(sv) &&
-               IoIFP(sv) != PerlIO_stdin() &&
-               IoIFP(sv) != PerlIO_stdout() &&
-               IoIFP(sv) != PerlIO_stderr() &&
-               !(IoFLAGS(sv) & IOf_FAKE_DIRP))
-           {
-               io_close(MUTABLE_IO(sv), NULL, FALSE,
-                        (IoTYPE(sv) == IoTYPE_WRONLY ||
-                         IoTYPE(sv) == IoTYPE_RDWR   ||
-                         IoTYPE(sv) == IoTYPE_APPEND));
-           }
-           if (IoDIRP(sv) && !(IoFLAGS(sv) & IOf_FAKE_DIRP))
-               PerlDir_close(IoDIRP(sv));
-           IoDIRP(sv) = (DIR*)NULL;
-           Safefree(IoTOP_NAME(sv));
-           Safefree(IoFMT_NAME(sv));
-           Safefree(IoBOTTOM_NAME(sv));
-           if ((const GV *)sv == PL_statgv)
-               PL_statgv = NULL;
-           goto freescalar;
-       case SVt_REGEXP:
-           /* FIXME for plugins */
-           pregfree2((REGEXP*) sv);
-           goto freescalar;
-       case SVt_PVCV:
-       case SVt_PVFM:
-           cv_undef(MUTABLE_CV(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 ((stash = CvSTASH(sv)))
-               sv_del_backref(MUTABLE_SV(stash), sv);
-           goto freescalar;
-       case SVt_PVHV:
-           if (HvTOTALKEYS((HV*)sv) > 0) {
-               const HEK *hek;
-               /* this statement should match the one at the beginning of
-                * hv_undef_flags() */
-               if (   PL_phase != PERL_PHASE_DESTRUCT
-                   && (hek = HvNAME_HEK((HV*)sv)))
-               {
-                   if (PL_stashcache) {
-                       DEBUG_o(Perl_deb(aTHX_
-                           "sv_clear clearing PL_stashcache for '%" HEKf
-                           "'\n",
-                            HEKfARG(hek)));
-                       (void)hv_deletehek(PL_stashcache,
+        if (type >= SVt_PVMG) {
+            if (SvOBJECT(sv)) {
+                if (!curse(sv, 1)) goto get_next_sv;
+                type = SvTYPE(sv); /* destructor may have changed it */
+            }
+            /* Free back-references before magic, in case the magic calls
+             * Perl code that has weak references to sv. */
+            if (type == SVt_PVHV) {
+                Perl_hv_kill_backrefs(aTHX_ MUTABLE_HV(sv));
+                if (SvMAGIC(sv))
+                    mg_free(sv);
+            }
+            else if (SvMAGIC(sv)) {
+                /* Free back-references before other types of magic. */
+                sv_unmagic(sv, PERL_MAGIC_backref);
+                mg_free(sv);
+            }
+            SvMAGICAL_off(sv);
+        }
+        switch (type) {
+            /* case SVt_INVLIST: */
+        case SVt_PVIO:
+            if (IoIFP(sv) &&
+                IoIFP(sv) != PerlIO_stdin() &&
+                IoIFP(sv) != PerlIO_stdout() &&
+                IoIFP(sv) != PerlIO_stderr() &&
+                !(IoFLAGS(sv) & IOf_FAKE_DIRP))
+            {
+                io_close(MUTABLE_IO(sv), NULL, FALSE,
+                         (IoTYPE(sv) == IoTYPE_WRONLY ||
+                          IoTYPE(sv) == IoTYPE_RDWR   ||
+                          IoTYPE(sv) == IoTYPE_APPEND));
+            }
+            if (IoDIRP(sv) && !(IoFLAGS(sv) & IOf_FAKE_DIRP))
+                PerlDir_close(IoDIRP(sv));
+            IoDIRP(sv) = (DIR*)NULL;
+            Safefree(IoTOP_NAME(sv));
+            Safefree(IoFMT_NAME(sv));
+            Safefree(IoBOTTOM_NAME(sv));
+            if ((const GV *)sv == PL_statgv)
+                PL_statgv = NULL;
+            goto freescalar;
+        case SVt_REGEXP:
+            /* FIXME for plugins */
+            pregfree2((REGEXP*) sv);
+            goto freescalar;
+        case SVt_PVCV:
+        case SVt_PVFM:
+            cv_undef(MUTABLE_CV(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 ((stash = CvSTASH(sv)))
+                sv_del_backref(MUTABLE_SV(stash), sv);
+            goto freescalar;
+        case SVt_PVHV:
+            if (HvTOTALKEYS((HV*)sv) > 0) {
+                const HEK *hek;
+                /* this statement should match the one at the beginning of
+                 * hv_undef_flags() */
+                if (   PL_phase != PERL_PHASE_DESTRUCT
+                    && (hek = HvNAME_HEK((HV*)sv)))
+                {
+                    if (PL_stashcache) {
+                        DEBUG_o(Perl_deb(aTHX_
+                            "sv_clear clearing PL_stashcache for '%" HEKf
+                            "'\n",
+                             HEKfARG(hek)));
+                        (void)hv_deletehek(PL_stashcache,
                                            hek, G_DISCARD);
                     }
-                   hv_name_set((HV*)sv, NULL, 0, 0);
-               }
-
-               /* save old iter_sv in unused SvSTASH field */
-               assert(!SvOBJECT(sv));
-               SvSTASH(sv) = (HV*)iter_sv;
-               iter_sv = sv;
-
-               /* save old hash_index in unused SvMAGIC field */
-               assert(!SvMAGICAL(sv));
-               assert(!SvMAGIC(sv));
-               ((XPVMG*) SvANY(sv))->xmg_u.xmg_hash_index = hash_index;
-               hash_index = 0;
-
-               next_sv = Perl_hfree_next_entry(aTHX_ (HV*)sv, &hash_index);
-               goto get_next_sv; /* process this new sv */
-           }
-           /* free empty hash */
-           Perl_hv_undef_flags(aTHX_ MUTABLE_HV(sv), HV_NAME_SETALL);
-           assert(!HvARRAY((HV*)sv));
-           break;
-       case SVt_PVAV:
-           {
-               AV* av = MUTABLE_AV(sv);
-               if (PL_comppad == av) {
-                   PL_comppad = NULL;
-                   PL_curpad = NULL;
-               }
-               if (AvREAL(av) && AvFILLp(av) > -1) {
-                   next_sv = AvARRAY(av)[AvFILLp(av)--];
-                   /* save old iter_sv in top-most slot of AV,
-                    * and pray that it doesn't get wiped in the meantime */
-                   AvARRAY(av)[AvMAX(av)] = iter_sv;
-                   iter_sv = sv;
-                   goto get_next_sv; /* process this new sv */
-               }
-               Safefree(AvALLOC(av));
-           }
-
-           break;
-       case SVt_PVLV:
-           if (LvTYPE(sv) == 'T') { /* for tie: return HE to pool */
-               SvREFCNT_dec(HeKEY_sv((HE*)LvTARG(sv)));
-               HeNEXT((HE*)LvTARG(sv)) = PL_hv_fetch_ent_mh;
-               PL_hv_fetch_ent_mh = (HE*)LvTARG(sv);
-           }
-           else if (LvTYPE(sv) != 't') /* unless tie: unrefcnted fake SV**  */
-               SvREFCNT_dec(LvTARG(sv));
-           if (isREGEXP(sv)) {
-                /* SvLEN points to a regex body. Free the body, then
-                 * set SvLEN to whatever value was in the now-freed
-                 * regex body. The PVX buffer is shared by multiple re's
-                 * and only freed once, by the re whose len in non-null */
-                STRLEN len = ReANY(sv)->xpv_len;
+                    hv_name_set((HV*)sv, NULL, 0, 0);
+                }
+
+                /* save old iter_sv in unused SvSTASH field */
+                assert(!SvOBJECT(sv));
+                SvSTASH(sv) = (HV*)iter_sv;
+                iter_sv = sv;
+
+                /* save old hash_index in unused SvMAGIC field */
+                assert(!SvMAGICAL(sv));
+                assert(!SvMAGIC(sv));
+                ((XPVMG*) SvANY(sv))->xmg_u.xmg_hash_index = hash_index;
+                hash_index = 0;
+
+                next_sv = Perl_hfree_next_entry(aTHX_ (HV*)sv, &hash_index);
+                goto get_next_sv; /* process this new sv */
+            }
+            /* free empty hash */
+            Perl_hv_undef_flags(aTHX_ MUTABLE_HV(sv), HV_NAME_SETALL);
+            assert(!HvARRAY((HV*)sv));
+            break;
+        case SVt_PVAV:
+            {
+                AV* av = MUTABLE_AV(sv);
+                if (PL_comppad == av) {
+                    PL_comppad = NULL;
+                    PL_curpad = NULL;
+                }
+                if (AvREAL(av) && AvFILLp(av) > -1) {
+                    next_sv = AvARRAY(av)[AvFILLp(av)--];
+                    /* save old iter_sv in top-most slot of AV,
+                     * and pray that it doesn't get wiped in the meantime */
+                    AvARRAY(av)[AvMAX(av)] = iter_sv;
+                    iter_sv = sv;
+                    goto get_next_sv; /* process this new sv */
+                }
+                Safefree(AvALLOC(av));
+            }
+
+            break;
+        case SVt_PVOBJ:
+            if(ObjectMAXFIELD(sv) > -1) {
+                next_sv = ObjectFIELDS(sv)[ObjectMAXFIELD(sv)--];
+                /* save old iter_sv in top-most field, and pray that it
+                 * doesn't get wiped in the meantime */
+                ObjectFIELDS(sv)[(ObjectITERSVAT(sv) = ObjectMAXFIELD(sv) + 1)] = iter_sv;
+                iter_sv = sv;
+                goto get_next_sv;
+            }
+            Safefree(ObjectFIELDS(sv));
+            break;
+        case SVt_PVLV:
+            if (LvTYPE(sv) == 'T') { /* for tie: return HE to pool */
+                SvREFCNT_dec(HeKEY_sv((HE*)LvTARG(sv)));
+                HeNEXT((HE*)LvTARG(sv)) = PL_hv_fetch_ent_mh;
+                PL_hv_fetch_ent_mh = (HE*)LvTARG(sv);
+            }
+            else if (LvTYPE(sv) != 't') /* unless tie: unrefcnted fake SV**  */
+                SvREFCNT_dec(LvTARG(sv));
+            if (isREGEXP(sv)) {
+                /* This PVLV has had a REGEXP assigned to it - the memory
+                 * normally used to store SvLEN instead points to a regex body.
+                 * Retrieving the pointer to the regex body from the correct
+                 * location is normally abstracted by ReANY(), which handles
+                 * both SVt_PVLV and SVt_REGEXP
+                 *
+                 * This code is unwinding the storage specific to SVt_PVLV.
+                 * We get the body pointer directly from the union, free it,
+                 * then set SvLEN to whatever value was in the now-freed regex
+                 * body. The PVX buffer is shared by multiple re's and only
+                 * freed once, by the re whose SvLEN is non-null.
+                 *
+                 * Perl_sv_force_normal_flags() also has code to free this
+                 * hidden body - it swaps the body into a temporary SV it has
+                 * just allocated, then frees that SV. That causes execution
+                 * to reach the SVt_REGEXP: case about 60 lines earlier in this
+                 * function.
+                 *
+                 * See Perl_reg_temp_copy() for the code that sets up this
+                 * REGEXP body referenced by the PVLV. */
+                struct regexp *r = ((XPV*)SvANY(sv))->xpv_len_u.xpvlenu_rx;
+                STRLEN len = r->xpv_len;
                 pregfree2((REGEXP*) sv);
+                del_body_by_type(r, SVt_REGEXP);
                 SvLEN_set((sv), len);
                 goto freescalar;
             }
             /* FALLTHROUGH */
-       case SVt_PVGV:
-           if (isGV_with_GP(sv)) {
-               if(GvCVu((const GV *)sv) && (stash = GvSTASH(MUTABLE_GV(sv)))
-                  && HvENAME_get(stash))
-                   mro_method_changed_in(stash);
-               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 ((stash = GvSTASH(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:  */
-           /* See also S_sv_unglob, which does the same thing. */
-           if ((const GV *)sv == PL_last_in_gv)
-               PL_last_in_gv = NULL;
-           else if ((const GV *)sv == PL_statgv)
-               PL_statgv = NULL;
+        case SVt_PVGV:
+            if (isGV_with_GP(sv)) {
+                if(GvCVu((const GV *)sv) && (stash = GvSTASH(MUTABLE_GV(sv)))
+                   && HvHasENAME(stash))
+                    mro_method_changed_in(stash);
+                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 ((stash = GvSTASH(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:  */
+            /* See also S_sv_unglob, which does the same thing. */
+            if ((const GV *)sv == PL_last_in_gv)
+                PL_last_in_gv = NULL;
+            else if ((const GV *)sv == PL_statgv)
+                PL_statgv = NULL;
             else if ((const GV *)sv == PL_stderrgv)
                 PL_stderrgv = NULL;
             /* FALLTHROUGH */
-       case SVt_PVMG:
-       case SVt_PVNV:
-       case SVt_PVIV:
-       case SVt_INVLIST:
-       case SVt_PV:
-         freescalar:
-           /* Don't bother with SvOOK_off(sv); as we're only going to
-            * free it.  */
-           if (SvOOK(sv)) {
-               STRLEN offset;
-               SvOOK_offset(sv, offset);
-               SvPV_set(sv, SvPVX_mutable(sv) - offset);
-               /* Don't even bother with turning off the OOK flag.  */
-           }
-           if (SvROK(sv)) {
-           free_rv:
-               {
-                   SV * const target = SvRV(sv);
-                   if (SvWEAKREF(sv))
-                       sv_del_backref(target, sv);
-                   else
-                       next_sv = target;
-               }
-           }
+        case SVt_PVMG:
+        case SVt_PVNV:
+        case SVt_PVIV:
+        case SVt_INVLIST:
+        case SVt_PV:
+          freescalar:
+            /* Don't bother with SvOOK_off(sv); as we're only going to
+             * free it.  */
+            if (SvOOK(sv)) {
+                STRLEN offset;
+                SvOOK_offset(sv, offset);
+                SvPV_set(sv, SvPVX_mutable(sv) - offset);
+                /* Don't even bother with turning off the OOK flag.  */
+            }
+            if (SvROK(sv)) {
+            free_rv:
+                {
+                    SV * const target = SvRV(sv);
+                    if (SvWEAKREF(sv))
+                        sv_del_backref(target, sv);
+                    else
+                        next_sv = target;
+                }
+            }
 #ifdef PERL_ANY_COW
-           else if (SvPVX_const(sv)
-                    && !(SvTYPE(sv) == SVt_PVIO
-                    && !(IoFLAGS(sv) & IOf_FAKE_DIRP)))
-           {
-               if (SvIsCOW(sv)) {
+            else if (SvPVX_const(sv)
+                     && !(SvTYPE(sv) == SVt_PVIO
+                     && !(IoFLAGS(sv) & IOf_FAKE_DIRP)))
+            {
+                if (SvIsCOW(sv)) {
 #ifdef DEBUGGING
-                   if (DEBUG_C_TEST) {
-                       PerlIO_printf(Perl_debug_log, "Copy on write: clear\n");
-                       sv_dump(sv);
-                   }
+                    if (DEBUG_C_TEST) {
+                        PerlIO_printf(Perl_debug_log, "Copy on write: clear\n");
+                        sv_dump(sv);
+                    }
 #endif
-                   if (SvLEN(sv)) {
-                       if (CowREFCNT(sv)) {
-                           sv_buf_to_rw(sv);
-                           CowREFCNT(sv)--;
-                           sv_buf_to_ro(sv);
-                           SvLEN_set(sv, 0);
-                       }
-                   } else {
-                       unshare_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sv)));
-                   }
-
-               }
-               if (SvLEN(sv)) {
-                   Safefree(SvPVX_mutable(sv));
-               }
-           }
+                    if (SvIsCOW_static(sv)) {
+                        SvLEN_set(sv, 0);
+                    }
+                    else if (SvIsCOW_shared_hash(sv)) {
+                        unshare_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sv)));
+                    }
+                    else {
+                        if (CowREFCNT(sv)) {
+                            sv_buf_to_rw(sv);
+                            CowREFCNT(sv)--;
+                            sv_buf_to_ro(sv);
+                            SvLEN_set(sv, 0);
+                        }
+                    }
+                }
+                if (SvLEN(sv)) {
+                    Safefree(SvPVX_mutable(sv));
+                }
+            }
 #else
-           else if (SvPVX_const(sv) && SvLEN(sv)
-                    && !(SvTYPE(sv) == SVt_PVIO
-                    && !(IoFLAGS(sv) & IOf_FAKE_DIRP)))
-               Safefree(SvPVX_mutable(sv));
-           else if (SvPVX_const(sv) && SvIsCOW(sv)) {
-               unshare_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sv)));
-           }
+            else if (SvPVX_const(sv) && SvLEN(sv)
+                     && !(SvTYPE(sv) == SVt_PVIO
+                     && !(IoFLAGS(sv) & IOf_FAKE_DIRP)))
+                Safefree(SvPVX_mutable(sv));
+            else if (SvPVX_const(sv) && SvIsCOW(sv)) {
+                unshare_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sv)));
+            }
 #endif
-           break;
-       case SVt_NV:
-           break;
-       }
+            break;
+        case SVt_NV:
+            break;
+        }
 
       free_body:
 
-       SvFLAGS(sv) &= SVf_BREAK;
-       SvFLAGS(sv) |= SVTYPEMASK;
+        {
+            U32 arena_index;
+            const struct body_details *sv_type_details;
+
+            if (type == SVt_PVHV && HvHasAUX(sv)) {
+                arena_index = HVAUX_ARENA_ROOT_IX;
+                sv_type_details = &fake_hv_with_aux;
+            }
+            else {
+                arena_index = type;
+                sv_type_details = bodies_by_type + arena_index;
+            }
+
+            SvFLAGS(sv) &= SVf_BREAK;
+            SvFLAGS(sv) |= SVTYPEMASK;
 
-       sv_type_details = bodies_by_type + type;
-       if (sv_type_details->arena) {
-           del_body(((char *)SvANY(sv) + sv_type_details->offset),
-                    &PL_body_roots[type]);
-       }
-       else if (sv_type_details->body_size) {
-           safefree(SvANY(sv));
-       }
+            if (sv_type_details->arena) {
+                del_body(((char *)SvANY(sv) + sv_type_details->offset),
+                         &PL_body_roots[arena_index]);
+            }
+            else if (sv_type_details->body_size) {
+                safefree(SvANY(sv));
+            }
+        }
 
       free_head:
-       /* caller is responsible for freeing the head of the original sv */
-       if (sv != orig_sv && !SvREFCNT(sv))
-           del_SV(sv);
+        /* caller is responsible for freeing the head of the original sv */
+        if (sv != orig_sv && !SvREFCNT(sv))
+            del_SV(sv);
 
-       /* grab and free next sv, if any */
+        /* grab and free next sv, if any */
       get_next_sv:
-       while (1) {
-           sv = NULL;
-           if (next_sv) {
-               sv = next_sv;
-               next_sv = NULL;
-           }
-           else if (!iter_sv) {
-               break;
-           } else if (SvTYPE(iter_sv) == SVt_PVAV) {
-               AV *const av = (AV*)iter_sv;
-               if (AvFILLp(av) > -1) {
-                   sv = AvARRAY(av)[AvFILLp(av)--];
-               }
-               else { /* no more elements of current AV to free */
-                   sv = iter_sv;
-                   type = SvTYPE(sv);
-                   /* restore previous value, squirrelled away */
-                   iter_sv = AvARRAY(av)[AvMAX(av)];
-                   Safefree(AvALLOC(av));
-                   goto free_body;
-               }
-           } else if (SvTYPE(iter_sv) == SVt_PVHV) {
-               sv = Perl_hfree_next_entry(aTHX_ (HV*)iter_sv, &hash_index);
-               if (!sv && !HvTOTALKEYS((HV *)iter_sv)) {
-                   /* no more elements of current HV to free */
-                   sv = iter_sv;
-                   type = SvTYPE(sv);
-                   /* Restore previous values of iter_sv and hash_index,
-                    * squirrelled away */
-                   assert(!SvOBJECT(sv));
-                   iter_sv = (SV*)SvSTASH(sv);
-                   assert(!SvMAGICAL(sv));
-                   hash_index = ((XPVMG*) SvANY(sv))->xmg_u.xmg_hash_index;
+        while (1) {
+            sv = NULL;
+            if (next_sv) {
+                sv = next_sv;
+                next_sv = NULL;
+            }
+            else if (!iter_sv) {
+                break;
+            } else if (SvTYPE(iter_sv) == SVt_PVAV) {
+                AV *const av = (AV*)iter_sv;
+                if (AvFILLp(av) > -1) {
+                    sv = AvARRAY(av)[AvFILLp(av)--];
+                }
+                else { /* no more elements of current AV to free */
+                    sv = iter_sv;
+                    type = SvTYPE(sv);
+                    /* restore previous value, squirrelled away */
+                    iter_sv = AvARRAY(av)[AvMAX(av)];
+                    Safefree(AvALLOC(av));
+                    goto free_body;
+                }
+            } else if (SvTYPE(iter_sv) == SVt_PVOBJ) {
+                if (ObjectMAXFIELD(iter_sv) > -1) {
+                    sv = ObjectFIELDS(iter_sv)[ObjectMAXFIELD(iter_sv)--];
+                }
+                else { /* no more fields in the current SV to free */
+                    sv = iter_sv;
+                    type = SvTYPE(sv);
+                    iter_sv = ObjectFIELDS(sv)[ObjectITERSVAT(sv)];
+                    Safefree(ObjectFIELDS(sv));
+                    goto free_body;
+                }
+            } else if (SvTYPE(iter_sv) == SVt_PVHV) {
+                sv = Perl_hfree_next_entry(aTHX_ (HV*)iter_sv, &hash_index);
+                if (!sv && !HvTOTALKEYS((HV *)iter_sv)) {
+                    /* no more elements of current HV to free */
+                    sv = iter_sv;
+                    type = SvTYPE(sv);
+                    /* Restore previous values of iter_sv and hash_index,
+                     * squirrelled away */
+                    assert(!SvOBJECT(sv));
+                    iter_sv = (SV*)SvSTASH(sv);
+                    assert(!SvMAGICAL(sv));
+                    hash_index = ((XPVMG*) SvANY(sv))->xmg_u.xmg_hash_index;
 #ifdef DEBUGGING
-                   /* perl -DA does not like rubbish in SvMAGIC. */
-                   SvMAGIC_set(sv, 0);
+                    /* perl -DA does not like rubbish in SvMAGIC. */
+                    SvMAGIC_set(sv, 0);
 #endif
 
-                   /* free any remaining detritus from the hash struct */
-                   Perl_hv_undef_flags(aTHX_ MUTABLE_HV(sv), HV_NAME_SETALL);
-                   assert(!HvARRAY((HV*)sv));
-                   goto free_body;
-               }
-           }
-
-           /* unrolled SvREFCNT_dec and sv_free2 follows: */
-
-           if (!sv)
-               continue;
-           if (!SvREFCNT(sv)) {
-               sv_free(sv);
-               continue;
-           }
-           if (--(SvREFCNT(sv)))
-               continue;
+                    /* free any remaining detritus from the hash struct */
+                    Perl_hv_undef_flags(aTHX_ MUTABLE_HV(sv), HV_NAME_SETALL);
+                    assert(!HvARRAY((HV*)sv));
+                    goto free_body;
+                }
+            }
+
+            /* unrolled SvREFCNT_dec and sv_free2 follows: */
+
+            if (!sv)
+                continue;
+            if (!SvREFCNT(sv)) {
+                sv_free(sv);
+                continue;
+            }
+            if (--(SvREFCNT(sv)))
+                continue;
+            if (SvIMMORTAL(sv)) {
+                /* make sure SvREFCNT(sv)==0 happens very seldom */
+                SvREFCNT(sv) = SvREFCNT_IMMORTAL;
+                SvTEMP_off(sv);
+                continue;
+            }
 #ifdef DEBUGGING
-           if (SvTEMP(sv)) {
-               Perl_ck_warner_d(aTHX_ packWARN(WARN_DEBUGGING),
-                        "Attempt to free temp prematurely: SV 0x%" UVxf
-                        pTHX__FORMAT, PTR2UV(sv) pTHX__VALUE);
-               continue;
-           }
+            if (SvTEMP(sv)) {
+                Perl_ck_warner_d(aTHX_ packWARN(WARN_DEBUGGING),
+                         "Attempt to free temp prematurely: SV 0x%" UVxf
+                         pTHX__FORMAT, PTR2UV(sv) pTHX__VALUE);
+                continue;
+            }
 #endif
-           if (SvIMMORTAL(sv)) {
-               /* make sure SvREFCNT(sv)==0 happens very seldom */
-               SvREFCNT(sv) = SvREFCNT_IMMORTAL;
-               continue;
-           }
-           break;
-       } /* while 1 */
+            break;
+        } /* while 1 */
 
     } /* while sv */
 }
@@ -6923,18 +7115,18 @@ S_curse(pTHX_ SV * const sv, const bool check_refcnt) {
     assert(SvOBJECT(sv));
 
     if (PL_defstash && /* Still have a symbol table? */
-       SvDESTROYABLE(sv))
+        SvDESTROYABLE(sv))
     {
-       dSP;
-       HV* stash;
-       do {
-         stash = SvSTASH(sv);
-         assert(SvTYPE(stash) == SVt_PVHV);
-         if (HvNAME(stash)) {
-           CV* destructor = NULL;
+        dSP;
+        HV* stash;
+        do {
+          stash = SvSTASH(sv);
+          assert(SvTYPE(stash) == SVt_PVHV);
+          if (HvNAME(stash)) {
+            CV* destructor = NULL;
             struct mro_meta *meta;
 
-           assert (SvOOK(stash));
+            assert (HvHasAUX(stash));
 
             DEBUG_o( Perl_deb(aTHX_ "Looking for DESTROY method for %s\n",
                          HvNAME(stash)) );
@@ -6949,9 +7141,9 @@ S_curse(pTHX_ SV * const sv, const bool check_refcnt) {
             }
             else {
                 bool autoload = FALSE;
-               GV *gv =
+                GV *gv =
                     gv_fetchmeth_pvn(stash, S_destroy, S_destroy_len, -1, 0);
-               if (gv)
+                if (gv)
                     destructor = GvCV(gv);
                 if (!destructor) {
                     gv = gv_autoload_pvn(stash, S_destroy, S_destroy_len,
@@ -6975,68 +7167,68 @@ S_curse(pTHX_ SV * const sv, const bool check_refcnt) {
                     DEBUG_o( Perl_deb(aTHX_ "Not caching AUTOLOAD for DESTROY method for %s\n",
                                       HvNAME(stash)) );
                 }
-           }
-           assert(!destructor || SvTYPE(destructor) == SVt_PVCV);
-           if (destructor
-               /* A constant subroutine can have no side effects, so
-                  don't bother calling it.  */
-               && !CvCONST(destructor)
-               /* Don't bother calling an empty destructor or one that
-                  returns immediately. */
-               && (CvISXSUB(destructor)
-               || (CvSTART(destructor)
-                   && (CvSTART(destructor)->op_next->op_type
-                                       != OP_LEAVESUB)
-                   && (CvSTART(destructor)->op_next->op_type
-                                       != OP_PUSHMARK
-                       || CvSTART(destructor)->op_next->op_next->op_type
-                                       != OP_RETURN
-                      )
-                  ))
-              )
-           {
-               SV* const tmpref = newRV(sv);
-               SvREADONLY_on(tmpref); /* DESTROY() could be naughty */
-               ENTER;
-               PUSHSTACKi(PERLSI_DESTROY);
-               EXTEND(SP, 2);
-               PUSHMARK(SP);
-               PUSHs(tmpref);
-               PUTBACK;
-               call_sv(MUTABLE_SV(destructor),
-                           G_DISCARD|G_EVAL|G_KEEPERR|G_VOID);
-               POPSTACK;
-               SPAGAIN;
-               LEAVE;
-               if(SvREFCNT(tmpref) < 2) {
-                   /* tmpref is not kept alive! */
-                   SvREFCNT(sv)--;
-                   SvRV_set(tmpref, NULL);
-                   SvROK_off(tmpref);
-               }
-               SvREFCNT_dec_NN(tmpref);
-           }
-         }
-       } while (SvOBJECT(sv) && SvSTASH(sv) != stash);
-
-
-       if (check_refcnt && SvREFCNT(sv)) {
-           if (PL_in_clean_objs)
-               Perl_croak(aTHX_
-                 "DESTROY created new reference to dead object '%" HEKf "'",
-                  HEKfARG(HvNAME_HEK(stash)));
-           /* DESTROY gave object new lease on life */
-           return FALSE;
-       }
+            }
+            assert(!destructor || SvTYPE(destructor) == SVt_PVCV);
+            if (destructor
+                /* A constant subroutine can have no side effects, so
+                   don't bother calling it.  */
+                && !CvCONST(destructor)
+                /* Don't bother calling an empty destructor or one that
+                   returns immediately. */
+                && (CvISXSUB(destructor)
+                || (CvSTART(destructor)
+                    && (CvSTART(destructor)->op_next->op_type
+                                        != OP_LEAVESUB)
+                    && (CvSTART(destructor)->op_next->op_type
+                                        != OP_PUSHMARK
+                        || CvSTART(destructor)->op_next->op_next->op_type
+                                        != OP_RETURN
+                       )
+                   ))
+               )
+            {
+                SV* const tmpref = newRV(sv);
+                SvREADONLY_on(tmpref); /* DESTROY() could be naughty */
+                ENTER;
+                PUSHSTACKi(PERLSI_DESTROY);
+                EXTEND(SP, 2);
+                PUSHMARK(SP);
+                PUSHs(tmpref);
+                PUTBACK;
+                call_sv(MUTABLE_SV(destructor),
+                            G_DISCARD|G_EVAL|G_KEEPERR|G_VOID);
+                POPSTACK;
+                SPAGAIN;
+                LEAVE;
+                if(SvREFCNT(tmpref) < 2) {
+                    /* tmpref is not kept alive! */
+                    SvREFCNT(sv)--;
+                    SvRV_set(tmpref, NULL);
+                    SvROK_off(tmpref);
+                }
+                SvREFCNT_dec_NN(tmpref);
+            }
+          }
+        } while (SvOBJECT(sv) && SvSTASH(sv) != stash);
+
+
+        if (check_refcnt && SvREFCNT(sv)) {
+            if (PL_in_clean_objs)
+                Perl_croak(aTHX_
+                  "DESTROY created new reference to dead object '%" HEKf "'",
+                   HEKfARG(HvNAME_HEK(stash)));
+            /* DESTROY gave object new lease on life */
+            return FALSE;
+        }
     }
 
     if (SvOBJECT(sv)) {
-       HV * const stash = SvSTASH(sv);
-       /* Curse before freeing the stash, as freeing the stash could cause
-          a recursive call into S_curse. */
-       SvOBJECT_off(sv);       /* Curse the object. */
-       SvSTASH_set(sv,0);      /* SvREFCNT_dec may try to read this */
-       SvREFCNT_dec(stash); /* possibly of changed persuasion */
+        HV * const stash = SvSTASH(sv);
+        /* Curse before freeing the stash, as freeing the stash could cause
+           a recursive call into S_curse. */
+        SvOBJECT_off(sv);      /* Curse the object. */
+        SvSTASH_set(sv,0);     /* SvREFCNT_dec may try to read this */
+        SvREFCNT_dec(stash); /* possibly of changed persuasion */
     }
     return TRUE;
 }
@@ -7055,7 +7247,7 @@ Perl_sv_newref(pTHX_ SV *const sv)
 {
     PERL_UNUSED_CONTEXT;
     if (sv)
-       (SvREFCNT(sv))++;
+        (SvREFCNT(sv))++;
     return sv;
 }
 
@@ -7083,7 +7275,6 @@ Perl_sv_free(pTHX_ SV *const sv)
 void
 Perl_sv_free2(pTHX_ SV *const sv, const U32 rc)
 {
-    dVAR;
 
     PERL_ARGS_ASSERT_SV_FREE2;
 
@@ -7091,6 +7282,12 @@ Perl_sv_free2(pTHX_ SV *const sv, const U32 rc)
         /* normal case */
         SvREFCNT(sv) = 0;
 
+        if (SvIMMORTAL(sv)) {
+            /* make sure SvREFCNT(sv)==0 happens very seldom */
+            SvREFCNT(sv) = SvREFCNT_IMMORTAL;
+            SvTEMP_off(sv);
+            return;
+        }
 #ifdef DEBUGGING
         if (SvTEMP(sv)) {
             Perl_ck_warner_d(aTHX_ packWARN(WARN_DEBUGGING),
@@ -7099,11 +7296,6 @@ Perl_sv_free2(pTHX_ SV *const sv, const U32 rc)
             return;
         }
 #endif
-        if (SvIMMORTAL(sv)) {
-            /* make sure SvREFCNT(sv)==0 happens very seldom */
-            SvREFCNT(sv) = SvREFCNT_IMMORTAL;
-            return;
-        }
         sv_clear(sv);
         if (! SvREFCNT(sv)) /* may have have been resurrected */
             del_SV(sv);
@@ -7168,7 +7360,7 @@ Perl_sv_len(pTHX_ SV *const sv)
     STRLEN len;
 
     if (!sv)
-       return 0;
+        return 0;
 
     (void)SvPV_const(sv, len);
     return len;
@@ -7176,9 +7368,12 @@ Perl_sv_len(pTHX_ SV *const sv)
 
 /*
 =for apidoc sv_len_utf8
+=for apidoc_item sv_len_utf8_nomg
 
-Returns the number of characters in the string in an SV, counting wide
-UTF-8 bytes as a single character.  Handles magic and type coercion.
+These return the number of characters in the string in an SV, counting wide
+UTF-8 bytes as a single character.  Both handle type coercion.
+They differ only in that C<sv_len_utf8> performs 'get' magic;
+C<sv_len_utf8_nomg> skips any magic.
 
 =cut
 */
@@ -7196,7 +7391,7 @@ STRLEN
 Perl_sv_len_utf8(pTHX_ SV *const sv)
 {
     if (!sv)
-       return 0;
+        return 0;
 
     SvGETMAGIC(sv);
     return sv_len_utf8_nomg(sv);
@@ -7211,31 +7406,31 @@ Perl_sv_len_utf8_nomg(pTHX_ SV * const sv)
     PERL_ARGS_ASSERT_SV_LEN_UTF8_NOMG;
 
     if (PL_utf8cache && SvUTF8(sv)) {
-           STRLEN ulen;
-           MAGIC *mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_utf8) : NULL;
-
-           if (mg && (mg->mg_len != -1 || mg->mg_ptr)) {
-               if (mg->mg_len != -1)
-                   ulen = mg->mg_len;
-               else {
-                   /* We can use the offset cache for a headstart.
-                      The longer value is stored in the first pair.  */
-                   STRLEN *cache = (STRLEN *) mg->mg_ptr;
-
-                   ulen = cache[0] + Perl_utf8_length(aTHX_ s + cache[1],
-                                                      s + len);
-               }
-               
-               if (PL_utf8cache < 0) {
-                   const STRLEN real = Perl_utf8_length(aTHX_ s, s + len);
-                   assert_uft8_cache_coherent("sv_len_utf8", ulen, real, sv);
-               }
-           }
-           else {
-               ulen = Perl_utf8_length(aTHX_ s, s + len);
-               utf8_mg_len_cache_update(sv, &mg, ulen);
-           }
-           return ulen;
+            STRLEN ulen;
+            MAGIC *mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_utf8) : NULL;
+
+            if (mg && (mg->mg_len != -1 || mg->mg_ptr)) {
+                if (mg->mg_len != -1)
+                    ulen = mg->mg_len;
+                else {
+                    /* We can use the offset cache for a headstart.
+                       The longer value is stored in the first pair.  */
+                    STRLEN *cache = (STRLEN *) mg->mg_ptr;
+
+                    ulen = cache[0] + Perl_utf8_length(aTHX_ s + cache[1],
+                                                       s + len);
+                }
+
+                if (PL_utf8cache < 0) {
+                    const STRLEN real = Perl_utf8_length(aTHX_ s, s + len);
+                    assert_uft8_cache_coherent("sv_len_utf8", ulen, real, sv);
+                }
+            }
+            else {
+                ulen = Perl_utf8_length(aTHX_ s, s + len);
+                utf8_mg_len_cache_update(sv, &mg, ulen);
+            }
+            return ulen;
     }
     return SvUTF8(sv) ? Perl_utf8_length(aTHX_ s, s + len) : len;
 }
@@ -7244,7 +7439,8 @@ Perl_sv_len_utf8_nomg(pTHX_ SV * const sv)
    offset.  */
 static STRLEN
 S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send,
-                     STRLEN *const uoffset_p, bool *const at_end)
+                      STRLEN *const uoffset_p, bool *const at_end,
+                      bool* canonical_position)
 {
     const U8 *s = start;
     STRLEN uoffset = *uoffset_p;
@@ -7252,18 +7448,21 @@ S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send,
     PERL_ARGS_ASSERT_SV_POS_U2B_FORWARDS;
 
     while (s < send && uoffset) {
-       --uoffset;
-       s += UTF8SKIP(s);
+        --uoffset;
+        s += UTF8SKIP(s);
     }
     if (s == send) {
-       *at_end = TRUE;
+        *at_end = TRUE;
     }
     else if (s > send) {
-       *at_end = TRUE;
-       /* This is the existing behaviour. Possibly it should be a croak, as
-          it's actually a bounds error  */
-       s = send;
-    }
+        *at_end = TRUE;
+        /* This is the existing behaviour. Possibly it should be a croak, as
+           it's actually a bounds error  */
+        s = send;
+    }
+    /* If the unicode position is beyond the end, we return the end but
+       shouldn't cache that position */
+    *canonical_position = (uoffset == 0);
     *uoffset_p -= uoffset;
     return s - start;
 }
@@ -7273,31 +7472,27 @@ 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, const STRLEN uend)
+                    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).
-          (The real figure of course depends on the UTF-8 data.)  */
-       const U8 *s = start;
+        /* The assumption is that the average size of a character is 2 bytes,
+         * so going forwards is twice the speed of going backwards (that's
+         * where the 2 * backw comes from).  (The real figure of course depends
+         * on the UTF-8 data.)  */
+        const U8 *s = start;
 
-       while (s < send && uoffset--)
-           s += UTF8SKIP(s);
-       assert (s <= send);
-       if (s > send)
-           s = send;
-       return s - start;
+        s = utf8_hop_forward(s, uoffset, send);
+        assert (s <= send);
+        if (s > send)
+            s = send;
+        return s - start;
     }
 
-    while (backw--) {
-       send--;
-       while (UTF8_IS_CONTINUATION(*send))
-           send--;
-    }
+    send = utf8_hop_back(send, -backw, start);
     return send - start;
 }
 
@@ -7311,108 +7506,111 @@ S_sv_pos_u2b_midway(const U8 *const start, const U8 *send,
    created if necessary, and the found value offered to it for update.  */
 static STRLEN
 S_sv_pos_u2b_cached(pTHX_ SV *const sv, MAGIC **const mgp, const U8 *const start,
-                   const U8 *const send, STRLEN uoffset,
-                   STRLEN uoffset0, STRLEN boffset0)
+                    const U8 *const send, STRLEN uoffset,
+                    STRLEN uoffset0, STRLEN boffset0)
 {
     STRLEN boffset = 0; /* Actually always set, but let's keep gcc happy.  */
     bool found = FALSE;
     bool at_end = FALSE;
+    bool canonical_position = FALSE;
 
     PERL_ARGS_ASSERT_SV_POS_U2B_CACHED;
 
     assert (uoffset >= uoffset0);
 
     if (!uoffset)
-       return 0;
+        return 0;
 
     if (!SvREADONLY(sv) && !SvGMAGICAL(sv) && SvPOK(sv)
-       && PL_utf8cache
-       && (*mgp || (SvTYPE(sv) >= SVt_PVMG &&
-                    (*mgp = mg_find(sv, PERL_MAGIC_utf8))))) {
-       if ((*mgp)->mg_ptr) {
-           STRLEN *cache = (STRLEN *) (*mgp)->mg_ptr;
-           if (cache[0] == uoffset) {
-               /* An exact match. */
-               return cache[1];
-           }
-           if (cache[2] == uoffset) {
-               /* An exact match. */
-               return cache[3];
-           }
-
-           if (cache[0] < uoffset) {
-               /* The cache already knows part of the way.   */
-               if (cache[0] > uoffset0) {
-                   /* The cache knows more than the passed in pair  */
-                   uoffset0 = cache[0];
-                   boffset0 = cache[1];
-               }
-               if ((*mgp)->mg_len != -1) {
-                   /* And we know the end too.  */
-                   boffset = boffset0
-                       + sv_pos_u2b_midway(start + boffset0, send,
-                                             uoffset - uoffset0,
-                                             (*mgp)->mg_len - uoffset0);
-               } else {
-                   uoffset -= uoffset0;
-                   boffset = boffset0
-                       + sv_pos_u2b_forwards(start + boffset0,
-                                             send, &uoffset, &at_end);
-                   uoffset += uoffset0;
-               }
-           }
-           else if (cache[2] < uoffset) {
-               /* We're between the two cache entries.  */
-               if (cache[2] > uoffset0) {
-                   /* and the cache knows more than the passed in pair  */
-                   uoffset0 = cache[2];
-                   boffset0 = cache[3];
-               }
-
-               boffset = boffset0
-                   + sv_pos_u2b_midway(start + boffset0,
-                                         start + cache[1],
-                                         uoffset - uoffset0,
-                                         cache[0] - uoffset0);
-           } else {
-               boffset = boffset0
-                   + sv_pos_u2b_midway(start + boffset0,
-                                         start + cache[3],
-                                         uoffset - uoffset0,
-                                         cache[2] - uoffset0);
-           }
-           found = TRUE;
-       }
-       else if ((*mgp)->mg_len != -1) {
-           /* If we can take advantage of a passed in offset, do so.  */
-           /* In fact, offset0 is either 0, or less than offset, so don't
-              need to worry about the other possibility.  */
-           boffset = boffset0
-               + sv_pos_u2b_midway(start + boffset0, send,
-                                     uoffset - uoffset0,
-                                     (*mgp)->mg_len - uoffset0);
-           found = TRUE;
-       }
-    }
+        && PL_utf8cache
+        && (*mgp || (SvTYPE(sv) >= SVt_PVMG &&
+                     (*mgp = mg_find(sv, PERL_MAGIC_utf8))))) {
+        if ((*mgp)->mg_ptr) {
+            STRLEN *cache = (STRLEN *) (*mgp)->mg_ptr;
+            if (cache[0] == uoffset) {
+                /* An exact match. */
+                return cache[1];
+            }
+            if (cache[2] == uoffset) {
+                /* An exact match. */
+                return cache[3];
+            }
 
-    if (!found || PL_utf8cache < 0) {
-       STRLEN real_boffset;
-       uoffset -= uoffset0;
-       real_boffset = boffset0 + sv_pos_u2b_forwards(start + boffset0,
-                                                     send, &uoffset, &at_end);
-       uoffset += uoffset0;
+            if (cache[0] < uoffset) {
+                /* The cache already knows part of the way.   */
+                if (cache[0] > uoffset0) {
+                    /* The cache knows more than the passed in pair  */
+                    uoffset0 = cache[0];
+                    boffset0 = cache[1];
+                }
+                if ((*mgp)->mg_len != -1) {
+                    /* And we know the end too.  */
+                    boffset = boffset0
+                        + sv_pos_u2b_midway(start + boffset0, send,
+                                              uoffset - uoffset0,
+                                              (*mgp)->mg_len - uoffset0);
+                } else {
+                    uoffset -= uoffset0;
+                    boffset = boffset0
+                        + sv_pos_u2b_forwards(start + boffset0,
+                                              send, &uoffset, &at_end,
+                                              &canonical_position);
+                    uoffset += uoffset0;
+                }
+            }
+            else if (cache[2] < uoffset) {
+                /* We're between the two cache entries.  */
+                if (cache[2] > uoffset0) {
+                    /* and the cache knows more than the passed in pair  */
+                    uoffset0 = cache[2];
+                    boffset0 = cache[3];
+                }
 
-       if (found && PL_utf8cache < 0)
-           assert_uft8_cache_coherent("sv_pos_u2b_cache", boffset,
-                                      real_boffset, sv);
-       boffset = real_boffset;
+                boffset = boffset0
+                    + sv_pos_u2b_midway(start + boffset0,
+                                          start + cache[1],
+                                          uoffset - uoffset0,
+                                          cache[0] - uoffset0);
+            } else {
+                boffset = boffset0
+                    + sv_pos_u2b_midway(start + boffset0,
+                                          start + cache[3],
+                                          uoffset - uoffset0,
+                                          cache[2] - uoffset0);
+            }
+            found = TRUE;
+        }
+        else if ((*mgp)->mg_len != -1) {
+            /* If we can take advantage of a passed in offset, do so.  */
+            /* In fact, offset0 is either 0, or less than offset, so don't
+               need to worry about the other possibility.  */
+            boffset = boffset0
+                + sv_pos_u2b_midway(start + boffset0, send,
+                                      uoffset - uoffset0,
+                                      (*mgp)->mg_len - uoffset0);
+            found = TRUE;
+        }
     }
 
-    if (PL_utf8cache && !SvGMAGICAL(sv) && SvPOK(sv)) {
-       if (at_end)
-           utf8_mg_len_cache_update(sv, mgp, uoffset);
-       else
-           utf8_mg_pos_cache_update(sv, mgp, boffset, uoffset, send - start);
+    if (!found || PL_utf8cache < 0) {
+        STRLEN real_boffset;
+        uoffset -= uoffset0;
+        real_boffset = boffset0 + sv_pos_u2b_forwards(start + boffset0,
+                                                      send, &uoffset, &at_end,
+                                                      &canonical_position);
+        uoffset += uoffset0;
+
+        if (found && PL_utf8cache < 0)
+            assert_uft8_cache_coherent("sv_pos_u2b_cache", boffset,
+                                       real_boffset, sv);
+        boffset = real_boffset;
+    }
+
+    if (PL_utf8cache && canonical_position && !SvGMAGICAL(sv) && SvPOK(sv)) {
+        if (at_end)
+            utf8_mg_len_cache_update(sv, mgp, uoffset);
+        else
+            utf8_mg_pos_cache_update(sv, mgp, boffset, uoffset, send - start);
     }
     return boffset;
 }
@@ -7441,7 +7639,7 @@ C<SV_GMAGIC|SV_CONST_RETURN> to handle magic.
 
 STRLEN
 Perl_sv_pos_u2b_flags(pTHX_ SV *const sv, STRLEN uoffset, STRLEN *const lenp,
-                     U32 flags)
+                      U32 flags)
 {
     const U8 *start;
     STRLEN len;
@@ -7451,25 +7649,25 @@ Perl_sv_pos_u2b_flags(pTHX_ SV *const sv, STRLEN uoffset, STRLEN *const lenp,
 
     start = (U8*)SvPV_flags(sv, len, flags);
     if (len) {
-       const U8 * const send = start + len;
-       MAGIC *mg = NULL;
-       boffset = sv_pos_u2b_cached(sv, &mg, start, send, uoffset, 0, 0);
-
-       if (lenp
-           && *lenp /* don't bother doing work for 0, as its bytes equivalent
-                       is 0, and *lenp is already set to that.  */) {
-           /* Convert the relative offset to absolute.  */
-           const STRLEN uoffset2 = uoffset + *lenp;
-           const STRLEN boffset2
-               = sv_pos_u2b_cached(sv, &mg, start, send, uoffset2,
-                                     uoffset, boffset) - boffset;
-
-           *lenp = boffset2;
-       }
+        const U8 * const send = start + len;
+        MAGIC *mg = NULL;
+        boffset = sv_pos_u2b_cached(sv, &mg, start, send, uoffset, 0, 0);
+
+        if (lenp
+            && *lenp /* don't bother doing work for 0, as its bytes equivalent
+                        is 0, and *lenp is already set to that.  */) {
+            /* Convert the relative offset to absolute.  */
+            const STRLEN uoffset2 = uoffset + *lenp;
+            const STRLEN boffset2
+                = sv_pos_u2b_cached(sv, &mg, start, send, uoffset2,
+                                      uoffset, boffset) - boffset;
+
+            *lenp = boffset2;
+        }
     } else {
-       if (lenp)
-           *lenp = 0;
-       boffset = 0;
+        if (lenp)
+            *lenp = 0;
+        boffset = 0;
     }
 
     return boffset;
@@ -7505,27 +7703,27 @@ Perl_sv_pos_u2b(pTHX_ SV *const sv, I32 *const offsetp, I32 *const lenp)
     PERL_ARGS_ASSERT_SV_POS_U2B;
 
     if (lenp) {
-       STRLEN ulen = (STRLEN)*lenp;
-       *offsetp = (I32)sv_pos_u2b_flags(sv, (STRLEN)*offsetp, &ulen,
-                                        SV_GMAGIC|SV_CONST_RETURN);
-       *lenp = (I32)ulen;
+        STRLEN ulen = (STRLEN)*lenp;
+        *offsetp = (I32)sv_pos_u2b_flags(sv, (STRLEN)*offsetp, &ulen,
+                                         SV_GMAGIC|SV_CONST_RETURN);
+        *lenp = (I32)ulen;
     } else {
-       *offsetp = (I32)sv_pos_u2b_flags(sv, (STRLEN)*offsetp, NULL,
-                                        SV_GMAGIC|SV_CONST_RETURN);
+        *offsetp = (I32)sv_pos_u2b_flags(sv, (STRLEN)*offsetp, NULL,
+                                         SV_GMAGIC|SV_CONST_RETURN);
     }
 }
 
 static void
 S_utf8_mg_len_cache_update(pTHX_ SV *const sv, MAGIC **const mgp,
-                          const STRLEN ulen)
+                           const STRLEN ulen)
 {
     PERL_ARGS_ASSERT_UTF8_MG_LEN_CACHE_UPDATE;
     if (SvREADONLY(sv) || SvGMAGICAL(sv) || !SvPOK(sv))
-       return;
+        return;
 
     if (!*mgp && (SvTYPE(sv) < SVt_PVMG ||
-                 !(*mgp = mg_find(sv, PERL_MAGIC_utf8)))) {
-       *mgp = sv_magicext(sv, 0, PERL_MAGIC_utf8, &PL_vtbl_utf8, 0, 0);
+                  !(*mgp = mg_find(sv, PERL_MAGIC_utf8)))) {
+        *mgp = sv_magicext(sv, 0, PERL_MAGIC_utf8, &PL_vtbl_utf8, 0, 0);
     }
     assert(*mgp);
 
@@ -7553,7 +7751,7 @@ S_utf8_mg_len_cache_update(pTHX_ SV *const sv, MAGIC **const mgp,
    the code that uses it doesn't need to worry if only 1 entry has actually
    been set to non-zero.  It also makes the "position beyond the end of the
    cache" logic much simpler, as the first slot is always the one to start
-   from.   
+   from.
 */
 static void
 S_utf8_mg_pos_cache_update(pTHX_ SV *const sv, MAGIC **const mgp, const STRLEN byte,
@@ -7564,110 +7762,110 @@ S_utf8_mg_pos_cache_update(pTHX_ SV *const sv, MAGIC **const mgp, const STRLEN b
     PERL_ARGS_ASSERT_UTF8_MG_POS_CACHE_UPDATE;
 
     if (SvREADONLY(sv))
-       return;
+        return;
 
     if (!*mgp && (SvTYPE(sv) < SVt_PVMG ||
-                 !(*mgp = mg_find(sv, PERL_MAGIC_utf8)))) {
-       *mgp = sv_magicext(sv, 0, PERL_MAGIC_utf8, (MGVTBL*)&PL_vtbl_utf8, 0,
-                          0);
-       (*mgp)->mg_len = -1;
+                  !(*mgp = mg_find(sv, PERL_MAGIC_utf8)))) {
+        *mgp = sv_magicext(sv, 0, PERL_MAGIC_utf8, (MGVTBL*)&PL_vtbl_utf8, 0,
+                           0);
+        (*mgp)->mg_len = -1;
     }
     assert(*mgp);
 
     if (!(cache = (STRLEN *)(*mgp)->mg_ptr)) {
-       Newxz(cache, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
-       (*mgp)->mg_ptr = (char *) cache;
+        Newxz(cache, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
+        (*mgp)->mg_ptr = (char *) cache;
     }
     assert(cache);
 
     if (PL_utf8cache < 0 && SvPOKp(sv)) {
-       /* SvPOKp() because, if sv is a reference, then SvPVX() is actually
-          a pointer.  Note that we no longer cache utf8 offsets on refer-
-          ences, but this check is still a good idea, for robustness.  */
-       const U8 *start = (const U8 *) SvPVX_const(sv);
-       const STRLEN realutf8 = utf8_length(start, start + byte);
+        /* SvPOKp() because, if sv is a reference, then SvPVX() is actually
+           a pointer.  Note that we no longer cache utf8 offsets on refer-
+           ences, but this check is still a good idea, for robustness.  */
+        const U8 *start = (const U8 *) SvPVX_const(sv);
+        const STRLEN realutf8 = utf8_length(start, start + byte);
 
-       assert_uft8_cache_coherent("utf8_mg_pos_cache_update", utf8, realutf8,
-                                  sv);
+        assert_uft8_cache_coherent("utf8_mg_pos_cache_update", utf8, realutf8,
+                                   sv);
     }
 
     /* Cache is held with the later position first, to simplify the code
        that deals with unbounded ends.  */
-       
+
     ASSERT_UTF8_CACHE(cache);
     if (cache[1] == 0) {
-       /* Cache is totally empty  */
-       cache[0] = utf8;
-       cache[1] = byte;
+        /* Cache is totally empty  */
+        cache[0] = utf8;
+        cache[1] = byte;
     } else if (cache[3] == 0) {
-       if (byte > cache[1]) {
-           /* New one is larger, so goes first.  */
-           cache[2] = cache[0];
-           cache[3] = cache[1];
-           cache[0] = utf8;
-           cache[1] = byte;
-       } else {
-           cache[2] = utf8;
-           cache[3] = byte;
-       }
+        if (byte > cache[1]) {
+            /* New one is larger, so goes first.  */
+            cache[2] = cache[0];
+            cache[3] = cache[1];
+            cache[0] = utf8;
+            cache[1] = byte;
+        } else {
+            cache[2] = utf8;
+            cache[3] = byte;
+        }
     } else {
 /* float casts necessary? XXX */
 #define THREEWAY_SQUARE(a,b,c,d) \
-           ((float)((d) - (c))) * ((float)((d) - (c))) \
-           + ((float)((c) - (b))) * ((float)((c) - (b))) \
-              + ((float)((b) - (a))) * ((float)((b) - (a)))
-
-       /* Cache has 2 slots in use, and we know three potential pairs.
-          Keep the two that give the lowest RMS distance. Do the
-          calculation in bytes simply because we always know the byte
-          length.  squareroot has the same ordering as the positive value,
-          so don't bother with the actual square root.  */
-       if (byte > cache[1]) {
-           /* New position is after the existing pair of pairs.  */
-           const float keep_earlier
-               = THREEWAY_SQUARE(0, cache[3], byte, blen);
-           const float keep_later
-               = THREEWAY_SQUARE(0, cache[1], byte, blen);
-
-           if (keep_later < keep_earlier) {
+            ((float)((d) - (c))) * ((float)((d) - (c))) \
+            + ((float)((c) - (b))) * ((float)((c) - (b))) \
+               + ((float)((b) - (a))) * ((float)((b) - (a)))
+
+        /* Cache has 2 slots in use, and we know three potential pairs.
+           Keep the two that give the lowest RMS distance. Do the
+           calculation in bytes simply because we always know the byte
+           length.  squareroot has the same ordering as the positive value,
+           so don't bother with the actual square root.  */
+        if (byte > cache[1]) {
+            /* New position is after the existing pair of pairs.  */
+            const float keep_earlier
+                = THREEWAY_SQUARE(0, cache[3], byte, blen);
+            const float keep_later
+                = THREEWAY_SQUARE(0, cache[1], byte, blen);
+
+            if (keep_later < keep_earlier) {
                 cache[2] = cache[0];
                 cache[3] = cache[1];
-           }
+            }
             cache[0] = utf8;
             cache[1] = byte;
-       }
-       else {
-           const float keep_later = THREEWAY_SQUARE(0, byte, cache[1], blen);
-           float b, c, keep_earlier;
-           if (byte > cache[3]) {
-               /* New position is between the existing pair of pairs.  */
-               b = (float)cache[3];
-               c = (float)byte;
-           } else {
-               /* New position is before the existing pair of pairs.  */
-               b = (float)byte;
-               c = (float)cache[3];
-           }
-           keep_earlier = THREEWAY_SQUARE(0, b, c, blen);
-           if (byte > cache[3]) {
-               if (keep_later < keep_earlier) {
-                   cache[2] = utf8;
-                   cache[3] = byte;
-               }
-               else {
-                   cache[0] = utf8;
-                   cache[1] = byte;
-               }
-           }
-           else {
-               if (! (keep_later < keep_earlier)) {
-                   cache[0] = cache[2];
-                   cache[1] = cache[3];
-               }
-               cache[2] = utf8;
-               cache[3] = byte;
-           }
-       }
+        }
+        else {
+            const float keep_later = THREEWAY_SQUARE(0, byte, cache[1], blen);
+            float b, c, keep_earlier;
+            if (byte > cache[3]) {
+                /* New position is between the existing pair of pairs.  */
+                b = (float)cache[3];
+                c = (float)byte;
+            } else {
+                /* New position is before the existing pair of pairs.  */
+                b = (float)byte;
+                c = (float)cache[3];
+            }
+            keep_earlier = THREEWAY_SQUARE(0, b, c, blen);
+            if (byte > cache[3]) {
+                if (keep_later < keep_earlier) {
+                    cache[2] = utf8;
+                    cache[3] = byte;
+                }
+                else {
+                    cache[0] = utf8;
+                    cache[1] = byte;
+                }
+            }
+            else {
+                if (! (keep_later < keep_earlier)) {
+                    cache[0] = cache[2];
+                    cache[1] = cache[3];
+                }
+                cache[2] = utf8;
+                cache[3] = byte;
+            }
+        }
     }
     ASSERT_UTF8_CACHE(cache);
 }
@@ -7685,15 +7883,12 @@ S_sv_pos_b2u_midway(pTHX_ const U8 *const s, const U8 *const target,
     PERL_ARGS_ASSERT_SV_POS_B2U_MIDWAY;
 
     if (forw < 2 * backw) {
-       return utf8_length(s, target);
+        return utf8_length(s, target);
     }
 
     while (end > target) {
-       end--;
-       while (UTF8_IS_CONTINUATION(*end)) {
-           end--;
-       }
-       endu--;
+        end = utf8_hop_back(end, -1, target);
+        endu--;
     }
     return endu;
 }
@@ -7730,73 +7925,73 @@ Perl_sv_pos_b2u_flags(pTHX_ SV *const sv, STRLEN const offset, U32 flags)
     s = (const U8*)SvPV_flags(sv, blen, flags);
 
     if (blen < offset)
-       Perl_croak(aTHX_ "panic: sv_pos_b2u: bad byte offset, blen=%" UVuf
-                  ", byte=%" UVuf, (UV)blen, (UV)offset);
+        Perl_croak(aTHX_ "panic: sv_pos_b2u: bad byte offset, blen=%" UVuf
+                   ", byte=%" UVuf, (UV)blen, (UV)offset);
 
     send = s + offset;
 
     if (!SvREADONLY(sv)
-       && PL_utf8cache
-       && SvTYPE(sv) >= SVt_PVMG
-       && (mg = mg_find(sv, PERL_MAGIC_utf8)))
+        && PL_utf8cache
+        && SvTYPE(sv) >= SVt_PVMG
+        && (mg = mg_find(sv, PERL_MAGIC_utf8)))
     {
-       if (mg->mg_ptr) {
-           STRLEN * const cache = (STRLEN *) mg->mg_ptr;
-           if (cache[1] == offset) {
-               /* An exact match. */
-               return cache[0];
-           }
-           if (cache[3] == offset) {
-               /* An exact match. */
-               return cache[2];
-           }
-
-           if (cache[1] < offset) {
-               /* We already know part of the way. */
-               if (mg->mg_len != -1) {
-                   /* Actually, we know the end too.  */
-                   len = cache[0]
-                       + S_sv_pos_b2u_midway(aTHX_ s + cache[1], send,
-                                             s + blen, mg->mg_len - cache[0]);
-               } else {
-                   len = cache[0] + utf8_length(s + cache[1], send);
-               }
-           }
-           else if (cache[3] < offset) {
-               /* We're between the two cached pairs, so we do the calculation
-                  offset by the byte/utf-8 positions for the earlier pair,
-                  then add the utf-8 characters from the string start to
-                  there.  */
-               len = S_sv_pos_b2u_midway(aTHX_ s + cache[3], send,
-                                         s + cache[1], cache[0] - cache[2])
-                   + cache[2];
-
-           }
-           else { /* cache[3] > offset */
-               len = S_sv_pos_b2u_midway(aTHX_ s, send, s + cache[3],
-                                         cache[2]);
-
-           }
-           ASSERT_UTF8_CACHE(cache);
-           found = TRUE;
-       } else if (mg->mg_len != -1) {
-           len = S_sv_pos_b2u_midway(aTHX_ s, send, s + blen, mg->mg_len);
-           found = TRUE;
-       }
+        if (mg->mg_ptr) {
+            STRLEN * const cache = (STRLEN *) mg->mg_ptr;
+            if (cache[1] == offset) {
+                /* An exact match. */
+                return cache[0];
+            }
+            if (cache[3] == offset) {
+                /* An exact match. */
+                return cache[2];
+            }
+
+            if (cache[1] < offset) {
+                /* We already know part of the way. */
+                if (mg->mg_len != -1) {
+                    /* Actually, we know the end too.  */
+                    len = cache[0]
+                        + S_sv_pos_b2u_midway(aTHX_ s + cache[1], send,
+                                              s + blen, mg->mg_len - cache[0]);
+                } else {
+                    len = cache[0] + utf8_length(s + cache[1], send);
+                }
+            }
+            else if (cache[3] < offset) {
+                /* We're between the two cached pairs, so we do the calculation
+                   offset by the byte/utf-8 positions for the earlier pair,
+                   then add the utf-8 characters from the string start to
+                   there.  */
+                len = S_sv_pos_b2u_midway(aTHX_ s + cache[3], send,
+                                          s + cache[1], cache[0] - cache[2])
+                    + cache[2];
+
+            }
+            else { /* cache[3] > offset */
+                len = S_sv_pos_b2u_midway(aTHX_ s, send, s + cache[3],
+                                          cache[2]);
+
+            }
+            ASSERT_UTF8_CACHE(cache);
+            found = TRUE;
+        } else if (mg->mg_len != -1) {
+            len = S_sv_pos_b2u_midway(aTHX_ s, send, s + blen, mg->mg_len);
+            found = TRUE;
+        }
     }
     if (!found || PL_utf8cache < 0) {
-       const STRLEN real_len = utf8_length(s, send);
+        const STRLEN real_len = utf8_length(s, send);
 
-       if (found && PL_utf8cache < 0)
-           assert_uft8_cache_coherent("sv_pos_b2u", len, real_len, sv);
-       len = real_len;
+        if (found && PL_utf8cache < 0)
+            assert_uft8_cache_coherent("sv_pos_b2u", len, real_len, sv);
+        len = real_len;
     }
 
     if (PL_utf8cache) {
-       if (blen == offset)
-           utf8_mg_len_cache_update(sv, &mg, len);
-       else
-           utf8_mg_pos_cache_update(sv, &mg, offset, len, blen);
+        if (blen == offset)
+            utf8_mg_len_cache_update(sv, &mg, len);
+        else
+            utf8_mg_pos_cache_update(sv, &mg, offset, len, blen);
     }
 
     return len;
@@ -7827,43 +8022,46 @@ Perl_sv_pos_b2u(pTHX_ SV *const sv, I32 *const offsetp)
     PERL_ARGS_ASSERT_SV_POS_B2U;
 
     if (!sv)
-       return;
+        return;
 
     *offsetp = (I32)sv_pos_b2u_flags(sv, (STRLEN)*offsetp,
-                                    SV_GMAGIC|SV_CONST_RETURN);
+                                     SV_GMAGIC|SV_CONST_RETURN);
 }
 
 static void
 S_assert_uft8_cache_coherent(pTHX_ const char *const func, STRLEN from_cache,
-                            STRLEN real, SV *const sv)
+                             STRLEN real, SV *const sv)
 {
     PERL_ARGS_ASSERT_ASSERT_UFT8_CACHE_COHERENT;
 
     /* As this is debugging only code, save space by keeping this test here,
        rather than inlining it in all the callers.  */
     if (from_cache == real)
-       return;
+        return;
 
     /* Need to turn the assertions off otherwise we may recurse infinitely
        while printing error messages.  */
     SAVEI8(PL_utf8cache);
     PL_utf8cache = 0;
     Perl_croak(aTHX_ "panic: %s cache %" UVuf " real %" UVuf " for %" SVf,
-              func, (UV) from_cache, (UV) real, SVfARG(sv));
+               func, (UV) from_cache, (UV) real, SVfARG(sv));
 }
 
 /*
-=for apidoc sv_eq
+=for apidoc      sv_eq
+=for apidoc_item sv_eq_flags
 
-Returns a boolean indicating whether the strings in the two SVs are
-identical.  Is UTF-8 and S<C<'use bytes'>> aware, handles get magic, and will
-coerce its args to strings if necessary.
+These each return a boolean indicating whether or not the strings in the two
+SVs are equal.  If S<C<'use bytes'>> is in effect, the comparison is
+byte-by-byte; otherwise character-by-character.  Each will coerce its args to
+strings if necessary.
 
-=for apidoc sv_eq_flags
+They differ only in that C<sv_eq> always processes get magic, while
+C<sv_eq_flags> processes get magic only when the C<flags> parameter has the
+C<SV_GMAGIC> bit set.
 
-Returns a boolean indicating whether the strings in the two SVs are
-identical.  Is UTF-8 and S<C<'use bytes'>> aware and coerces its args to strings
-if necessary.  If the flags has the C<SV_GMAGIC> bit set, it handles get-magic, too.
+These functions do not handle operator overloading.  For versions that do,
+see instead C<L</sv_streq>> or C<L</sv_streq_flags>>.
 
 =cut
 */
@@ -7877,46 +8075,142 @@ Perl_sv_eq_flags(pTHX_ SV *sv1, SV *sv2, const U32 flags)
     STRLEN cur2;
 
     if (!sv1) {
-       pv1 = "";
-       cur1 = 0;
+        pv1 = "";
+        cur1 = 0;
     }
     else {
-       /* if pv1 and pv2 are the same, second SvPV_const call may
-        * invalidate pv1 (if we are handling magic), so we may need to
-        * make a copy */
-       if (sv1 == sv2 && flags & SV_GMAGIC
-        && (SvTHINKFIRST(sv1) || SvGMAGICAL(sv1))) {
-           pv1 = SvPV_const(sv1, cur1);
-           sv1 = newSVpvn_flags(pv1, cur1, SVs_TEMP | SvUTF8(sv2));
-       }
-       pv1 = SvPV_flags_const(sv1, cur1, flags);
+        /* if pv1 and pv2 are the same, second SvPV_const call may
+         * invalidate pv1 (if we are handling magic), so we may need to
+         * make a copy */
+        if (sv1 == sv2 && flags & SV_GMAGIC
+         && (SvTHINKFIRST(sv1) || SvGMAGICAL(sv1))) {
+            pv1 = SvPV_const(sv1, cur1);
+            sv1 = newSVpvn_flags(pv1, cur1, SVs_TEMP | SvUTF8(sv2));
+        }
+        pv1 = SvPV_flags_const(sv1, cur1, flags);
     }
 
     if (!sv2){
-       pv2 = "";
-       cur2 = 0;
+        pv2 = "";
+        cur2 = 0;
     }
     else
-       pv2 = SvPV_flags_const(sv2, cur2, flags);
+        pv2 = SvPV_flags_const(sv2, cur2, flags);
 
     if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTES) {
         /* Differing utf8ness.  */
-       if (SvUTF8(sv1)) {
-                 /* sv1 is the UTF-8 one  */
-                 return bytes_cmp_utf8((const U8*)pv2, cur2,
-                                       (const U8*)pv1, cur1) == 0;
-       }
-       else {
-                 /* sv2 is the UTF-8 one  */
-                 return bytes_cmp_utf8((const U8*)pv1, cur1,
-                                       (const U8*)pv2, cur2) == 0;
-       }
+        if (SvUTF8(sv1)) {
+                  /* sv1 is the UTF-8 one  */
+                  return bytes_cmp_utf8((const U8*)pv2, cur2,
+                                        (const U8*)pv1, cur1) == 0;
+        }
+        else {
+                  /* sv2 is the UTF-8 one  */
+                  return bytes_cmp_utf8((const U8*)pv1, cur1,
+                                        (const U8*)pv2, cur2) == 0;
+        }
     }
 
     if (cur1 == cur2)
-       return (pv1 == pv2) || memEQ(pv1, pv2, cur1);
+        return (pv1 == pv2) || memEQ(pv1, pv2, cur1);
     else
-       return 0;
+        return 0;
+}
+
+/*
+=for apidoc sv_streq_flags
+
+Returns a boolean indicating whether the strings in the two SVs are
+identical. If the flags argument has the C<SV_GMAGIC> bit set, it handles
+get-magic too. Will coerce its args to strings if necessary. Treats
+C<NULL> as undef. Correctly handles the UTF8 flag.
+
+If flags does not have the C<SV_SKIP_OVERLOAD> bit set, an attempt to use
+C<eq> overloading will be made. If such overloading does not exist or the
+flag is set, then regular string comparison will be used instead.
+
+=for apidoc sv_streq
+
+A convenient shortcut for calling C<sv_streq_flags> with the C<SV_GMAGIC>
+flag. This function basically behaves like the Perl code C<$sv1 eq $sv2>.
+
+=cut
+*/
+
+bool
+Perl_sv_streq_flags(pTHX_ SV *sv1, SV *sv2, const U32 flags)
+{
+    PERL_ARGS_ASSERT_SV_STREQ_FLAGS;
+
+    if(flags & SV_GMAGIC) {
+        if(sv1)
+            SvGETMAGIC(sv1);
+        if(sv2)
+            SvGETMAGIC(sv2);
+    }
+
+    /* Treat NULL as undef */
+    if(!sv1)
+        sv1 = &PL_sv_undef;
+    if(!sv2)
+        sv2 = &PL_sv_undef;
+
+    if(!(flags & SV_SKIP_OVERLOAD) &&
+            (SvAMAGIC(sv1) || SvAMAGIC(sv2))) {
+        SV *ret = amagic_call(sv1, sv2, seq_amg, 0);
+        if(ret)
+            return SvTRUE(ret);
+    }
+
+    return sv_eq_flags(sv1, sv2, 0);
+}
+
+/*
+=for apidoc sv_numeq_flags
+
+Returns a boolean indicating whether the numbers in the two SVs are
+identical. If the flags argument has the C<SV_GMAGIC> bit set, it handles
+get-magic too. Will coerce its args to numbers if necessary. Treats
+C<NULL> as undef.
+
+If flags does not have the C<SV_SKIP_OVERLOAD> bit set, an attempt to use
+C<==> overloading will be made. If such overloading does not exist or the
+flag is set, then regular numerical comparison will be used instead.
+
+=for apidoc sv_numeq
+
+A convenient shortcut for calling C<sv_numeq_flags> with the C<SV_GMAGIC>
+flag. This function basically behaves like the Perl code C<$sv1 == $sv2>.
+
+=cut
+*/
+
+bool
+Perl_sv_numeq_flags(pTHX_ SV *sv1, SV *sv2, const U32 flags)
+{
+    PERL_ARGS_ASSERT_SV_NUMEQ_FLAGS;
+
+    if(flags & SV_GMAGIC) {
+        if(sv1)
+            SvGETMAGIC(sv1);
+        if(sv2)
+            SvGETMAGIC(sv2);
+    }
+
+    /* Treat NULL as undef */
+    if(!sv1)
+        sv1 = &PL_sv_undef;
+    if(!sv2)
+        sv2 = &PL_sv_undef;
+
+    if(!(flags & SV_SKIP_OVERLOAD) &&
+            (SvAMAGIC(sv1) || SvAMAGIC(sv2))) {
+        SV *ret = amagic_call(sv1, sv2, eq_amg, 0);
+        if(ret)
+            return SvTRUE(ret);
+    }
+
+    return do_ncmp(sv1, sv2) == 0;
 }
 
 /*
@@ -7946,7 +8240,7 @@ Perl_sv_cmp(pTHX_ SV *const sv1, SV *const sv2)
 
 I32
 Perl_sv_cmp_flags(pTHX_ SV *const sv1, SV *const sv2,
-                 const U32 flags)
+                  const U32 flags)
 {
     STRLEN cur1, cur2;
     const char *pv1, *pv2;
@@ -7954,39 +8248,39 @@ Perl_sv_cmp_flags(pTHX_ SV *const sv1, SV *const sv2,
     SV *svrecode = NULL;
 
     if (!sv1) {
-       pv1 = "";
-       cur1 = 0;
+        pv1 = "";
+        cur1 = 0;
     }
     else
-       pv1 = SvPV_flags_const(sv1, cur1, flags);
+        pv1 = SvPV_flags_const(sv1, cur1, flags);
 
     if (!sv2) {
-       pv2 = "";
-       cur2 = 0;
+        pv2 = "";
+        cur2 = 0;
     }
     else
-       pv2 = SvPV_flags_const(sv2, cur2, flags);
+        pv2 = SvPV_flags_const(sv2, cur2, flags);
 
     if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTES) {
         /* Differing utf8ness.  */
-       if (SvUTF8(sv1)) {
-               const int retval = -bytes_cmp_utf8((const U8*)pv2, cur2,
-                                                  (const U8*)pv1, cur1);
-               return retval ? retval < 0 ? -1 : +1 : 0;
-       }
-       else {
-               const int retval = bytes_cmp_utf8((const U8*)pv1, cur1,
-                                                 (const U8*)pv2, cur2);
-               return retval ? retval < 0 ? -1 : +1 : 0;
-       }
+        if (SvUTF8(sv1)) {
+                const int retval = -bytes_cmp_utf8((const U8*)pv2, cur2,
+                                                   (const U8*)pv1, cur1);
+                return retval ? retval < 0 ? -1 : +1 : 0;
+        }
+        else {
+                const int retval = bytes_cmp_utf8((const U8*)pv1, cur1,
+                                                  (const U8*)pv2, cur2);
+                return retval ? retval < 0 ? -1 : +1 : 0;
+        }
     }
 
     /* Here, if both are non-NULL, then they have the same UTF8ness. */
 
     if (!cur1) {
-       cmp = cur2 ? -1 : 0;
+        cmp = cur2 ? -1 : 0;
     } else if (!cur2) {
-       cmp = 1;
+        cmp = 1;
     } else {
         STRLEN shortest_len = cur1 < cur2 ? cur1 : cur2;
 
@@ -8037,7 +8331,7 @@ Perl_sv_cmp_flags(pTHX_ SV *const sv1, SV *const sv2,
                     * at the beginning of a character.  But neither or both are
                     * (or else earlier bytes would have been different).  And
                     * if we are in the middle of a character, the two
-                    * characters are comprised of the same number of bytes
+                    * characters have the same number of bytes
                     * (because in this case the start bytes are the same, and
                     * the start bytes encode the character's length). */
                  if (UTF8_IS_INVARIANT(*pv1))
@@ -8174,7 +8468,7 @@ Perl_sv_cmp_locale(pTHX_ SV *const sv1, SV *const sv2)
 
 I32
 Perl_sv_cmp_locale_flags(pTHX_ SV *const sv1, SV *const sv2,
-                        const U32 flags)
+                         const U32 flags)
 {
 #ifdef USE_LOCALE_COLLATE
 
@@ -8183,7 +8477,7 @@ Perl_sv_cmp_locale_flags(pTHX_ SV *const sv1, SV *const sv2,
     I32 retval;
 
     if (PL_collation_standard)
-       goto raw_compare;
+        goto raw_compare;
 
     len1 = len2 = 0;
 
@@ -8205,20 +8499,20 @@ Perl_sv_cmp_locale_flags(pTHX_ SV *const sv1, SV *const sv2,
     }
 
     if (!pv1 || !len1) {
-       if (pv2 && len2)
-           return -1;
-       else
-           goto raw_compare;
+        if (pv2 && len2)
+            return -1;
+        else
+            goto raw_compare;
     }
     else {
-       if (!pv2 || !len2)
-           return 1;
+        if (!pv2 || !len2)
+            return 1;
     }
 
     retval = memcmp((void*)pv1, (void*)pv2, len1 < len2 ? len1 : len2);
 
     if (retval)
-       return retval < 0 ? -1 : 1;
+        return retval < 0 ? -1 : 1;
 
     /*
      * When the result of collation is equality, that doesn't mean
@@ -8271,39 +8565,39 @@ Perl_sv_collxfrm_flags(pTHX_ SV *const sv, STRLEN *const nxp, const I32 flags)
     /* If we don't have collation magic on 'sv', or the locale has changed
      * since the last time we calculated it, get it and save it now */
     if (!mg || !mg->mg_ptr || *(U32*)mg->mg_ptr != PL_collation_ix) {
-       const char *s;
-       char *xf;
-       STRLEN len, xlen;
+        const char *s;
+        char *xf;
+        STRLEN len, xlen;
 
         /* Free the old space */
-       if (mg)
-           Safefree(mg->mg_ptr);
-
-       s = SvPV_flags_const(sv, len, flags);
-       if ((xf = _mem_collxfrm(s, len, &xlen, cBOOL(SvUTF8(sv))))) {
-           if (! mg) {
-               mg = sv_magicext(sv, 0, PERL_MAGIC_collxfrm, &PL_vtbl_collxfrm,
-                                0, 0);
-               assert(mg);
-           }
-           mg->mg_ptr = xf;
-           mg->mg_len = xlen;
-       }
-       else {
-           if (mg) {
-               mg->mg_ptr = NULL;
-               mg->mg_len = -1;
-           }
-       }
+        if (mg)
+            Safefree(mg->mg_ptr);
+
+        s = SvPV_flags_const(sv, len, flags);
+        if ((xf = mem_collxfrm_(s, len, &xlen, cBOOL(SvUTF8(sv))))) {
+            if (! mg) {
+                mg = sv_magicext(sv, 0, PERL_MAGIC_collxfrm, &PL_vtbl_collxfrm,
+                                 0, 0);
+                assert(mg);
+            }
+            mg->mg_ptr = xf;
+            mg->mg_len = xlen;
+        }
+        else {
+            if (mg) {
+                mg->mg_ptr = NULL;
+                mg->mg_len = -1;
+            }
+        }
     }
 
     if (mg && mg->mg_ptr) {
-       *nxp = mg->mg_len;
-       return mg->mg_ptr + sizeof(PL_collation_ix);
+        *nxp = mg->mg_len;
+        return mg->mg_ptr + sizeof(PL_collation_ix);
     }
     else {
-       *nxp = 0;
-       return NULL;
+        *nxp = 0;
+        return NULL;
     }
 }
 
@@ -8312,7 +8606,7 @@ Perl_sv_collxfrm_flags(pTHX_ SV *const sv, STRLEN *const nxp, const I32 flags)
 static char *
 S_sv_gets_append_to_utf8(pTHX_ SV *const sv, PerlIO *const fp, I32 append)
 {
-    SV * const tsv = newSV(0);
+    SV * const tsv = newSV_type(SVt_NULL);
     ENTER;
     SAVEFREESV(tsv);
     sv_gets(tsv, fp, 0);
@@ -8330,7 +8624,7 @@ S_sv_gets_read_record(pTHX_ SV *const sv, PerlIO *const fp, I32 append)
     const STRLEN recsize = SvUV(SvRV(PL_rs)); /* RsRECORD() guarantees > 0. */
       /* Grab the size of the record we're getting */
     char *buffer = SvGROW(sv, (STRLEN)(recsize + append + 1)) + append;
-    
+
     /* Go yank in */
 #ifdef __VMS
     int fd;
@@ -8344,96 +8638,96 @@ S_sv_gets_read_record(pTHX_ SV *const sv, PerlIO *const fp, I32 append)
      */
     fd = PerlIO_fileno(fp);
     if (fd != -1
-       && PerlLIO_fstat(fd, &st) == 0
-       && (st.st_fab_rfm == FAB$C_VAR
-           || st.st_fab_rfm == FAB$C_VFC
-           || st.st_fab_rfm == FAB$C_FIX)) {
+        && PerlLIO_fstat(fd, &st) == 0
+        && (st.st_fab_rfm == FAB$C_VAR
+            || st.st_fab_rfm == FAB$C_VFC
+            || st.st_fab_rfm == FAB$C_FIX)) {
 
-       bytesread = PerlLIO_read(fd, buffer, recsize);
+        bytesread = PerlLIO_read(fd, buffer, recsize);
     }
     else /* in-memory file from PerlIO::Scalar
           * or not a record-oriented file
           */
 #endif
     {
-       bytesread = PerlIO_read(fp, buffer, recsize);
-
-       /* At this point, the logic in sv_get() means that sv will
-          be treated as utf-8 if the handle is utf8.
-       */
-       if (PerlIO_isutf8(fp) && bytesread > 0) {
-           char *bend = buffer + bytesread;
-           char *bufp = buffer;
-           size_t charcount = 0;
-           bool charstart = TRUE;
-           STRLEN skip = 0;
-
-           while (charcount < recsize) {
-               /* count accumulated characters */
-               while (bufp < bend) {
-                   if (charstart) {
-                       skip = UTF8SKIP(bufp);
-                   }
-                   if (bufp + skip > bend) {
-                       /* partial at the end */
-                       charstart = FALSE;
-                       break;
-                   }
-                   else {
-                       ++charcount;
-                       bufp += skip;
-                       charstart = TRUE;
-                   }
-               }
-
-               if (charcount < recsize) {
-                   STRLEN readsize;
-                   STRLEN bufp_offset = bufp - buffer;
-                   SSize_t morebytesread;
-
-                   /* originally I read enough to fill any incomplete
-                      character and the first byte of the next
-                      character if needed, but if there's many
-                      multi-byte encoded characters we're going to be
-                      making a read call for every character beyond
-                      the original read size.
-
-                      So instead, read the rest of the character if
-                      any, and enough bytes to match at least the
-                      start bytes for each character we're going to
-                      read.
-                   */
-                   if (charstart)
-                       readsize = recsize - charcount;
-                   else 
-                       readsize = skip - (bend - bufp) + recsize - charcount - 1;
-                   buffer = SvGROW(sv, append + bytesread + readsize + 1) + append;
-                   bend = buffer + bytesread;
-                   morebytesread = PerlIO_read(fp, bend, readsize);
-                   if (morebytesread <= 0) {
-                       /* we're done, if we still have incomplete
-                          characters the check code in sv_gets() will
-                          warn about them.
-
-                          I'd originally considered doing
-                          PerlIO_ungetc() on all but the lead
-                          character of the incomplete character, but
-                          read() doesn't do that, so I don't.
-                       */
-                       break;
-                   }
-
-                   /* prepare to scan some more */
-                   bytesread += morebytesread;
-                   bend = buffer + bytesread;
-                   bufp = buffer + bufp_offset;
-               }
-           }
-       }
+        bytesread = PerlIO_read(fp, buffer, recsize);
+
+        /* At this point, the logic in sv_get() means that sv will
+           be treated as utf-8 if the handle is utf8.
+        */
+        if (PerlIO_isutf8(fp) && bytesread > 0) {
+            char *bend = buffer + bytesread;
+            char *bufp = buffer;
+            size_t charcount = 0;
+            bool charstart = TRUE;
+            STRLEN skip = 0;
+
+            while (charcount < recsize) {
+                /* count accumulated characters */
+                while (bufp < bend) {
+                    if (charstart) {
+                        skip = UTF8SKIP(bufp);
+                    }
+                    if (bufp + skip > bend) {
+                        /* partial at the end */
+                        charstart = FALSE;
+                        break;
+                    }
+                    else {
+                        ++charcount;
+                        bufp += skip;
+                        charstart = TRUE;
+                    }
+                }
+
+                if (charcount < recsize) {
+                    STRLEN readsize;
+                    STRLEN bufp_offset = bufp - buffer;
+                    SSize_t morebytesread;
+
+                    /* originally I read enough to fill any incomplete
+                       character and the first byte of the next
+                       character if needed, but if there's many
+                       multi-byte encoded characters we're going to be
+                       making a read call for every character beyond
+                       the original read size.
+
+                       So instead, read the rest of the character if
+                       any, and enough bytes to match at least the
+                       start bytes for each character we're going to
+                       read.
+                    */
+                    if (charstart)
+                        readsize = recsize - charcount;
+                    else
+                        readsize = skip - (bend - bufp) + recsize - charcount - 1;
+                    buffer = SvGROW(sv, append + bytesread + readsize + 1) + append;
+                    bend = buffer + bytesread;
+                    morebytesread = PerlIO_read(fp, bend, readsize);
+                    if (morebytesread <= 0) {
+                        /* we're done, if we still have incomplete
+                           characters the check code in sv_gets() will
+                           warn about them.
+
+                           I'd originally considered doing
+                           PerlIO_ungetc() on all but the lead
+                           character of the incomplete character, but
+                           read() doesn't do that, so I don't.
+                        */
+                        break;
+                    }
+
+                    /* prepare to scan some more */
+                    bytesread += morebytesread;
+                    bend = buffer + bytesread;
+                    bufp = buffer + bufp_offset;
+                }
+            }
+        }
     }
 
     if (bytesread < 0)
-       bytesread = 0;
+        bytesread = 0;
     SvCUR_set(sv, bytesread + append);
     buffer[bytesread] = '\0';
     return (SvCUR(sv) - append) ? SvPVX(sv) : NULL;
@@ -8465,7 +8759,7 @@ Perl_sv_gets(pTHX_ SV *const sv, PerlIO *const fp, I32 append)
     PERL_ARGS_ASSERT_SV_GETS;
 
     if (SvTHINKFIRST(sv))
-       sv_force_normal_flags(sv, append ? 0 : SV_COW_DROP_PV);
+        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
        from <>.
        However, perlbench says it's slower, because the existing swipe code
@@ -8475,75 +8769,75 @@ Perl_sv_gets(pTHX_ SV *const sv, PerlIO *const fp, I32 append)
 
     if (append) {
         /* line is going to be appended to the existing buffer in the sv */
-       if (PerlIO_isutf8(fp)) {
-           if (!SvUTF8(sv)) {
-               sv_utf8_upgrade_nomg(sv);
-               sv_pos_u2b(sv,&append,0);
-           }
-       } else if (SvUTF8(sv)) {
-           return S_sv_gets_append_to_utf8(aTHX_ sv, fp, append);
-       }
+        if (PerlIO_isutf8(fp)) {
+            if (!SvUTF8(sv)) {
+                sv_utf8_upgrade_nomg(sv);
+                sv_pos_u2b(sv,&append,0);
+            }
+        } else if (SvUTF8(sv)) {
+            return S_sv_gets_append_to_utf8(aTHX_ sv, fp, append);
+        }
     }
 
     SvPOK_only(sv);
     if (!append) {
         /* not appending - "clear" the string by setting SvCUR to 0,
-         * the pv is still avaiable. */
+         * the pv is still available. */
         SvCUR_set(sv,0);
     }
     if (PerlIO_isutf8(fp))
-       SvUTF8_on(sv);
+        SvUTF8_on(sv);
 
     if (IN_PERL_COMPILETIME) {
-       /* we always read code in line mode */
-       rsptr = "\n";
-       rslen = 1;
+        /* we always read code in line mode */
+        rsptr = "\n";
+        rslen = 1;
     }
     else if (RsSNARF(PL_rs)) {
-       /* If it is a regular disk file use size from stat() as estimate
-          of amount we are going to read -- may result in mallocing
-          more memory than we really need if the layers below reduce
-          the size we read (e.g. CRLF or a gzip layer).
-        */
-       Stat_t st;
+        /* If it is a regular disk file use size from stat() as estimate
+           of amount we are going to read -- may result in mallocing
+           more memory than we really need if the layers below reduce
+           the size we read (e.g. CRLF or a gzip layer).
+         */
+        Stat_t st;
         int fd = PerlIO_fileno(fp);
-       if (fd >= 0 && (PerlLIO_fstat(fd, &st) == 0) && S_ISREG(st.st_mode))  {
-           const Off_t offset = PerlIO_tell(fp);
-           if (offset != (Off_t) -1 && st.st_size + append > offset) {
+        if (fd >= 0 && (PerlLIO_fstat(fd, &st) == 0) && S_ISREG(st.st_mode))  {
+            const Off_t offset = PerlIO_tell(fp);
+            if (offset != (Off_t) -1 && st.st_size + append > offset) {
 #ifdef PERL_COPY_ON_WRITE
                 /* Add an extra byte for the sake of copy-on-write's
                  * buffer reference count. */
-               (void) SvGROW(sv, (STRLEN)((st.st_size - offset) + append + 2));
+                (void) SvGROW(sv, (STRLEN)((st.st_size - offset) + append + 2));
 #else
-               (void) SvGROW(sv, (STRLEN)((st.st_size - offset) + append + 1));
+                (void) SvGROW(sv, (STRLEN)((st.st_size - offset) + append + 1));
 #endif
-           }
-       }
-       rsptr = NULL;
-       rslen = 0;
+            }
+        }
+        rsptr = NULL;
+        rslen = 0;
     }
     else if (RsRECORD(PL_rs)) {
-       return S_sv_gets_read_record(aTHX_ sv, fp, append);
+        return S_sv_gets_read_record(aTHX_ sv, fp, append);
     }
     else if (RsPARA(PL_rs)) {
-       rsptr = "\n\n";
-       rslen = 2;
-       rspara = 1;
+        rsptr = "\n\n";
+        rslen = 2;
+        rspara = 1;
     }
     else {
-       /* Get $/ i.e. PL_rs into same encoding as stream wants */
-       if (PerlIO_isutf8(fp)) {
-           rsptr = SvPVutf8(PL_rs, rslen);
-       }
-       else {
-           if (SvUTF8(PL_rs)) {
-               if (!sv_utf8_downgrade(PL_rs, TRUE)) {
-                   Perl_croak(aTHX_ "Wide character in $/");
-               }
-           }
+        /* Get $/ i.e. PL_rs into same encoding as stream wants */
+        if (PerlIO_isutf8(fp)) {
+            rsptr = SvPVutf8(PL_rs, rslen);
+        }
+        else {
+            if (SvUTF8(PL_rs)) {
+                if (!sv_utf8_downgrade(PL_rs, TRUE)) {
+                    Perl_croak(aTHX_ "Wide character in $/");
+                }
+            }
             /* extract the raw pointer to the record separator */
-           rsptr = SvPV_const(PL_rs, rslen);
-       }
+            rsptr = SvPV_const(PL_rs, rslen);
+        }
     }
 
     /* rslast is the last character in the record separator
@@ -8660,25 +8954,25 @@ Perl_sv_gets(pTHX_ SV *const sv, PerlIO *const fp, I32 append)
 
     /* make sure we have the room */
     if ((I32)(SvLEN(sv) - append) <= cnt + 1) {
-       /* Not room for all of it
-          if we are looking for a separator and room for some
-        */
-       if (rslen && cnt > 80 && (I32)SvLEN(sv) > append) {
-           /* just process what we have room for */
-           shortbuffered = cnt - SvLEN(sv) + append + 1;
-           cnt -= shortbuffered;
-       }
-       else {
+        /* Not room for all of it
+           if we are looking for a separator and room for some
+         */
+        if (rslen && cnt > 80 && (I32)SvLEN(sv) > append) {
+            /* just process what we have room for */
+            shortbuffered = cnt - SvLEN(sv) + append + 1;
+            cnt -= shortbuffered;
+        }
+        else {
             /* ensure that the target sv has enough room to hold
              * the rest of the read-ahead buffer */
-           shortbuffered = 0;
-           /* remember that cnt can be negative */
-           SvGROW(sv, (STRLEN)(append + (cnt <= 0 ? 2 : (cnt + 1))));
-       }
+            shortbuffered = 0;
+            /* remember that cnt can be negative */
+            SvGROW(sv, (STRLEN)(append + (cnt <= 0 ? 2 : (cnt + 1))));
+        }
     }
     else {
         /* we have enough room to hold the full buffer, lets scream */
-       shortbuffered = 0;
+        shortbuffered = 0;
     }
 
     /* extract the pointer to sv's string buffer, offset by append as necessary */
@@ -8688,19 +8982,19 @@ Perl_sv_gets(pTHX_ SV *const sv, PerlIO *const fp, I32 append)
 
     /* some trace debug output */
     DEBUG_P(PerlIO_printf(Perl_debug_log,
-       "Screamer: entering, ptr=%" UVuf ", cnt=%ld\n",PTR2UV(ptr),(long)cnt));
+        "Screamer: entering, ptr=%" UVuf ", cnt=%ld\n",PTR2UV(ptr),(long)cnt));
     DEBUG_P(PerlIO_printf(Perl_debug_log,
-       "Screamer: entering: PerlIO * thinks ptr=%" UVuf ", cnt=%" IVdf ", base=%"
-        UVuf "\n",
-              PTR2UV(PerlIO_get_ptr(fp)), (IV)PerlIO_get_cnt(fp),
-              PTR2UV(PerlIO_has_base(fp) ? PerlIO_get_base(fp) : 0)));
+        "Screamer: entering: PerlIO * thinks ptr=%" UVuf ", cnt=%" IVdf ", base=%"
+         UVuf "\n",
+               PTR2UV(PerlIO_get_ptr(fp)), (IV)PerlIO_get_cnt(fp),
+               PTR2UV(PerlIO_has_base(fp) ? PerlIO_get_base(fp) : 0)));
 
     for (;;) {
       screamer:
         /* if there is stuff left in the read-ahead buffer */
-       if (cnt > 0) {
+        if (cnt > 0) {
             /* if there is a separator */
-           if (rslen) {
+            if (rslen) {
                 /* find next rslast */
                 STDCHAR *p;
 
@@ -8722,43 +9016,43 @@ Perl_sv_gets(pTHX_ SV *const sv, PerlIO *const fp, I32 append)
                 ptr += cnt;
                 bp  += cnt;
                 cnt = 0;
-           }
-           else {
+            }
+            else {
                 /* no separator, slurp the full buffer */
-               Copy(ptr, bp, cnt, char);            /* this     |  eat */
-               bp += cnt;                           /* screams  |  dust */
-               ptr += cnt;                          /* louder   |  sed :-) */
-               cnt = 0;
-               assert (!shortbuffered);
-               goto cannot_be_shortbuffered;
-           }
-       }
-       
-       if (shortbuffered) {            /* oh well, must extend */
-            /* we didnt have enough room to fit the line into the target buffer
+                Copy(ptr, bp, cnt, char);           /* this     |  eat */
+                bp += cnt;                          /* screams  |  dust */
+                ptr += cnt;                         /* louder   |  sed :-) */
+                cnt = 0;
+                assert (!shortbuffered);
+                goto cannot_be_shortbuffered;
+            }
+        }
+
+        if (shortbuffered) {           /* oh well, must extend */
+            /* we didn't have enough room to fit the line into the target buffer
              * so we must extend the target buffer and keep going */
-           cnt = shortbuffered;
-           shortbuffered = 0;
-           bpx = bp - (STDCHAR*)SvPVX_const(sv); /* box up before relocation */
-           SvCUR_set(sv, bpx);
+            cnt = shortbuffered;
+            shortbuffered = 0;
+            bpx = bp - (STDCHAR*)SvPVX_const(sv); /* box up before relocation */
+            SvCUR_set(sv, bpx);
             /* extned the target sv's buffer so it can hold the full read-ahead buffer */
-           SvGROW(sv, SvLEN(sv) + append + cnt + 2);
-           bp = (STDCHAR*)SvPVX_const(sv) + bpx; /* unbox after relocation */
-           continue;
-       }
+            SvGROW(sv, SvLEN(sv) + append + cnt + 2);
+            bp = (STDCHAR*)SvPVX_const(sv) + bpx; /* unbox after relocation */
+            continue;
+        }
 
     cannot_be_shortbuffered:
         /* we need to refill the read-ahead buffer if possible */
 
-       DEBUG_P(PerlIO_printf(Perl_debug_log,
-                            "Screamer: going to getc, ptr=%" UVuf ", cnt=%" IVdf "\n",
-                             PTR2UV(ptr),(IV)cnt));
-       PerlIO_set_ptrcnt(fp, (STDCHAR*)ptr, cnt); /* deregisterize cnt and ptr */
+        DEBUG_P(PerlIO_printf(Perl_debug_log,
+                             "Screamer: going to getc, ptr=%" UVuf ", cnt=%" IVdf "\n",
+                              PTR2UV(ptr),(IV)cnt));
+        PerlIO_set_ptrcnt(fp, (STDCHAR*)ptr, cnt); /* deregisterize cnt and ptr */
 
-       DEBUG_Pv(PerlIO_printf(Perl_debug_log,
-          "Screamer: pre: FILE * thinks ptr=%" UVuf ", cnt=%" IVdf ", base=%" UVuf "\n",
-           PTR2UV(PerlIO_get_ptr(fp)), (IV)PerlIO_get_cnt(fp),
-           PTR2UV(PerlIO_has_base (fp) ? PerlIO_get_base(fp) : 0)));
+        DEBUG_Pv(PerlIO_printf(Perl_debug_log,
+           "Screamer: pre: FILE * thinks ptr=%" UVuf ", cnt=%" IVdf ", base=%" UVuf "\n",
+            PTR2UV(PerlIO_get_ptr(fp)), (IV)PerlIO_get_cnt(fp),
+            PTR2UV(PerlIO_has_base (fp) ? PerlIO_get_base(fp) : 0)));
 
         /*
             call PerlIO_getc() to let it prefill the lookahead buffer
@@ -8771,132 +9065,123 @@ Perl_sv_gets(pTHX_ SV *const sv, PerlIO *const fp, I32 append)
         */
         bpx = bp - (STDCHAR*)SvPVX_const(sv);
         /* signals might be called here, possibly modifying sv */
-       i   = PerlIO_getc(fp);          /* get more characters */
+        i   = PerlIO_getc(fp);         /* get more characters */
         bp = (STDCHAR*)SvPVX_const(sv) + bpx;
 
-       DEBUG_Pv(PerlIO_printf(Perl_debug_log,
-          "Screamer: post: FILE * thinks ptr=%" UVuf ", cnt=%" IVdf ", base=%" UVuf "\n",
-           PTR2UV(PerlIO_get_ptr(fp)), (IV)PerlIO_get_cnt(fp),
-           PTR2UV(PerlIO_has_base (fp) ? PerlIO_get_base(fp) : 0)));
+        DEBUG_Pv(PerlIO_printf(Perl_debug_log,
+           "Screamer: post: FILE * thinks ptr=%" UVuf ", cnt=%" IVdf ", base=%" UVuf "\n",
+            PTR2UV(PerlIO_get_ptr(fp)), (IV)PerlIO_get_cnt(fp),
+            PTR2UV(PerlIO_has_base (fp) ? PerlIO_get_base(fp) : 0)));
 
         /* find out how much is left in the read-ahead buffer, and rextract its pointer */
-       cnt = PerlIO_get_cnt(fp);
-       ptr = (STDCHAR*)PerlIO_get_ptr(fp);     /* reregisterize cnt and ptr */
-       DEBUG_P(PerlIO_printf(Perl_debug_log,
-           "Screamer: after getc, ptr=%" UVuf ", cnt=%" IVdf "\n",
-           PTR2UV(ptr),(IV)cnt));
+        cnt = PerlIO_get_cnt(fp);
+        ptr = (STDCHAR*)PerlIO_get_ptr(fp);    /* reregisterize cnt and ptr */
+        DEBUG_P(PerlIO_printf(Perl_debug_log,
+            "Screamer: after getc, ptr=%" UVuf ", cnt=%" IVdf "\n",
+            PTR2UV(ptr),(IV)cnt));
 
-       if (i == EOF)                   /* all done for ever? */
-           goto thats_really_all_folks;
+        if (i == EOF)                  /* all done for ever? */
+            goto thats_really_all_folks;
 
         /* make sure we have enough space in the target sv */
-       bpx = bp - (STDCHAR*)SvPVX_const(sv);   /* box up before relocation */
-       SvCUR_set(sv, bpx);
-       SvGROW(sv, bpx + cnt + 2);
-       bp = (STDCHAR*)SvPVX_const(sv) + bpx;   /* unbox after relocation */
+        bpx = bp - (STDCHAR*)SvPVX_const(sv);  /* box up before relocation */
+        SvCUR_set(sv, bpx);
+        SvGROW(sv, bpx + cnt + 2);
+        bp = (STDCHAR*)SvPVX_const(sv) + bpx;  /* unbox after relocation */
 
         /* copy of the char we got from getc() */
-       *bp++ = (STDCHAR)i;             /* store character from PerlIO_getc */
+        *bp++ = (STDCHAR)i;            /* store character from PerlIO_getc */
 
         /* make sure we deal with the i being the last character of a separator */
-       if (rslen && (STDCHAR)i == rslast)  /* all done for now? */
-           goto thats_all_folks;
+        if (rslen && (STDCHAR)i == rslast)  /* all done for now? */
+            goto thats_all_folks;
     }
 
   thats_all_folks:
     /* check if we have actually found the separator - only really applies
      * when rslen > 1 */
     if ((rslen > 1 && (STRLEN)(bp - (STDCHAR*)SvPVX_const(sv)) < rslen) ||
-         memNE((char*)bp - rslen, rsptr, rslen))
-       goto screamer;                          /* go back to the fray */
+          memNE((char*)bp - rslen, rsptr, rslen))
+        goto screamer;                         /* go back to the fray */
   thats_really_all_folks:
     if (shortbuffered)
-       cnt += shortbuffered;
-       DEBUG_P(PerlIO_printf(Perl_debug_log,
-            "Screamer: quitting, ptr=%" UVuf ", cnt=%" IVdf "\n",PTR2UV(ptr),(IV)cnt));
+        cnt += shortbuffered;
+    DEBUG_P(PerlIO_printf(Perl_debug_log,
+         "Screamer: quitting, ptr=%" UVuf ", cnt=%" IVdf "\n",PTR2UV(ptr),(IV)cnt));
     PerlIO_set_ptrcnt(fp, (STDCHAR*)ptr, cnt); /* put these back or we're in trouble */
     DEBUG_P(PerlIO_printf(Perl_debug_log,
-       "Screamer: end: FILE * thinks ptr=%" UVuf ", cnt=%" IVdf ", base=%" UVuf
-       "\n",
-       PTR2UV(PerlIO_get_ptr(fp)), (IV)PerlIO_get_cnt(fp),
-       PTR2UV(PerlIO_has_base (fp) ? PerlIO_get_base(fp) : 0)));
+        "Screamer: end: FILE * thinks ptr=%" UVuf ", cnt=%" IVdf ", base=%" UVuf
+        "\n",
+        PTR2UV(PerlIO_get_ptr(fp)), (IV)PerlIO_get_cnt(fp),
+        PTR2UV(PerlIO_has_base (fp) ? PerlIO_get_base(fp) : 0)));
     *bp = '\0';
     SvCUR_set(sv, bp - (STDCHAR*)SvPVX_const(sv));     /* set length */
     DEBUG_P(PerlIO_printf(Perl_debug_log,
-       "Screamer: done, len=%ld, string=|%.*s|\n",
-       (long)SvCUR(sv),(int)SvCUR(sv),SvPVX_const(sv)));
+        "Screamer: done, len=%ld, string=|%.*s|\n",
+        (long)SvCUR(sv),(int)SvCUR(sv),SvPVX_const(sv)));
     }
    else
     {
        /*The big, slow, and stupid way. */
-#ifdef USE_HEAP_INSTEAD_OF_STACK       /* Even slower way. */
-       STDCHAR *buf = NULL;
-       Newx(buf, 8192, STDCHAR);
-       assert(buf);
-#else
-       STDCHAR buf[8192];
-#endif
+        STDCHAR buf[8192];
 
       screamer2:
-       if (rslen) {
+        if (rslen) {
             const STDCHAR * const bpe = buf + sizeof(buf);
-           bp = buf;
-           while ((i = PerlIO_getc(fp)) != EOF && (*bp++ = (STDCHAR)i) != rslast && bp < bpe)
-               ; /* keep reading */
-           cnt = bp - buf;
-       }
-       else {
-           cnt = PerlIO_read(fp,(char*)buf, sizeof(buf));
-           /* Accommodate broken VAXC compiler, which applies U8 cast to
-            * both args of ?: operator, causing EOF to change into 255
-            */
-           if (cnt > 0)
-                i = (U8)buf[cnt - 1];
-           else
-                i = EOF;
-       }
-
-       if (cnt < 0)
-           cnt = 0;  /* we do need to re-set the sv even when cnt <= 0 */
-       if (append)
+            bp = buf;
+            while ((i = PerlIO_getc(fp)) != EOF && (*bp++ = (STDCHAR)i) != rslast && bp < bpe)
+                ; /* keep reading */
+            cnt = bp - buf;
+        }
+        else {
+            cnt = PerlIO_read(fp,(char*)buf, sizeof(buf));
+            /* Accommodate broken VAXC compiler, which applies U8 cast to
+             * both args of ?: operator, causing EOF to change into 255
+             */
+            if (cnt > 0)
+                 i = (U8)buf[cnt - 1];
+            else
+                 i = EOF;
+        }
+
+        if (cnt < 0)
+            cnt = 0;  /* we do need to re-set the sv even when cnt <= 0 */
+        if (append)
             sv_catpvn_nomg(sv, (char *) buf, cnt);
-       else
+        else
             sv_setpvn(sv, (char *) buf, cnt);   /* "nomg" is implied */
 
-       if (i != EOF &&                 /* joy */
-           (!rslen ||
-            SvCUR(sv) < rslen ||
-            memNE(SvPVX_const(sv) + SvCUR(sv) - rslen, rsptr, rslen)))
-       {
-           append = -1;
-           /*
-            * If we're reading from a TTY and we get a short read,
-            * indicating that the user hit his EOF character, we need
-            * to notice it now, because if we try to read from the TTY
-            * again, the EOF condition will disappear.
-            *
-            * The comparison of cnt to sizeof(buf) is an optimization
-            * that prevents unnecessary calls to feof().
-            *
-            * - jik 9/25/96
-            */
-           if (!(cnt < (I32)sizeof(buf) && PerlIO_eof(fp)))
-               goto screamer2;
-       }
-
-#ifdef USE_HEAP_INSTEAD_OF_STACK
-       Safefree(buf);
-#endif
+        if (i != EOF &&                        /* joy */
+            (!rslen ||
+             SvCUR(sv) < rslen ||
+             memNE(SvPVX_const(sv) + SvCUR(sv) - rslen, rsptr, rslen)))
+        {
+            append = -1;
+            /*
+             * If we're reading from a TTY and we get a short read,
+             * indicating that the user hit his EOF character, we need
+             * to notice it now, because if we try to read from the TTY
+             * again, the EOF condition will disappear.
+             *
+             * The comparison of cnt to sizeof(buf) is an optimization
+             * that prevents unnecessary calls to feof().
+             *
+             * - jik 9/25/96
+             */
+            if (!(cnt < (I32)sizeof(buf) && PerlIO_eof(fp)))
+                goto screamer2;
+        }
+
     }
 
     if (rspara) {              /* have to do this both before and after */
         while (i != EOF) {     /* to make sure file boundaries work right */
-           i = PerlIO_getc(fp);
-           if (i != '\n') {
-               PerlIO_ungetc(fp,i);
-               break;
-           }
-       }
+            i = PerlIO_getc(fp);
+            if (i != '\n') {
+                PerlIO_ungetc(fp,i);
+                break;
+            }
+        }
     }
 
     return (SvCUR(sv) - append) ? SvPVX(sv) : NULL;
@@ -8904,9 +9189,13 @@ Perl_sv_gets(pTHX_ SV *const sv, PerlIO *const fp, I32 append)
 
 /*
 =for apidoc sv_inc
+=for apidoc_item sv_inc_nomg
+
+These auto-increment the value in the SV, doing string to numeric conversion
+if necessary.  They both handle operator overloading.
 
-Auto-increment of the value in the SV, doing string to numeric conversion
-if necessary.  Handles 'get' magic and operator overloading.
+They differ only in that C<sv_inc> performs 'get' magic; C<sv_inc_nomg> skips
+any magic.
 
 =cut
 */
@@ -8915,20 +9204,11 @@ void
 Perl_sv_inc(pTHX_ SV *const sv)
 {
     if (!sv)
-       return;
+        return;
     SvGETMAGIC(sv);
     sv_inc_nomg(sv);
 }
 
-/*
-=for apidoc sv_inc_nomg
-
-Auto-increment of the value in the SV, doing string to numeric conversion
-if necessary.  Handles operator overloading.  Skips handling 'get' magic.
-
-=cut
-*/
-
 void
 Perl_sv_inc_nomg(pTHX_ SV *const sv)
 {
@@ -8936,62 +9216,70 @@ Perl_sv_inc_nomg(pTHX_ SV *const sv)
     int flags;
 
     if (!sv)
-       return;
+        return;
     if (SvTHINKFIRST(sv)) {
-       if (SvREADONLY(sv)) {
-               Perl_croak_no_modify();
-       }
-       if (SvROK(sv)) {
-           IV i;
-           if (SvAMAGIC(sv) && AMG_CALLunary(sv, inc_amg))
-               return;
-           i = PTR2IV(SvRV(sv));
-           sv_unref(sv);
-           sv_setiv(sv, i);
-       }
-       else sv_force_normal_flags(sv, 0);
+        if (SvREADONLY(sv)) {
+                Perl_croak_no_modify();
+        }
+        if (SvROK(sv)) {
+            IV i;
+            if (SvAMAGIC(sv) && AMG_CALLunary(sv, inc_amg))
+                return;
+            i = PTR2IV(SvRV(sv));
+            sv_unref(sv);
+            sv_setiv(sv, i);
+        }
+        else sv_force_normal_flags(sv, 0);
     }
     flags = SvFLAGS(sv);
     if ((flags & (SVp_NOK|SVp_IOK)) == SVp_NOK) {
-       /* It's (privately or publicly) a float, but not tested as an
-          integer, so test it to see. */
-       (void) SvIV(sv);
-       flags = SvFLAGS(sv);
+        /* It's (privately or publicly) a float, but not tested as an
+           integer, so test it to see. */
+        (void) SvIV(sv);
+        flags = SvFLAGS(sv);
     }
     if ((flags & SVf_IOK) || ((flags & (SVp_IOK | SVp_NOK)) == SVp_IOK)) {
-       /* It's publicly an integer, or privately an integer-not-float */
+        /* It's publicly an integer, or privately an integer-not-float */
 #ifdef PERL_PRESERVE_IVUV
       oops_its_int:
 #endif
-       if (SvIsUV(sv)) {
-           if (SvUVX(sv) == UV_MAX)
-               sv_setnv(sv, UV_MAX_P1);
-           else
-               (void)SvIOK_only_UV(sv);
-               SvUV_set(sv, SvUVX(sv) + 1);
-       } else {
-           if (SvIVX(sv) == IV_MAX)
-               sv_setuv(sv, (UV)IV_MAX + 1);
-           else {
-               (void)SvIOK_only(sv);
-               SvIV_set(sv, SvIVX(sv) + 1);
-           }   
-       }
-       return;
+        if (SvIsUV(sv)) {
+            if (SvUVX(sv) == UV_MAX)
+                sv_setnv(sv, UV_MAX_P1);
+            else {
+                (void)SvIOK_only_UV(sv);
+                SvUV_set(sv, SvUVX(sv) + 1);
+            }
+        } else {
+            if (SvIVX(sv) == IV_MAX)
+                sv_setuv(sv, (UV)IV_MAX + 1);
+            else {
+                (void)SvIOK_only(sv);
+                SvIV_set(sv, SvIVX(sv) + 1);
+            }
+        }
+        return;
     }
     if (flags & SVp_NOK) {
-       const NV was = SvNVX(sv);
-       if (LIKELY(!Perl_isinfnan(was)) &&
-            NV_OVERFLOWS_INTEGERS_AT != 0.0 &&
-           was >= NV_OVERFLOWS_INTEGERS_AT) {
-           /* diag_listed_as: Lost precision when %s %f by 1 */
-           Perl_ck_warner(aTHX_ packWARN(WARN_IMPRECISION),
-                          "Lost precision when incrementing %" NVff " by 1",
-                          was);
-       }
-       (void)SvNOK_only(sv);
+        const NV was = SvNVX(sv);
+        if (NV_OVERFLOWS_INTEGERS_AT != 0.0 &&
+            /* If NVX was NaN, the following comparisons return always false */
+            UNLIKELY(was >= NV_OVERFLOWS_INTEGERS_AT ||
+                     was < -NV_OVERFLOWS_INTEGERS_AT) &&
+#if defined(NAN_COMPARE_BROKEN)
+            LIKELY(!Perl_isinfnan(was))
+#else
+            LIKELY(!Perl_isinf(was))
+#endif
+            ) {
+            /* diag_listed_as: Lost precision when %s %f by 1 */
+            Perl_ck_warner(aTHX_ packWARN(WARN_IMPRECISION),
+                           "Lost precision when incrementing %" NVff " by 1",
+                           was);
+        }
+        (void)SvNOK_only(sv);
         SvNV_set(sv, was + 1.0);
-       return;
+        return;
     }
 
     /* treat AV/HV/CV/FM/IO and non-fake GVs as immutable */
@@ -8999,95 +9287,100 @@ Perl_sv_inc_nomg(pTHX_ SV *const sv)
         Perl_croak_no_modify();
 
     if (!(flags & SVp_POK) || !*SvPVX_const(sv)) {
-       if ((flags & SVTYPEMASK) < SVt_PVIV)
-           sv_upgrade(sv, ((flags & SVTYPEMASK) > SVt_IV ? SVt_PVIV : SVt_IV));
-       (void)SvIOK_only(sv);
-       SvIV_set(sv, 1);
-       return;
+        if ((flags & SVTYPEMASK) < SVt_PVIV)
+            sv_upgrade(sv, ((flags & SVTYPEMASK) > SVt_IV ? SVt_PVIV : SVt_IV));
+        (void)SvIOK_only(sv);
+        SvIV_set(sv, 1);
+        return;
     }
     d = SvPVX(sv);
     while (isALPHA(*d)) d++;
     while (isDIGIT(*d)) d++;
     if (d < SvEND(sv)) {
-       const int numtype = grok_number_flags(SvPVX_const(sv), SvCUR(sv), NULL, PERL_SCAN_TRAILING);
+        const int numtype = grok_number_flags(SvPVX_const(sv), SvCUR(sv), NULL, PERL_SCAN_TRAILING);
 #ifdef PERL_PRESERVE_IVUV
-       /* Got to punt this as an integer if needs be, but we don't issue
-          warnings. Probably ought to make the sv_iv_please() that does
-          the conversion if possible, and silently.  */
-       if (numtype && !(numtype & IS_NUMBER_INFINITY)) {
-           /* Need to try really hard to see if it's an integer.
-              9.22337203685478e+18 is an integer.
-              but "9.22337203685478e+18" + 0 is UV=9223372036854779904
-              so $a="9.22337203685478e+18"; $a+0; $a++
-              needs to be the same as $a="9.22337203685478e+18"; $a++
-              or we go insane. */
-       
-           (void) sv_2iv(sv);
-           if (SvIOK(sv))
-               goto oops_its_int;
-
-           /* sv_2iv *should* have made this an NV */
-           if (flags & SVp_NOK) {
-               (void)SvNOK_only(sv);
+        /* Got to punt this as an integer if needs be, but we don't issue
+           warnings. Probably ought to make the sv_iv_please() that does
+           the conversion if possible, and silently.  */
+        if (numtype && !(numtype & IS_NUMBER_INFINITY)) {
+            /* Need to try really hard to see if it's an integer.
+               9.22337203685478e+18 is an integer.
+               but "9.22337203685478e+18" + 0 is UV=9223372036854779904
+               so $a="9.22337203685478e+18"; $a+0; $a++
+               needs to be the same as $a="9.22337203685478e+18"; $a++
+               or we go insane. */
+
+            (void) sv_2iv(sv);
+            if (SvIOK(sv))
+                goto oops_its_int;
+
+            /* sv_2iv *should* have made this an NV */
+            if (flags & SVp_NOK) {
+                (void)SvNOK_only(sv);
                 SvNV_set(sv, SvNVX(sv) + 1.0);
-               return;
-           }
-           /* I don't think we can get here. Maybe I should assert this
-              And if we do get here I suspect that sv_setnv will croak. NWC
-              Fall through. */
-           DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_inc punt failed to convert '%s' to IOK or NOKp, UV=0x%" UVxf " NV=%" NVgf "\n",
-                                 SvPVX_const(sv), SvIVX(sv), SvNVX(sv)));
-       }
+                return;
+            }
+            /* I don't think we can get here. Maybe I should assert this
+               And if we do get here I suspect that sv_setnv will croak. NWC
+               Fall through. */
+            DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_inc punt failed to convert '%s' to IOK or NOKp, UV=0x%" UVxf " NV=%" NVgf "\n",
+                                  SvPVX_const(sv), SvIVX(sv), SvNVX(sv)));
+        }
 #endif /* PERL_PRESERVE_IVUV */
         if (!numtype && ckWARN(WARN_NUMERIC))
             not_incrementable(sv);
-       sv_setnv(sv,Atof(SvPVX_const(sv)) + 1.0);
-       return;
+        sv_setnv(sv,Atof(SvPVX_const(sv)) + 1.0);
+        return;
     }
     d--;
     while (d >= SvPVX_const(sv)) {
-       if (isDIGIT(*d)) {
-           if (++*d <= '9')
-               return;
-           *(d--) = '0';
-       }
-       else {
+        if (isDIGIT(*d)) {
+            if (++*d <= '9')
+                return;
+            *(d--) = '0';
+        }
+        else {
 #ifdef EBCDIC
-           /* MKS: The original code here died if letters weren't consecutive.
-            * at least it didn't have to worry about non-C locales.  The
-            * new code assumes that ('z'-'a')==('Z'-'A'), letters are
-            * arranged in order (although not consecutively) and that only
-            * [A-Za-z] are accepted by isALPHA in the C locale.
-            */
-           if (isALPHA_FOLD_NE(*d, 'z')) {
-               do { ++*d; } while (!isALPHA(*d));
-               return;
-           }
-           *(d--) -= 'z' - 'a';
+            /* MKS: The original code here died if letters weren't consecutive.
+             * at least it didn't have to worry about non-C locales.  The
+             * new code assumes that ('z'-'a')==('Z'-'A'), letters are
+             * arranged in order (although not consecutively) and that only
+             * [A-Za-z] are accepted by isALPHA in the C locale.
+             */
+            if (isALPHA_FOLD_NE(*d, 'z')) {
+                do { ++*d; } while (!isALPHA(*d));
+                return;
+            }
+            *(d--) -= 'z' - 'a';
 #else
-           ++*d;
-           if (isALPHA(*d))
-               return;
-           *(d--) -= 'z' - 'a' + 1;
+            ++*d;
+            if (isALPHA(*d))
+                return;
+            *(d--) -= 'z' - 'a' + 1;
 #endif
-       }
+        }
     }
     /* oh,oh, the number grew */
     SvGROW(sv, SvCUR(sv) + 2);
     SvCUR_set(sv, SvCUR(sv) + 1);
     for (d = SvPVX(sv) + SvCUR(sv); d > SvPVX_const(sv); d--)
-       *d = d[-1];
+        *d = d[-1];
     if (isDIGIT(d[1]))
-       *d = '1';
+        *d = '1';
     else
-       *d = d[1];
+        *d = d[1];
 }
 
 /*
 =for apidoc sv_dec
+=for apidoc_item sv_dec_nomg
+
+These auto-decrement the value in the SV, doing string to numeric conversion
+if necessary.  They both handle operator overloading.
+
+They differ only in that:
 
-Auto-decrement of the value in the SV, doing string to numeric conversion
-if necessary.  Handles 'get' magic and operator overloading.
+C<sv_dec> handles 'get' magic; C<sv_dec_nomg> skips 'get' magic.
 
 =cut
 */
@@ -9096,86 +9389,84 @@ void
 Perl_sv_dec(pTHX_ SV *const sv)
 {
     if (!sv)
-       return;
+        return;
     SvGETMAGIC(sv);
     sv_dec_nomg(sv);
 }
 
-/*
-=for apidoc sv_dec_nomg
-
-Auto-decrement of the value in the SV, doing string to numeric conversion
-if necessary.  Handles operator overloading.  Skips handling 'get' magic.
-
-=cut
-*/
-
 void
 Perl_sv_dec_nomg(pTHX_ SV *const sv)
 {
     int flags;
 
     if (!sv)
-       return;
+        return;
     if (SvTHINKFIRST(sv)) {
-       if (SvREADONLY(sv)) {
-               Perl_croak_no_modify();
-       }
-       if (SvROK(sv)) {
-           IV i;
-           if (SvAMAGIC(sv) && AMG_CALLunary(sv, dec_amg))
-               return;
-           i = PTR2IV(SvRV(sv));
-           sv_unref(sv);
-           sv_setiv(sv, i);
-       }
-       else sv_force_normal_flags(sv, 0);
+        if (SvREADONLY(sv)) {
+                Perl_croak_no_modify();
+        }
+        if (SvROK(sv)) {
+            IV i;
+            if (SvAMAGIC(sv) && AMG_CALLunary(sv, dec_amg))
+                return;
+            i = PTR2IV(SvRV(sv));
+            sv_unref(sv);
+            sv_setiv(sv, i);
+        }
+        else sv_force_normal_flags(sv, 0);
     }
     /* Unlike sv_inc we don't have to worry about string-never-numbers
        and keeping them magic. But we mustn't warn on punting */
     flags = SvFLAGS(sv);
     if ((flags & SVf_IOK) || ((flags & (SVp_IOK | SVp_NOK)) == SVp_IOK)) {
-       /* It's publicly an integer, or privately an integer-not-float */
+        /* It's publicly an integer, or privately an integer-not-float */
 #ifdef PERL_PRESERVE_IVUV
       oops_its_int:
 #endif
-       if (SvIsUV(sv)) {
-           if (SvUVX(sv) == 0) {
-               (void)SvIOK_only(sv);
-               SvIV_set(sv, -1);
-           }
-           else {
-               (void)SvIOK_only_UV(sv);
-               SvUV_set(sv, SvUVX(sv) - 1);
-           }   
-       } else {
-           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);
-           }   
-       }
-       return;
+        if (SvIsUV(sv)) {
+            if (SvUVX(sv) == 0) {
+                (void)SvIOK_only(sv);
+                SvIV_set(sv, -1);
+            }
+            else {
+                (void)SvIOK_only_UV(sv);
+                SvUV_set(sv, SvUVX(sv) - 1);
+            }
+        } else {
+            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);
+            }
+        }
+        return;
     }
     if (flags & SVp_NOK) {
     oops_its_num:
-       {
-           const NV was = SvNVX(sv);
-           if (LIKELY(!Perl_isinfnan(was)) &&
-                NV_OVERFLOWS_INTEGERS_AT != 0.0 &&
-               was <= -NV_OVERFLOWS_INTEGERS_AT) {
-               /* diag_listed_as: Lost precision when %s %f by 1 */
-               Perl_ck_warner(aTHX_ packWARN(WARN_IMPRECISION),
-                              "Lost precision when decrementing %" NVff " by 1",
-                              was);
-           }
-           (void)SvNOK_only(sv);
-           SvNV_set(sv, was - 1.0);
-           return;
-       }
+        {
+            const NV was = SvNVX(sv);
+            if (NV_OVERFLOWS_INTEGERS_AT != 0.0 &&
+                /* If NVX was NaN, these comparisons return always false */
+                UNLIKELY(was <= -NV_OVERFLOWS_INTEGERS_AT ||
+                         was > NV_OVERFLOWS_INTEGERS_AT) &&
+#if defined(NAN_COMPARE_BROKEN)
+                LIKELY(!Perl_isinfnan(was))
+#else
+                LIKELY(!Perl_isinf(was))
+#endif
+                ) {
+                /* diag_listed_as: Lost precision when %s %f by 1 */
+                Perl_ck_warner(aTHX_ packWARN(WARN_IMPRECISION),
+                               "Lost precision when decrementing %" NVff " by 1",
+                               was);
+            }
+            (void)SvNOK_only(sv);
+            SvNV_set(sv, was - 1.0);
+            return;
+        }
     }
 
     /* treat AV/HV/CV/FM/IO and non-fake GVs as immutable */
@@ -9183,39 +9474,39 @@ Perl_sv_dec_nomg(pTHX_ SV *const sv)
         Perl_croak_no_modify();
 
     if (!(flags & SVp_POK)) {
-       if ((flags & SVTYPEMASK) < SVt_PVIV)
-           sv_upgrade(sv, ((flags & SVTYPEMASK) > SVt_IV) ? SVt_PVIV : SVt_IV);
-       SvIV_set(sv, -1);
-       (void)SvIOK_only(sv);
-       return;
+        if ((flags & SVTYPEMASK) < SVt_PVIV)
+            sv_upgrade(sv, ((flags & SVTYPEMASK) > SVt_IV) ? SVt_PVIV : SVt_IV);
+        SvIV_set(sv, -1);
+        (void)SvIOK_only(sv);
+        return;
     }
 #ifdef PERL_PRESERVE_IVUV
     {
-       const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), NULL);
-       if (numtype && !(numtype & IS_NUMBER_INFINITY)) {
-           /* Need to try really hard to see if it's an integer.
-              9.22337203685478e+18 is an integer.
-              but "9.22337203685478e+18" + 0 is UV=9223372036854779904
-              so $a="9.22337203685478e+18"; $a+0; $a--
-              needs to be the same as $a="9.22337203685478e+18"; $a--
-              or we go insane. */
-       
-           (void) sv_2iv(sv);
-           if (SvIOK(sv))
-               goto oops_its_int;
-
-           /* sv_2iv *should* have made this an NV */
-           if (flags & SVp_NOK) {
-               (void)SvNOK_only(sv);
+        const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), NULL);
+        if (numtype && !(numtype & IS_NUMBER_INFINITY)) {
+            /* Need to try really hard to see if it's an integer.
+               9.22337203685478e+18 is an integer.
+               but "9.22337203685478e+18" + 0 is UV=9223372036854779904
+               so $a="9.22337203685478e+18"; $a+0; $a--
+               needs to be the same as $a="9.22337203685478e+18"; $a--
+               or we go insane. */
+
+            (void) sv_2iv(sv);
+            if (SvIOK(sv))
+                goto oops_its_int;
+
+            /* sv_2iv *should* have made this an NV */
+            if (flags & SVp_NOK) {
+                (void)SvNOK_only(sv);
                 SvNV_set(sv, SvNVX(sv) - 1.0);
-               return;
-           }
-           /* I don't think we can get here. Maybe I should assert this
-              And if we do get here I suspect that sv_setnv will croak. NWC
-              Fall through. */
-           DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_dec punt failed to convert '%s' to IOK or NOKp, UV=0x%" UVxf " NV=%" NVgf "\n",
-                                 SvPVX_const(sv), SvIVX(sv), SvNVX(sv)));
-       }
+                return;
+            }
+            /* I don't think we can get here. Maybe I should assert this
+               And if we do get here I suspect that sv_setnv will croak. NWC
+               Fall through. */
+            DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_dec punt failed to convert '%s' to IOK or NOKp, UV=0x%" UVxf " NV=%" NVgf "\n",
+                                  SvPVX_const(sv), SvIVX(sv), SvNVX(sv)));
+        }
     }
 #endif /* PERL_PRESERVE_IVUV */
     sv_setnv(sv,Atof(SvPVX_const(sv)) - 1.0);  /* punt */
@@ -9227,10 +9518,10 @@ Perl_sv_dec_nomg(pTHX_ SV *const sv)
  */
 #define PUSH_EXTEND_MORTAL__SV_C(AnSv) \
     STMT_START {      \
-       SSize_t ix = ++PL_tmps_ix;              \
-       if (UNLIKELY(ix >= PL_tmps_max))        \
-           ix = tmps_grow_p(ix);                       \
-       PL_tmps_stack[ix] = (AnSv); \
+        SSize_t ix = ++PL_tmps_ix;             \
+        if (UNLIKELY(ix >= PL_tmps_max))       \
+            ix = tmps_grow_p(ix);                      \
+        PL_tmps_stack[ix] = (AnSv); \
     } STMT_END
 
 /*
@@ -9260,7 +9551,7 @@ Perl_sv_mortalcopy_flags(pTHX_ SV *const oldstr, U32 flags)
     SV *sv;
 
     if (flags & SV_GMAGIC)
-       SvGETMAGIC(oldstr); /* before new_SV, in case it dies */
+        SvGETMAGIC(oldstr); /* before new_SV, in case it dies */
     new_SV(sv);
     sv_setsv_flags(sv,oldstr,flags & ~SV_GMAGIC);
     PUSH_EXTEND_MORTAL__SV_C(sv);
@@ -9307,9 +9598,8 @@ C<SVf_UTF8> flag will be set on the new SV.
 C<newSVpvn_utf8()> is a convenience wrapper for this function, defined as
 
     #define newSVpvn_utf8(s, len, u)                   \
-       newSVpvn_flags((s), (len), (u) ? SVf_UTF8 : 0)
+        newSVpvn_flags((s), (len), (u) ? SVf_UTF8 : 0)
 
-=for apidoc Amnh||SVf_UTF8
 =for apidoc Amnh||SVs_TEMP
 
 =cut
@@ -9323,21 +9613,21 @@ Perl_newSVpvn_flags(pTHX_ const char *const s, const STRLEN len, const U32 flags
     /* All the flags we don't support must be zero.
        And we're new code so I'm going to assert this from the start.  */
     assert(!(flags & ~(SVf_UTF8|SVs_TEMP)));
-    new_SV(sv);
-    sv_setpvn(sv,s,len);
+    sv = newSV_type(SVt_PV);
+    sv_setpvn_fresh(sv,s,len);
 
     /* This code used to do a sv_2mortal(), however we now unroll the call to
      * sv_2mortal() and do what it does ourselves here.  Since we have asserted
      * that flags can only have the SVf_UTF8 and/or SVs_TEMP flags set above we
      * can use it to enable the sv flags directly (bypassing SvTEMP_on), which
-     * in turn means we dont need to mask out the SVf_UTF8 flag below, which
+     * in turn means we don't need to mask out the SVf_UTF8 flag below, which
      * means that we eliminate quite a few steps than it looks - Yves
      * (explaining patch by gfx) */
 
     SvFLAGS(sv) |= flags;
 
     if(flags & SVs_TEMP){
-       PUSH_EXTEND_MORTAL__SV_C(sv);
+        PUSH_EXTEND_MORTAL__SV_C(sv);
     }
 
     return sv;
@@ -9358,11 +9648,10 @@ C<L</sv_newmortal>> and C<L</sv_mortalcopy>>.
 SV *
 Perl_sv_2mortal(pTHX_ SV *const sv)
 {
-    dVAR;
     if (!sv)
-       return sv;
+        return sv;
     if (SvIMMORTAL(sv))
-       return sv;
+        return sv;
     PUSH_EXTEND_MORTAL__SV_C(sv);
     SvTEMP_on(sv);
     return sv;
@@ -9392,10 +9681,8 @@ to call C<strlen> use C<newSVpvn> instead (calling C<strlen> yourself).
 SV *
 Perl_newSVpv(pTHX_ const char *const s, const STRLEN len)
 {
-    SV *sv;
-
-    new_SV(sv);
-    sv_setpvn(sv, s, len || s == NULL ? len : strlen(s));
+    SV *sv = newSV_type(SVt_PV);
+    sv_setpvn_fresh(sv, s, len || s == NULL ? len : strlen(s));
     return sv;
 }
 
@@ -9415,9 +9702,32 @@ undefined.
 SV *
 Perl_newSVpvn(pTHX_ const char *const buffer, const STRLEN len)
 {
-    SV *sv;
-    new_SV(sv);
-    sv_setpvn(sv,buffer,len);
+    SV *sv = newSV_type(SVt_PV);
+    sv_setpvn_fresh(sv,buffer,len);
+    return sv;
+}
+
+/*
+=for apidoc newSVhek_mortal
+
+Creates a new mortal SV from the hash key structure.  It will generate
+scalars that point to the shared string table where possible.  Returns
+a new (undefined) SV if C<hek> is NULL.
+
+This is more efficient than using sv_2mortal(newSVhek( ... ))
+
+=cut
+*/
+
+SV *
+Perl_newSVhek_mortal(pTHX_ const HEK *const hek)
+{
+    SV * const sv = newSVhek(hek);
+    assert(sv);
+    assert(!SvIMMORTAL(sv));
+
+    PUSH_EXTEND_MORTAL__SV_C(sv);
+    SvTEMP_on(sv);
     return sv;
 }
 
@@ -9435,54 +9745,52 @@ SV *
 Perl_newSVhek(pTHX_ const HEK *const hek)
 {
     if (!hek) {
-       SV *sv;
+        SV *sv;
 
-       new_SV(sv);
-       return sv;
+        new_SV(sv);
+        return sv;
     }
 
     if (HEK_LEN(hek) == HEf_SVKEY) {
-       return newSVsv(*(SV**)HEK_KEY(hek));
+        return newSVsv(*(SV**)HEK_KEY(hek));
     } else {
-       const int flags = HEK_FLAGS(hek);
-       if (flags & HVhek_WASUTF8) {
-           /* Trouble :-)
-              Andreas would like keys he put in as utf8 to come back as utf8
-           */
-           STRLEN utf8_len = HEK_LEN(hek);
-           SV * const sv = newSV_type(SVt_PV);
-           char *as_utf8 = (char *)bytes_to_utf8 ((U8*)HEK_KEY(hek), &utf8_len);
-           /* bytes_to_utf8() allocates a new string, which we can repurpose: */
-           sv_usepvn_flags(sv, as_utf8, utf8_len, SV_HAS_TRAILING_NUL);
-           SvUTF8_on (sv);
-           return sv;
-        } else if (flags & HVhek_UNSHARED) {
+        const int flags = HEK_FLAGS(hek);
+        if (flags & HVhek_WASUTF8) {
+            /* Trouble :-)
+               Andreas would like keys he put in as utf8 to come back as utf8
+            */
+            STRLEN utf8_len = HEK_LEN(hek);
+            SV * const sv = newSV_type(SVt_PV);
+            char *as_utf8 = (char *)bytes_to_utf8 ((U8*)HEK_KEY(hek), &utf8_len);
+            /* bytes_to_utf8() allocates a new string, which we can repurpose: */
+            sv_usepvn_flags(sv, as_utf8, utf8_len, SV_HAS_TRAILING_NUL);
+            SvUTF8_on (sv);
+            return sv;
+        } else if (flags & HVhek_NOTSHARED) {
             /* A hash that isn't using shared hash keys has to have
-              the flag in every key so that we know not to try to call
-              share_hek_hek on it.  */
-
-           SV * const sv = newSVpvn (HEK_KEY(hek), HEK_LEN(hek));
-           if (HEK_UTF8(hek))
-               SvUTF8_on (sv);
-           return sv;
-       }
-       /* This will be overwhelminly the most common case.  */
-       {
-           /* Inline most of newSVpvn_share(), because share_hek_hek() is far
-              more efficient than sharepvn().  */
-           SV *sv;
-
-           new_SV(sv);
-           sv_upgrade(sv, SVt_PV);
-           SvPV_set(sv, (char *)HEK_KEY(share_hek_hek(hek)));
-           SvCUR_set(sv, HEK_LEN(hek));
-           SvLEN_set(sv, 0);
-           SvIsCOW_on(sv);
-           SvPOK_on(sv);
-           if (HEK_UTF8(hek))
-               SvUTF8_on(sv);
-           return sv;
-       }
+               the flag in every key so that we know not to try to call
+               share_hek_hek on it.  */
+
+            SV * const sv = newSVpvn (HEK_KEY(hek), HEK_LEN(hek));
+            if (HEK_UTF8(hek))
+                SvUTF8_on (sv);
+            return sv;
+        }
+        /* This will be overwhelmingly the most common case.  */
+        {
+            /* Inline most of newSVpvn_share(), because share_hek_hek() is far
+               more efficient than sharepvn().  */
+            SV *sv = newSV_type(SVt_PV);
+
+            SvPV_set(sv, (char *)HEK_KEY(share_hek_hek(hek)));
+            SvCUR_set(sv, HEK_LEN(hek));
+            SvLEN_set(sv, 0);
+            SvIsCOW_on(sv);
+            SvPOK_on(sv);
+            if (HEK_UTF8(hek))
+                SvUTF8_on(sv);
+            return sv;
+        }
     }
 }
 
@@ -9495,7 +9803,7 @@ created first.  Turns on the C<SvIsCOW> flag (or C<READONLY>
 and C<FAKE> in 5.16 and earlier).  If the C<hash> parameter
 is non-zero, that value is used; otherwise the hash is computed.
 The string's hash can later be retrieved from the SV
-with the C<SvSHARED_HASH()> macro.  The idea here is
+with the C<L</SvSHARED_HASH>> macro.  The idea here is
 that as the string table is used for shared hash keys these strings will have
 C<SvPVX_const == HeKEY> and hash lookup will avoid string compare.
 
@@ -9505,24 +9813,22 @@ C<SvPVX_const == HeKEY> and hash lookup will avoid string compare.
 SV *
 Perl_newSVpvn_share(pTHX_ const char *src, I32 len, U32 hash)
 {
-    dVAR;
     SV *sv;
     bool is_utf8 = FALSE;
     const char *const orig_src = src;
 
     if (len < 0) {
-       STRLEN tmplen = -len;
+        STRLEN tmplen = -len;
         is_utf8 = TRUE;
-       /* See the note in hv.c:hv_fetch() --jhi */
-       src = (char*)bytes_from_utf8((const U8*)src, &tmplen, &is_utf8);
-       len = tmplen;
+        /* See the note in hv.c:hv_fetch() --jhi */
+        src = (char*)bytes_from_utf8((const U8*)src, &tmplen, &is_utf8);
+        len = tmplen;
     }
     if (!hash)
-       PERL_HASH(hash, src, len);
-    new_SV(sv);
+        PERL_HASH(hash, src, len);
+    sv = newSV_type(SVt_PV);
     /* 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);
     SvLEN_set(sv, 0);
@@ -9531,7 +9837,7 @@ Perl_newSVpvn_share(pTHX_ const char *src, I32 len, U32 hash)
     if (is_utf8)
         SvUTF8_on(sv);
     if (src != orig_src)
-       Safefree(src);
+        Safefree(src);
     return sv;
 }
 
@@ -9550,7 +9856,7 @@ Perl_newSVpv_share(pTHX_ const char *src, U32 hash)
     return newSVpvn_share(src, strlen(src), hash);
 }
 
-#if defined(PERL_IMPLICIT_CONTEXT)
+#if defined(MULTIPLICITY)
 
 /* pTHX_ magic can't cope with varargs, so this is a no-context
  * version of the main function, (which may itself be aliased to us).
@@ -9579,6 +9885,14 @@ Perl_newSVpvf_nocontext(const char *const pat, ...)
 Creates a new SV and initializes it with the string formatted like
 C<sv_catpvf>.
 
+=for apidoc newSVpvf_nocontext
+Like C<L</newSVpvf>> but does not take a thread context (C<aTHX>) parameter,
+so is used in situations where the caller doesn't already have the thread
+context.
+
+=for apidoc vnewSVpvf
+Like C<L</newSVpvf>> but the arguments are an encapsulated argument list.
+
 =cut
 */
 
@@ -9605,8 +9919,9 @@ Perl_vnewSVpvf(pTHX_ const char *const pat, va_list *const args)
 
     PERL_ARGS_ASSERT_VNEWSVPVF;
 
-    new_SV(sv);
-    sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
+    sv = newSV(1);
+    SvPVCLEAR_FRESH(sv);
+    sv_vcatpvfn_flags(sv, pat, strlen(pat), args, NULL, 0, NULL, 0);
     return sv;
 }
 
@@ -9622,10 +9937,12 @@ The reference count for the SV is set to 1.
 SV *
 Perl_newSVnv(pTHX_ const NV n)
 {
-    SV *sv;
+    SV *sv = newSV_type(SVt_NV);
+    (void)SvNOK_on(sv);
+
+    SvNV_set(sv, n);
+    SvTAINT(sv);
 
-    new_SV(sv);
-    sv_setnv(sv,n);
     return sv;
 }
 
@@ -9641,20 +9958,7 @@ SV is set to 1.
 SV *
 Perl_newSViv(pTHX_ const IV i)
 {
-    SV *sv;
-
-    new_SV(sv);
-
-    /* Inlining ONLY the small relevant subset of sv_setiv here
-     * for performance. Makes a significant difference. */
-
-    /* We're starting from SVt_FIRST, so provided that's
-     * actual 0, we don't have to unset any SV type flags
-     * to promote to SVt_IV. */
-    STATIC_ASSERT_STMT(SVt_FIRST == 0);
-
-    SET_SVANY_FOR_BODYLESS_IV(sv);
-    SvFLAGS(sv) |= SVt_IV;
+    SV *sv = newSV_type(SVt_IV);
     (void)SvIOK_on(sv);
 
     SvIV_set(sv, i);
@@ -9682,7 +9986,7 @@ Perl_newSVuv(pTHX_ const UV u)
 
     /* Using ivs is more efficient than using uvs - see sv_setuv */
     if (u <= (UV)IV_MAX) {
-       return newSViv((IV)u);
+        return newSViv((IV)u);
     }
 
     new_SV(sv);
@@ -9704,56 +10008,51 @@ Perl_newSVuv(pTHX_ const UV u)
 }
 
 /*
-=for apidoc newSV_type
+=for apidoc newSVbool
 
-Creates a new SV, of the type specified.  The reference count for the new SV
-is set to 1.
+Creates a new SV boolean.
 
 =cut
 */
 
 SV *
-Perl_newSV_type(pTHX_ const svtype type)
+Perl_newSVbool(pTHX_ bool bool_val)
 {
-    SV *sv;
+    PERL_ARGS_ASSERT_NEWSVBOOL;
+    SV *sv = newSVsv(bool_val ? &PL_sv_yes : &PL_sv_no);
 
-    new_SV(sv);
-    ASSUME(SvTYPE(sv) == SVt_FIRST);
-    if(type != SVt_FIRST)
-       sv_upgrade(sv, type);
     return sv;
 }
 
 /*
-=for apidoc newRV_noinc
+=for apidoc newSV_true
 
-Creates an RV wrapper for an SV.  The reference count for the original
-SV is B<not> incremented.
+Creates a new SV that is a boolean true.
 
 =cut
 */
-
 SV *
-Perl_newRV_noinc(pTHX_ SV *const tmpRef)
+Perl_newSV_true(pTHX)
 {
-    SV *sv;
+    PERL_ARGS_ASSERT_NEWSV_TRUE;
+    SV *sv = newSVsv(&PL_sv_yes);
 
-    PERL_ARGS_ASSERT_NEWRV_NOINC;
+    return sv;
+}
 
-    new_SV(sv);
+/*
+=for apidoc newSV_false
 
-    /* We're starting from SVt_FIRST, so provided that's
-     * actual 0, we don't have to unset any SV type flags
-     * to promote to SVt_IV. */
-    STATIC_ASSERT_STMT(SVt_FIRST == 0);
+Creates a new SV that is a boolean false.
 
-    SET_SVANY_FOR_BODYLESS_IV(sv);
-    SvFLAGS(sv) |= SVt_IV;
-    SvROK_on(sv);
-    SvIV_set(sv, 0);
+=cut
+*/
 
-    SvTEMP_off(tmpRef);
-    SvRV_set(sv, tmpRef);
+SV *
+Perl_newSV_false(pTHX)
+{
+    PERL_ARGS_ASSERT_NEWSV_FALSE;
+    SV *sv = newSVsv(&PL_sv_no);
 
     return sv;
 }
@@ -9772,13 +10071,15 @@ Perl_newRV(pTHX_ SV *const sv)
 
 /*
 =for apidoc newSVsv
+=for apidoc_item newSVsv_flags
+=for apidoc_item newSVsv_nomg
 
-Creates a new SV which is an exact duplicate of the original SV.
-(Uses C<sv_setsv>.)
+These create a new SV which is an exact duplicate of the original SV
+(using C<sv_setsv>.)
 
-=for apidoc newSVsv_nomg
-
-Like C<newSVsv> but does not process get magic.
+They differ only in that C<newSVsv> performs 'get' magic; C<newSVsv_nomg> skips
+any magic; and C<newSVsv_flags> allows you to explicitly set a C<flags>
+parameter.
 
 =cut
 */
@@ -9789,10 +10090,10 @@ Perl_newSVsv_flags(pTHX_ SV *const old, I32 flags)
     SV *sv;
 
     if (!old)
-       return NULL;
-    if (SvTYPE(old) == (svtype)SVTYPEMASK) {
-       Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL), "semi-panic: attempt to dup freed string");
-       return NULL;
+        return NULL;
+    if (SvIS_FREED(old)) {
+        Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL), "semi-panic: attempt to dup freed string");
+        return NULL;
     }
     /* Do this here, otherwise we leak the new SV if this croaks. */
     if (flags & SV_GMAGIC)
@@ -9826,71 +10127,74 @@ Perl_sv_resetpvn(pTHX_ const char *s, STRLEN len, HV * const stash)
     const char *send;
 
     if (!stash || SvTYPE(stash) != SVt_PVHV)
-       return;
+        return;
 
     if (!s) {          /* reset ?? searches */
-       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;
-           PMOP *const *const end = pmp + count;
+        MAGIC * const mg = mg_find((const SV *)stash, PERL_MAGIC_symtab);
+        if (mg && mg->mg_len) {
+            const U32 count = mg->mg_len / sizeof(PMOP**);
+            PMOP **pmp = (PMOP**) mg->mg_ptr;
+            PMOP *const *const end = pmp + count;
 
-           while (pmp < end) {
+            while (pmp < end) {
 #ifdef USE_ITHREADS
                 SvREADONLY_off(PL_regex_pad[(*pmp)->op_pmoffset]);
 #else
-               (*pmp)->op_pmflags &= ~PMf_USED;
+                (*pmp)->op_pmflags &= ~PMf_USED;
 #endif
-               ++pmp;
-           }
-       }
-       return;
+                ++pmp;
+            }
+        }
+        return;
     }
 
     /* reset variables */
 
-    if (!HvARRAY(stash))
-       return;
+    if (!HvTOTALKEYS(stash))
+        return;
 
     Zero(todo, 256, char);
     send = s + len;
     while (s < send) {
-       I32 max;
-       I32 i = (unsigned char)*s;
-       if (s[1] == '-') {
-           s += 2;
-       }
-       max = (unsigned char)*s++;
-       for ( ; i <= max; i++) {
-           todo[i] = 1;
-       }
-       for (i = 0; i <= (I32) HvMAX(stash); i++) {
-           HE *entry;
-           for (entry = HvARRAY(stash)[i];
-                entry;
-                entry = HeNEXT(entry))
-           {
-               GV *gv;
-               SV *sv;
-
-               if (!todo[(U8)*HeKEY(entry)])
-                   continue;
-               gv = MUTABLE_GV(HeVAL(entry));
-               if (!isGV(gv))
-                   continue;
-               sv = GvSV(gv);
-               if (sv && !SvREADONLY(sv)) {
-                   SV_CHECK_THINKFIRST_COW_DROP(sv);
-                   if (!isGV(sv)) SvOK_off(sv);
-               }
-               if (GvAV(gv)) {
-                   av_clear(GvAV(gv));
-               }
-               if (GvHV(gv) && !HvNAME_get(GvHV(gv))) {
-                   hv_clear(GvHV(gv));
-               }
-           }
-       }
+        I32 max;
+        I32 i = (unsigned char)*s;
+        if (s[1] == '-') {
+            s += 2;
+        }
+        max = (unsigned char)*s++;
+        for ( ; i <= max; i++) {
+            todo[i] = 1;
+        }
+        for (i = 0; i <= (I32) HvMAX(stash); i++) {
+            HE *entry;
+            for (entry = HvARRAY(stash)[i];
+                 entry;
+                 entry = HeNEXT(entry))
+            {
+                GV *gv;
+                SV *sv;
+
+                if (!todo[(U8)*HeKEY(entry)])
+                    continue;
+                gv = MUTABLE_GV(HeVAL(entry));
+                if (!isGV(gv))
+                    continue;
+                sv = GvSV(gv);
+                if (sv && !SvREADONLY(sv)) {
+                    SV_CHECK_THINKFIRST_COW_DROP(sv);
+                    if (!isGV(sv)) {
+                        SvOK_off(sv);
+                        SvSETMAGIC(sv);
+                    }
+                }
+                if (GvAV(gv)) {
+                    av_clear(GvAV(gv));
+                }
+                if (GvHV(gv) && !HvHasNAME(GvHV(gv))) {
+                    hv_clear(GvHV(gv));
+                }
+            }
+        }
     }
 }
 
@@ -9917,40 +10221,40 @@ Perl_sv_2io(pTHX_ SV *const sv)
 
     switch (SvTYPE(sv)) {
     case SVt_PVIO:
-       io = MUTABLE_IO(sv);
-       break;
+        io = MUTABLE_IO(sv);
+        break;
     case SVt_PVGV:
     case SVt_PVLV:
-       if (isGV_with_GP(sv)) {
-           gv = MUTABLE_GV(sv);
-           io = GvIO(gv);
-           if (!io)
-               Perl_croak(aTHX_ "Bad filehandle: %" HEKf,
+        if (isGV_with_GP(sv)) {
+            gv = MUTABLE_GV(sv);
+            io = GvIO(gv);
+            if (!io)
+                Perl_croak(aTHX_ "Bad filehandle: %" HEKf,
                                     HEKfARG(GvNAME_HEK(gv)));
-           break;
-       }
-       /* FALLTHROUGH */
+            break;
+        }
+        /* FALLTHROUGH */
     default:
-       if (!SvOK(sv))
-           Perl_croak(aTHX_ PL_no_usym, "filehandle");
-       if (SvROK(sv)) {
-           SvGETMAGIC(SvRV(sv));
-           return sv_2io(SvRV(sv));
-       }
-       gv = gv_fetchsv_nomg(sv, 0, SVt_PVIO);
-       if (gv)
-           io = GvIO(gv);
-       else
-           io = 0;
-       if (!io) {
-           SV *newsv = sv;
-           if (SvGMAGICAL(sv)) {
-               newsv = sv_newmortal();
-               sv_setsv_nomg(newsv, sv);
-           }
-           Perl_croak(aTHX_ "Bad filehandle: %" SVf, SVfARG(newsv));
-       }
-       break;
+        if (!SvOK(sv))
+            Perl_croak(aTHX_ PL_no_usym, "filehandle");
+        if (SvROK(sv)) {
+            SvGETMAGIC(SvRV(sv));
+            return sv_2io(SvRV(sv));
+        }
+        gv = gv_fetchsv_nomg(sv, 0, SVt_PVIO);
+        if (gv)
+            io = GvIO(gv);
+        else
+            io = 0;
+        if (!io) {
+            SV *newsv = sv;
+            if (SvGMAGICAL(sv)) {
+                newsv = sv_newmortal();
+                sv_setsv_nomg(newsv, sv);
+            }
+            Perl_croak(aTHX_ "Bad filehandle: %" SVf, SVfARG(newsv));
+        }
+        break;
     }
     return io;
 }
@@ -9974,62 +10278,62 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **const st, GV **const gvp, const I32 lref)
     PERL_ARGS_ASSERT_SV_2CV;
 
     if (!sv) {
-       *st = NULL;
-       *gvp = NULL;
-       return NULL;
+        *st = NULL;
+        *gvp = NULL;
+        return NULL;
     }
     switch (SvTYPE(sv)) {
     case SVt_PVCV:
-       *st = CvSTASH(sv);
-       *gvp = NULL;
-       return MUTABLE_CV(sv);
+        *st = CvSTASH(sv);
+        *gvp = NULL;
+        return MUTABLE_CV(sv);
     case SVt_PVHV:
     case SVt_PVAV:
-       *st = NULL;
-       *gvp = NULL;
-       return NULL;
+        *st = NULL;
+        *gvp = NULL;
+        return NULL;
     default:
-       SvGETMAGIC(sv);
-       if (SvROK(sv)) {
-           if (SvAMAGIC(sv))
-               sv = amagic_deref_call(sv, to_cv_amg);
-
-           sv = SvRV(sv);
-           if (SvTYPE(sv) == SVt_PVCV) {
-               cv = MUTABLE_CV(sv);
-               *gvp = NULL;
-               *st = CvSTASH(cv);
-               return cv;
-           }
-           else if(SvGETMAGIC(sv), isGV_with_GP(sv))
-               gv = MUTABLE_GV(sv);
-           else
-               Perl_croak(aTHX_ "Not a subroutine reference");
-       }
-       else if (isGV_with_GP(sv)) {
-           gv = MUTABLE_GV(sv);
-       }
-       else {
-           gv = gv_fetchsv_nomg(sv, lref, SVt_PVCV);
-       }
-       *gvp = gv;
-       if (!gv) {
-           *st = NULL;
-           return NULL;
-       }
-       /* Some flags to gv_fetchsv mean don't really create the GV  */
-       if (!isGV_with_GP(gv)) {
-           *st = NULL;
-           return NULL;
-       }
-       *st = GvESTASH(gv);
-       if (lref & ~GV_ADDMG && !GvCVu(gv)) {
-           /* XXX this is probably not what they think they're getting.
-            * It has the same effect as "sub name;", i.e. just a forward
-            * declaration! */
-           newSTUB(gv,0);
-       }
-       return GvCVu(gv);
+        SvGETMAGIC(sv);
+        if (SvROK(sv)) {
+            if (SvAMAGIC(sv))
+                sv = amagic_deref_call(sv, to_cv_amg);
+
+            sv = SvRV(sv);
+            if (SvTYPE(sv) == SVt_PVCV) {
+                cv = MUTABLE_CV(sv);
+                *gvp = NULL;
+                *st = CvSTASH(cv);
+                return cv;
+            }
+            else if(SvGETMAGIC(sv), isGV_with_GP(sv))
+                gv = MUTABLE_GV(sv);
+            else
+                Perl_croak(aTHX_ "Not a subroutine reference");
+        }
+        else if (isGV_with_GP(sv)) {
+            gv = MUTABLE_GV(sv);
+        }
+        else {
+            gv = gv_fetchsv_nomg(sv, lref, SVt_PVCV);
+        }
+        *gvp = gv;
+        if (!gv) {
+            *st = NULL;
+            return NULL;
+        }
+        /* Some flags to gv_fetchsv mean don't really create the GV  */
+        if (!isGV_with_GP(gv)) {
+            *st = NULL;
+            return NULL;
+        }
+        *st = GvESTASH(gv);
+        if (lref & ~GV_ADDMG && !GvCVu(gv)) {
+            /* XXX this is probably not what they think they're getting.
+             * It has the same effect as "sub name;", i.e. just a forward
+             * declaration! */
+            newSTUB(gv,0);
+        }
+        return GvCVu(gv);
     }
 }
 
@@ -10047,25 +10351,25 @@ I32
 Perl_sv_true(pTHX_ SV *const sv)
 {
     if (!sv)
-       return 0;
+        return 0;
     if (SvPOK(sv)) {
-       const XPV* const tXpv = (XPV*)SvANY(sv);
-       if (tXpv &&
-               (tXpv->xpv_cur > 1 ||
-               (tXpv->xpv_cur && *sv->sv_u.svu_pv != '0')))
-           return 1;
-       else
-           return 0;
+        const XPV* const tXpv = (XPV*)SvANY(sv);
+        if (tXpv &&
+                (tXpv->xpv_cur > 1 ||
+                (tXpv->xpv_cur && *sv->sv_u.svu_pv != '0')))
+            return 1;
+        else
+            return 0;
     }
     else {
-       if (SvIOK(sv))
-           return SvIVX(sv) != 0;
-       else {
-           if (SvNOK(sv))
-               return SvNVX(sv) != 0.0;
-           else
-               return sv_2bool(sv);
-       }
+        if (SvIOK(sv))
+            return SvIVX(sv) != 0;
+        else {
+            if (SvNOK(sv))
+                return SvNVX(sv) != 0.0;
+            else
+                return sv_2bool(sv);
+        }
     }
 }
 
@@ -10079,7 +10383,7 @@ can't cope with complex macro expressions.  Always use the macro instead.
 =for apidoc sv_pvn_force_flags
 
 Get a sensible string out of the SV somehow.
-If C<flags> has the C<SV_GMAGIC> bit set, will C<mg_get> on C<sv> if
+If C<flags> has the C<SV_GMAGIC> bit set, will C<L</mg_get>> on C<sv> if
 appropriate, else not.  C<sv_pvn_force> and C<sv_pvn_force_nomg> are
 implemented in terms of this function.
 You normally want to use the various wrapper macros instead: see
@@ -10089,7 +10393,7 @@ C<L</SvPV_force>> and C<L</SvPV_force_nomg>>.
 */
 
 char *
-Perl_sv_pvn_force_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags)
+Perl_sv_pvn_force_flags(pTHX_ SV *const sv, STRLEN *const lp, const U32 flags)
 {
     PERL_ARGS_ASSERT_SV_PVN_FORCE_FLAGS;
 
@@ -10098,41 +10402,41 @@ Perl_sv_pvn_force_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags)
         sv_force_normal_flags(sv, 0);
 
     if (SvPOK(sv)) {
-       if (lp)
-           *lp = SvCUR(sv);
+        if (lp)
+            *lp = SvCUR(sv);
     }
     else {
-       char *s;
-       STRLEN len;
-       if (SvTYPE(sv) > SVt_PVLV
-           || isGV_with_GP(sv))
-           /* diag_listed_as: Can't coerce %s to %s in %s */
-           Perl_croak(aTHX_ "Can't coerce %s to string in %s", sv_reftype(sv,0),
-               OP_DESC(PL_op));
-       s = sv_2pv_flags(sv, &len, flags &~ SV_GMAGIC);
-       if (!s) {
-         s = (char *)"";
-       }
-       if (lp)
-           *lp = len;
+        char *s;
+        STRLEN len;
+
+        if (SvTYPE(sv) > SVt_PVLV
+            || isGV_with_GP(sv))
+            /* diag_listed_as: Can't coerce %s to %s in %s */
+            Perl_croak(aTHX_ "Can't coerce %s to string in %s", sv_reftype(sv,0),
+                OP_DESC(PL_op));
+        s = sv_2pv_flags(sv, &len, flags &~ SV_GMAGIC);
+        if (!s) {
+          s = (char *)"";
+        }
+        if (lp)
+            *lp = len;
 
         if (SvTYPE(sv) < SVt_PV ||
             s != SvPVX_const(sv)) {    /* Almost, but not quite, sv_setpvn() */
-           if (SvROK(sv))
-               sv_unref(sv);
-           SvUPGRADE(sv, SVt_PV);              /* Never FALSE */
-           SvGROW(sv, len + 1);
-           Move(s,SvPVX(sv),len,char);
-           SvCUR_set(sv, len);
-           SvPVX(sv)[len] = '\0';
-       }
-       if (!SvPOK(sv)) {
-           SvPOK_on(sv);               /* validate pointer */
-           SvTAINT(sv);
-           DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%" UVxf " 2pv(%s)\n",
-                                 PTR2UV(sv),SvPVX_const(sv)));
-       }
+            if (SvROK(sv))
+                sv_unref(sv);
+            SvUPGRADE(sv, SVt_PV);             /* Never FALSE */
+            SvGROW(sv, len + 1);
+            Move(s,SvPVX(sv),len,char);
+            SvCUR_set(sv, len);
+            SvPVX(sv)[len] = '\0';
+        }
+        if (!SvPOK(sv)) {
+            SvPOK_on(sv);              /* validate pointer */
+            SvTAINT(sv);
+            DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%" UVxf " 2pv(%s)\n",
+                                  PTR2UV(sv),SvPVX_const(sv)));
+        }
     }
     (void)SvPOK_only_UTF8(sv);
     return SvPVX_mutable(sv);
@@ -10142,7 +10446,7 @@ Perl_sv_pvn_force_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags)
 =for apidoc sv_pvbyten_force
 
 The backend for the C<SvPVbytex_force> macro.  Always use the macro
-instead.
+instead.  If the SV cannot be downgraded from UTF-8, this croaks.
 
 =cut
 */
@@ -10153,7 +10457,7 @@ 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);
+    (void)sv_utf8_downgrade(sv,0);
     *lp = SvCUR(sv);
     return SvPVX(sv);
 }
@@ -10194,7 +10498,7 @@ Perl_sv_reftype(pTHX_ const SV *const sv, const int ob)
 {
     PERL_ARGS_ASSERT_SV_REFTYPE;
     if (ob && SvOBJECT(sv)) {
-       return SvPV_nolen_const(sv_ref(NULL, sv, ob));
+        return SvPV_nolen_const(sv_ref(NULL, sv, ob));
     }
     else {
         /* WARNING - There is code, for instance in mg.c, that assumes that
@@ -10205,37 +10509,38 @@ Perl_sv_reftype(pTHX_ const SV *const sv, const int ob)
          * Do not change this assumption without searching for "dodgy type check" in
          * the code.
          * - Yves */
-       switch (SvTYPE(sv)) {
-       case SVt_NULL:
-       case SVt_IV:
-       case SVt_NV:
-       case SVt_PV:
-       case SVt_PVIV:
-       case SVt_PVNV:
-       case SVt_PVMG:
-                               if (SvVOK(sv))
-                                   return "VSTRING";
-                               if (SvROK(sv))
-                                   return "REF";
-                               else
-                                   return "SCALAR";
-
-       case SVt_PVLV:          return (char *)  (SvROK(sv) ? "REF"
-                               /* tied lvalues should appear to be
-                                * scalars for backwards compatibility */
-                               : (isALPHA_FOLD_EQ(LvTYPE(sv), 't'))
-                                   ? "SCALAR" : "LVALUE");
-       case SVt_PVAV:          return "ARRAY";
-       case SVt_PVHV:          return "HASH";
-       case SVt_PVCV:          return "CODE";
-       case SVt_PVGV:          return (char *) (isGV_with_GP(sv)
-                                   ? "GLOB" : "SCALAR");
-       case SVt_PVFM:          return "FORMAT";
-       case SVt_PVIO:          return "IO";
-       case SVt_INVLIST:       return "INVLIST";
-       case SVt_REGEXP:        return "REGEXP";
-       default:                return "UNKNOWN";
-       }
+        switch (SvTYPE(sv)) {
+        case SVt_NULL:
+        case SVt_IV:
+        case SVt_NV:
+        case SVt_PV:
+        case SVt_PVIV:
+        case SVt_PVNV:
+        case SVt_PVMG:
+                                if (SvVOK(sv))
+                                    return "VSTRING";
+                                if (SvROK(sv))
+                                    return "REF";
+                                else
+                                    return "SCALAR";
+
+        case SVt_PVLV:         return (char *)  (SvROK(sv) ? "REF"
+                                /* tied lvalues should appear to be
+                                 * scalars for backwards compatibility */
+                                : (isALPHA_FOLD_EQ(LvTYPE(sv), 't'))
+                                    ? "SCALAR" : "LVALUE");
+        case SVt_PVAV:         return "ARRAY";
+        case SVt_PVHV:         return "HASH";
+        case SVt_PVCV:         return "CODE";
+        case SVt_PVGV:         return (char *) (isGV_with_GP(sv)
+                                    ? "GLOB" : "SCALAR");
+        case SVt_PVFM:         return "FORMAT";
+        case SVt_PVIO:         return "IO";
+        case SVt_INVLIST:      return "INVLIST";
+        case SVt_REGEXP:       return "REGEXP";
+        case SVt_PVOBJ:         return "OBJECT";
+        default:               return "UNKNOWN";
+        }
     }
 }
 
@@ -10262,9 +10567,10 @@ Perl_sv_ref(pTHX_ SV *dst, const SV *const sv, const int ob)
         dst = sv_newmortal();
 
     if (ob && SvOBJECT(sv)) {
-       HvNAME_get(SvSTASH(sv))
-                    ? sv_sethek(dst, HvNAME_HEK(SvSTASH(sv)))
-                    : sv_setpvs(dst, "__ANON__");
+        if (HvHasNAME(SvSTASH(sv)))
+            sv_sethek(dst, HvNAME_HEK(SvSTASH(sv)));
+        else
+            sv_setpvs(dst, "__ANON__");
     }
     else {
         const char * reftype = sv_reftype(sv, 0);
@@ -10287,13 +10593,13 @@ int
 Perl_sv_isobject(pTHX_ SV *sv)
 {
     if (!sv)
-       return 0;
+        return 0;
     SvGETMAGIC(sv);
     if (!SvROK(sv))
-       return 0;
+        return 0;
     sv = SvRV(sv);
     if (!SvOBJECT(sv))
-       return 0;
+        return 0;
     return 1;
 }
 
@@ -10301,8 +10607,12 @@ Perl_sv_isobject(pTHX_ SV *sv)
 =for apidoc sv_isa
 
 Returns a boolean indicating whether the SV is blessed into the specified
-class.  This does not check for subtypes; use C<sv_derived_from> to verify
-an inheritance relationship.
+class.
+
+This does not check for subtypes or method overloading. Use C<sv_isa_sv> to
+verify an inheritance relationship in the same way as the C<isa> operator by
+respecting any C<isa()> method overloading; or C<sv_derived_from_sv> to test
+directly on the actual object type.
 
 =cut
 */
@@ -10315,16 +10625,16 @@ Perl_sv_isa(pTHX_ SV *sv, const char *const name)
     PERL_ARGS_ASSERT_SV_ISA;
 
     if (!sv)
-       return 0;
+        return 0;
     SvGETMAGIC(sv);
     if (!SvROK(sv))
-       return 0;
+        return 0;
     sv = SvRV(sv);
     if (!SvOBJECT(sv))
-       return 0;
+        return 0;
     hvname = HvNAME_get(SvSTASH(sv));
     if (!hvname)
-       return 0;
+        return 0;
 
     return strEQ(hvname, name);
 }
@@ -10353,17 +10663,17 @@ Perl_newSVrv(pTHX_ SV *const rv, const char *const classname)
     SV_CHECK_THINKFIRST_COW_DROP(rv);
 
     if (UNLIKELY( SvTYPE(rv) >= SVt_PVMG )) {
-       const U32 refcnt = SvREFCNT(rv);
-       SvREFCNT(rv) = 0;
-       sv_clear(rv);
-       SvFLAGS(rv) = 0;
-       SvREFCNT(rv) = refcnt;
+        const U32 refcnt = SvREFCNT(rv);
+        SvREFCNT(rv) = 0;
+        sv_clear(rv);
+        SvFLAGS(rv) = 0;
+        SvREFCNT(rv) = refcnt;
 
-       sv_upgrade(rv, SVt_IV);
+        sv_upgrade(rv, SVt_IV);
     } else if (SvROK(rv)) {
-       SvREFCNT_dec(SvRV(rv));
+        SvREFCNT_dec(SvRV(rv));
     } else {
-       prepare_SV_for_RV(rv);
+        prepare_SV_for_RV(rv);
     }
 
     SvOK_off(rv);
@@ -10371,8 +10681,8 @@ Perl_newSVrv(pTHX_ SV *const rv, const char *const classname)
     SvROK_on(rv);
 
     if (classname) {
-       HV* const stash = gv_stashpv(classname, GV_ADD);
-       (void)sv_bless(rv, stash);
+        HV* const stash = gv_stashpv(classname, GV_ADD);
+        (void)sv_bless(rv, stash);
     }
     return sv;
 }
@@ -10414,11 +10724,11 @@ Perl_sv_setref_pv(pTHX_ SV *const rv, const char *const classname, void *const p
     PERL_ARGS_ASSERT_SV_SETREF_PV;
 
     if (!pv) {
-       sv_set_undef(rv);
-       SvSETMAGIC(rv);
+        sv_set_undef(rv);
+        SvSETMAGIC(rv);
     }
     else
-       sv_setiv(newSVrv(rv,classname), PTR2IV(pv));
+        sv_setiv(newSVrv(rv,classname), PTR2IV(pv));
     return rv;
 }
 
@@ -10531,13 +10841,18 @@ Perl_sv_bless(pTHX_ SV *const sv, HV *const stash)
     SvGETMAGIC(sv);
     if (!SvROK(sv))
         Perl_croak(aTHX_ "Can't bless non-reference value");
+    if (HvSTASH_IS_CLASS(stash))
+        Perl_croak(aTHX_ "Attempt to bless into a class");
+
     tmpRef = SvRV(sv);
     if (SvFLAGS(tmpRef) & (SVs_OBJECT|SVf_READONLY|SVf_PROTECT)) {
-       if (SvREADONLY(tmpRef))
-           Perl_croak_no_modify();
-       if (SvOBJECT(tmpRef)) {
-           oldstash = SvSTASH(tmpRef);
-       }
+        if (SvREADONLY(tmpRef))
+            Perl_croak_no_modify();
+        if (SvTYPE(tmpRef) == SVt_PVOBJ)
+            Perl_croak(aTHX_ "Can't bless an object reference");
+        if (SvOBJECT(tmpRef)) {
+            oldstash = SvSTASH(tmpRef);
+        }
     }
     SvOBJECT_on(tmpRef);
     SvUPGRADE(tmpRef, SVt_PVMG);
@@ -10569,34 +10884,34 @@ S_sv_unglob(pTHX_ SV *const sv, U32 flags)
     assert(SvTYPE(sv) == SVt_PVGV || SvTYPE(sv) == SVt_PVLV);
     SvFAKE_off(sv);
     if (!(flags & SV_COW_DROP_PV))
-       gv_efullname3(temp, MUTABLE_GV(sv), "*");
+        gv_efullname3(temp, MUTABLE_GV(sv), "*");
 
     SvREFCNT_inc_simple_void_NN(sv_2mortal(sv));
     if (GvGP(sv)) {
         if(GvCVu((const GV *)sv) && (stash = GvSTASH(MUTABLE_GV(sv)))
-          && HvNAME_get(stash))
+           && HvHasNAME(stash))
             mro_method_changed_in(stash);
-       gp_free(MUTABLE_GV(sv));
+        gp_free(MUTABLE_GV(sv));
     }
     if (GvSTASH(sv)) {
-       sv_del_backref(MUTABLE_SV(GvSTASH(sv)), sv);
-       GvSTASH(sv) = NULL;
+        sv_del_backref(MUTABLE_SV(GvSTASH(sv)), sv);
+        GvSTASH(sv) = NULL;
     }
     GvMULTI_off(sv);
     if (GvNAME_HEK(sv)) {
-       unshare_hek(GvNAME_HEK(sv));
+        unshare_hek(GvNAME_HEK(sv));
     }
     isGV_with_GP_off(sv);
 
     if(SvTYPE(sv) == SVt_PVGV) {
-       /* need to keep SvANY(sv) in the right arena */
-       xpvmg = new_XPVMG();
-       StructCopy(SvANY(sv), xpvmg, XPVMG);
-       del_XPVGV(SvANY(sv));
-       SvANY(sv) = xpvmg;
+        /* need to keep SvANY(sv) in the right arena */
+        xpvmg = new_XPVMG();
+        StructCopy(SvANY(sv), xpvmg, XPVMG);
+        del_body_by_type(SvANY(sv), SVt_PVGV);
+        SvANY(sv) = xpvmg;
 
-       SvFLAGS(sv) &= ~SVTYPEMASK;
-       SvFLAGS(sv) |= SVt_PVMG;
+        SvFLAGS(sv) &= ~SVTYPEMASK;
+        SvFLAGS(sv) |= SVt_PVMG;
     }
 
     /* Intentionally not calling any local SET magic, as this isn't so much a
@@ -10605,9 +10920,9 @@ S_sv_unglob(pTHX_ SV *const sv, U32 flags)
     else sv_setsv_flags(sv, temp, 0);
 
     if ((const GV *)sv == PL_last_in_gv)
-       PL_last_in_gv = NULL;
+        PL_last_in_gv = NULL;
     else if ((const GV *)sv == PL_statgv)
-       PL_statgv = NULL;
+        PL_statgv = NULL;
 }
 
 /*
@@ -10634,19 +10949,19 @@ Perl_sv_unref_flags(pTHX_ SV *const ref, const U32 flags)
     PERL_ARGS_ASSERT_SV_UNREF_FLAGS;
 
     if (SvWEAKREF(ref)) {
-       sv_del_backref(target, ref);
-       SvWEAKREF_off(ref);
-       SvRV_set(ref, NULL);
-       return;
+        sv_del_backref(target, ref);
+        SvWEAKREF_off(ref);
+        SvRV_set(ref, NULL);
+        return;
     }
     SvRV_set(ref, NULL);
     SvROK_off(ref);
     /* You can't have a || SvREADONLY(target) here, as $a = $$a, where $a was
        assigned to as BEGIN {$a = \"Foo"} will fail.  */
     if (SvREFCNT(target) != 1 || (flags & SV_IMMEDIATE_UNREF))
-       SvREFCNT_dec_NN(target);
+        SvREFCNT_dec_NN(target);
     else /* XXX Hack, but hard to make $a=$a->[1] work otherwise */
-       sv_2mortal(target);     /* Schedule for freeing later */
+        sv_2mortal(target);    /* Schedule for freeing later */
 }
 
 /*
@@ -10664,9 +10979,9 @@ Perl_sv_untaint(pTHX_ SV *const sv)
     PERL_UNUSED_CONTEXT;
 
     if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-       MAGIC * const mg = mg_find(sv, PERL_MAGIC_taint);
-       if (mg)
-           mg->mg_len &= ~1;
+        MAGIC * const mg = mg_find(sv, PERL_MAGIC_taint);
+        if (mg)
+            mg->mg_len &= ~1;
     }
 }
 
@@ -10685,67 +11000,14 @@ Perl_sv_tainted(pTHX_ SV *const sv)
     PERL_UNUSED_CONTEXT;
 
     if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-       const MAGIC * const mg = mg_find(sv, PERL_MAGIC_taint);
-       if (mg && (mg->mg_len & 1) )
-           return TRUE;
+        const MAGIC * const mg = mg_find(sv, PERL_MAGIC_taint);
+        if (mg && (mg->mg_len & 1) )
+            return TRUE;
     }
     return FALSE;
 }
 
-#ifndef NO_MATHOMS  /* Can't move these to mathoms.c because call uiv_2buf(),
-                       private to this file */
-
-/*
-=for apidoc sv_setpviv
-
-Copies an integer into the given SV, also updating its string value.
-Does not handle 'set' magic.  See C<L</sv_setpviv_mg>>.
-
-=cut
-*/
-
-void
-Perl_sv_setpviv(pTHX_ SV *const sv, const IV iv)
-{
-    /* The purpose of this union is to ensure that arr is aligned on
-       a 2 byte boundary, because that is what uiv_2buf() requires */
-    union {
-        char arr[TYPE_CHARS(UV)];
-        U16 dummy;
-    } buf;
-    char *ebuf;
-    char * const ptr = uiv_2buf(buf.arr, iv, 0, 0, &ebuf);
-
-    PERL_ARGS_ASSERT_SV_SETPVIV;
-
-    sv_setpvn(sv, ptr, ebuf - ptr);
-}
-
-/*
-=for apidoc sv_setpviv_mg
-
-Like C<sv_setpviv>, but also handles 'set' magic.
-
-=cut
-*/
-
-void
-Perl_sv_setpviv_mg(pTHX_ SV *const sv, const IV iv)
-{
-    PERL_ARGS_ASSERT_SV_SETPVIV_MG;
-
-    GCC_DIAG_IGNORE_STMT(-Wdeprecated-declarations);
-
-    sv_setpviv(sv, iv);
-
-    GCC_DIAG_RESTORE_STMT;
-
-    SvSETMAGIC(sv);
-}
-
-#endif  /* NO_MATHOMS */
-
-#if defined(PERL_IMPLICIT_CONTEXT)
+#if defined(MULTIPLICITY)
 
 /* pTHX_ magic can't cope with varargs, so this is a no-context
  * version of the main function, (which may itself be aliased to us).
@@ -10785,10 +11047,22 @@ Perl_sv_setpvf_mg_nocontext(SV *const sv, const char *const pat, ...)
 #endif
 
 /*
-=for apidoc sv_setpvf
+=for apidoc      sv_setpvf
+=for apidoc_item sv_setpvf_mg
+=for apidoc_item sv_setpvf_mg_nocontext
+=for apidoc_item sv_setpvf_nocontext
+
+These work like C<L</sv_catpvf>> but copy the text into the SV instead of
+appending it.
 
-Works like C<sv_catpvf> but copies the text into the SV instead of
-appending it.  Does not handle 'set' magic.  See C<L</sv_setpvf_mg>>.
+The differences between these are:
+
+C<sv_setpvf_mg> and C<sv_setpvf_mg_nocontext> perform 'set' magic; C<sv_setpvf>
+and C<sv_setpvf_nocontext> skip all magic.
+
+C<sv_setpvf_nocontext> and C<sv_setpvf_mg_nocontext> do not take a thread
+context (C<aTHX>) parameter, so are used in situations where the caller
+doesn't already have the thread context.
 
 =cut
 */
@@ -10807,11 +11081,16 @@ Perl_sv_setpvf(pTHX_ SV *const sv, const char *const pat, ...)
 
 /*
 =for apidoc sv_vsetpvf
+=for apidoc_item sv_vsetpvf_mg
+
+These work like C<L</sv_vcatpvf>> but copy the text into the SV instead of
+appending it.
 
-Works like C<sv_vcatpvf> but copies the text into the SV instead of
-appending it.  Does not handle 'set' magic.  See C<L</sv_vsetpvf_mg>>.
+They differ only in that C<sv_vsetpvf_mg> performs 'set' magic;
+C<sv_vsetpvf> skips all magic.
 
-Usually used via its frontend C<sv_setpvf>.
+They are usually used via their frontends, C<L</sv_setpvf>> and
+C<L</sv_setpvf_mg>>.
 
 =cut
 */
@@ -10824,14 +11103,6 @@ Perl_sv_vsetpvf(pTHX_ SV *const sv, const char *const pat, va_list *const args)
     sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
 }
 
-/*
-=for apidoc sv_setpvf_mg
-
-Like C<sv_setpvf>, but also handles 'set' magic.
-
-=cut
-*/
-
 void
 Perl_sv_setpvf_mg(pTHX_ SV *const sv, const char *const pat, ...)
 {
@@ -10844,16 +11115,6 @@ Perl_sv_setpvf_mg(pTHX_ SV *const sv, const char *const pat, ...)
     va_end(args);
 }
 
-/*
-=for apidoc sv_vsetpvf_mg
-
-Like C<sv_vsetpvf>, but also handles 'set' magic.
-
-Usually used via its frontend C<sv_setpvf_mg>.
-
-=cut
-*/
-
 void
 Perl_sv_vsetpvf_mg(pTHX_ SV *const sv, const char *const pat, va_list *const args)
 {
@@ -10863,7 +11124,7 @@ Perl_sv_vsetpvf_mg(pTHX_ SV *const sv, const char *const pat, va_list *const arg
     SvSETMAGIC(sv);
 }
 
-#if defined(PERL_IMPLICIT_CONTEXT)
+#if defined(MULTIPLICITY)
 
 /* pTHX_ magic can't cope with varargs, so this is a no-context
  * version of the main function, (which may itself be aliased to us).
@@ -10905,18 +11166,31 @@ Perl_sv_catpvf_mg_nocontext(SV *const sv, const char *const pat, ...)
 
 /*
 =for apidoc sv_catpvf
+=for apidoc_item sv_catpvf_mg
+=for apidoc_item sv_catpvf_mg_nocontext
+=for apidoc_item sv_catpvf_nocontext
+
+These process their arguments like C<sprintf>, and append the formatted
+output to an SV.  As with C<sv_vcatpvfn>, argument reordering is not supporte
+when called with a non-null C-style variable argument list.
 
-Processes its arguments like C<sprintf>, and appends the formatted
-output to an SV.  As with C<sv_vcatpvfn> called with a non-null C-style
-variable argument list, argument reordering is not supported.
 If the appended data contains "wide" characters
 (including, but not limited to, SVs with a UTF-8 PV formatted with C<%s>,
 and characters >255 formatted with C<%c>), the original SV might get
-upgraded to UTF-8.  Handles 'get' magic, but not 'set' magic.  See
-C<L</sv_catpvf_mg>>.  If the original SV was UTF-8, the pattern should be
+upgraded to UTF-8.
+
+If the original SV was UTF-8, the pattern should be
 valid UTF-8; if the original SV was bytes, the pattern should be too.
 
-=cut */
+All perform 'get' magic, but only C<sv_catpvf_mg> and C<sv_catpvf_mg_nocontext>
+perform 'set' magic.
+
+C<sv_catpvf_nocontext> and C<sv_catpvf_mg_nocontext> do not take a thread
+context (C<aTHX>) parameter, so are used in situations where the caller
+doesn't already have the thread context.
+
+=cut
+*/
 
 void
 Perl_sv_catpvf(pTHX_ SV *const sv, const char *const pat, ...)
@@ -10932,12 +11206,18 @@ Perl_sv_catpvf(pTHX_ SV *const sv, const char *const pat, ...)
 
 /*
 =for apidoc sv_vcatpvf
+=for apidoc_item sv_vcatpvf_mg
 
-Processes its arguments like C<sv_vcatpvfn> called with a non-null C-style
-variable argument list, and appends the formatted output
-to an SV.  Does not handle 'set' magic.  See C<L</sv_vcatpvf_mg>>.
+These process their arguments like C<sv_vcatpvfn> called with a non-null
+C-style variable argument list, and append the formatted output to C<sv>.
 
-Usually used via its frontend C<sv_catpvf>.
+They differ only in that C<sv_vcatpvf_mg> performs 'set' magic;
+C<sv_vcatpvf> skips 'set' magic.
+
+Both perform 'get' magic.
+
+They are usually accessed via their frontends C<L</sv_catpvf>> and
+C<L</sv_catpvf_mg>>.
 
 =cut
 */
@@ -10950,14 +11230,6 @@ Perl_sv_vcatpvf(pTHX_ SV *const sv, const char *const pat, va_list *const args)
     sv_vcatpvfn_flags(sv, pat, strlen(pat), args, NULL, 0, NULL, SV_GMAGIC|SV_SMAGIC);
 }
 
-/*
-=for apidoc sv_catpvf_mg
-
-Like C<sv_catpvf>, but also handles 'set' magic.
-
-=cut
-*/
-
 void
 Perl_sv_catpvf_mg(pTHX_ SV *const sv, const char *const pat, ...)
 {
@@ -10971,16 +11243,6 @@ Perl_sv_catpvf_mg(pTHX_ SV *const sv, const char *const pat, ...)
     va_end(args);
 }
 
-/*
-=for apidoc sv_vcatpvf_mg
-
-Like C<sv_vcatpvf>, but also handles 'set' magic.
-
-Usually used via its frontend C<sv_catpvf_mg>.
-
-=cut
-*/
-
 void
 Perl_sv_vcatpvf_mg(pTHX_ SV *const sv, const char *const pat, va_list *const args)
 {
@@ -10996,7 +11258,8 @@ Perl_sv_vcatpvf_mg(pTHX_ SV *const sv, const char *const pat, va_list *const arg
 Works like C<sv_vcatpvfn> but copies the text into the SV instead of
 appending it.
 
-Usually used via one of its frontends C<sv_vsetpvf> and C<sv_vsetpvf_mg>.
+Usually used via one of its frontends L</C<sv_vsetpvf>> and
+L</C<sv_vsetpvf_mg>>.
 
 =cut
 */
@@ -11043,8 +11306,8 @@ S_sv_catpvn_simple(pTHX_ SV *const sv, const char* const buf, const STRLEN len)
 STATIC void
 S_warn_vcatpvfn_missing_argument(pTHX) {
     if (ckWARN(WARN_MISSING)) {
-       Perl_warner(aTHX_ packWARN(WARN_MISSING), "Missing argument in %s",
-               PL_op ? OP_DESC(PL_op) : "sv_vcatpvfn()");
+        Perl_warner(aTHX_ packWARN(WARN_MISSING), "Missing argument in %s",
+                PL_op ? OP_DESC(PL_op) : "sv_vcatpvfn()");
     }
 }
 
@@ -11149,24 +11412,24 @@ S_F0convert(NV nv, char *const endbuf, STRLEN *const len)
 
     assert(!Perl_isinfnan(nv));
     if (neg)
-       nv = -nv;
-    if (nv != 0.0 && nv < UV_MAX) {
-       char *p = endbuf;
-       uv = (UV)nv;
-       if (uv != nv) {
-           nv += 0.5;
-           uv = (UV)nv;
-           if (uv & 1 && uv == nv)
-               uv--;                   /* Round to even */
-       }
-       do {
-           const unsigned dig = uv % 10;
-           *--p = '0' + dig;
-       } while (uv /= 10);
-       if (neg)
-           *--p = '-';
-       *len = endbuf - p;
-       return p;
+        nv = -nv;
+    if (nv != 0.0 && nv < (NV) UV_MAX) {
+        char *p = endbuf;
+        uv = (UV)nv;
+        if (uv != nv) {
+            nv += 0.5;
+            uv = (UV)nv;
+            if (uv & 1 && uv == nv)
+                uv--;                  /* Round to even */
+        }
+        do {
+            const unsigned dig = uv % 10;
+            *--p = '0' + dig;
+        } while (uv /= 10);
+        if (neg)
+            *--p = '-';
+        *len = endbuf - p;
+        return p;
     }
     return NULL;
 }
@@ -11192,7 +11455,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
  * synonym for "double").
 */
 #if defined(HAS_LONG_DOUBLE) && LONG_DOUBLESIZE > DOUBLESIZE && \
-       defined(PERL_PRIgldbl) && !defined(USE_QUADMATH)
+        defined(PERL_PRIgldbl) && !defined(USE_QUADMATH)
 #  define VCATPVFN_FV_GF PERL_PRIgldbl
 #  if defined(__VMS) && defined(__ia64) && defined(__IEEE_FLOAT)
        /* Work around breakage in OTS$CVT_FLOAT_T_X */
@@ -11361,7 +11624,7 @@ S_hextract(pTHX_ const NV nv, int* exponent, bool *subnormal,
         /* The bytes 13..0 are the mantissa/fraction,
          * the 15,14 are the sign+exponent. */
         const U8* nvp = (const U8*)(&nv);
-       HEXTRACT_GET_SUBNORMAL(nv);
+        HEXTRACT_GET_SUBNORMAL(nv);
         HEXTRACT_IMPLICIT_BIT(nv);
 #    undef HEXTRACT_HAS_TOP_NYBBLE
         HEXTRACT_BYTES_LE(13, 0);
@@ -11371,7 +11634,7 @@ S_hextract(pTHX_ const NV nv, int* exponent, bool *subnormal,
         /* The bytes 2..15 are the mantissa/fraction,
          * the 0,1 are the sign+exponent. */
         const U8* nvp = (const U8*)(&nv);
-       HEXTRACT_GET_SUBNORMAL(nv);
+        HEXTRACT_GET_SUBNORMAL(nv);
         HEXTRACT_IMPLICIT_BIT(nv);
 #    undef HEXTRACT_HAS_TOP_NYBBLE
         HEXTRACT_BYTES_BE(2, 15);
@@ -11381,11 +11644,11 @@ S_hextract(pTHX_ const NV nv, int* exponent, bool *subnormal,
          * NVSIZE can be either 12 (ILP32, Solaris x86) or 16 (LP64, Linux
          * and OS X), meaning that 2 or 6 bytes are empty padding. */
         /* The bytes 0..1 are the sign+exponent,
-        * the bytes 2..9 are the mantissa/fraction. */
+         * the bytes 2..9 are the mantissa/fraction. */
         const U8* nvp = (const U8*)(&nv);
 #    undef HEXTRACT_HAS_IMPLICIT_BIT
 #    undef HEXTRACT_HAS_TOP_NYBBLE
-       HEXTRACT_GET_SUBNORMAL(nv);
+        HEXTRACT_GET_SUBNORMAL(nv);
         HEXTRACT_BYTES_LE(7, 0);
 #  elif LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_BIG_ENDIAN
         /* Does this format ever happen? (Wikipedia says the Motorola
@@ -11395,7 +11658,7 @@ S_hextract(pTHX_ const NV nv, int* exponent, bool *subnormal,
         const U8* nvp = (const U8*)(&nv);
 #    undef HEXTRACT_HAS_IMPLICIT_BIT
 #    undef HEXTRACT_HAS_TOP_NYBBLE
-       HEXTRACT_GET_SUBNORMAL(nv);
+        HEXTRACT_GET_SUBNORMAL(nv);
         HEXTRACT_BYTES_BE(0, 7);
 #  else
 #    define HEXTRACT_FALLBACK
@@ -11431,21 +11694,21 @@ S_hextract(pTHX_ const NV nv, int* exponent, bool *subnormal,
 #    ifdef HEXTRACT_LITTLE_ENDIAN
         /* 0 1 2 3 4 5 6 7 (MSB = 7, LSB = 0, 6+7 = exponent+sign) */
         const U8* nvp = (const U8*)(&nv);
-       HEXTRACT_GET_SUBNORMAL(nv);
+        HEXTRACT_GET_SUBNORMAL(nv);
         HEXTRACT_IMPLICIT_BIT(nv);
         HEXTRACT_TOP_NYBBLE(6);
         HEXTRACT_BYTES_LE(5, 0);
 #    elif defined(HEXTRACT_BIG_ENDIAN)
         /* 7 6 5 4 3 2 1 0 (MSB = 7, LSB = 0, 6+7 = exponent+sign) */
         const U8* nvp = (const U8*)(&nv);
-       HEXTRACT_GET_SUBNORMAL(nv);
+        HEXTRACT_GET_SUBNORMAL(nv);
         HEXTRACT_IMPLICIT_BIT(nv);
         HEXTRACT_TOP_NYBBLE(1);
         HEXTRACT_BYTES_BE(2, 7);
 #    elif DOUBLEKIND == DOUBLE_IS_IEEE_754_64_BIT_MIXED_ENDIAN_LE_BE
         /* 4 5 6 7 0 1 2 3 (MSB = 7, LSB = 0, 6:7 = nybble:exponent:sign) */
         const U8* nvp = (const U8*)(&nv);
-       HEXTRACT_GET_SUBNORMAL(nv);
+        HEXTRACT_GET_SUBNORMAL(nv);
         HEXTRACT_IMPLICIT_BIT(nv);
         HEXTRACT_TOP_NYBBLE(2); /* 6 */
         HEXTRACT_BYTE(1); /* 5 */
@@ -11457,7 +11720,7 @@ S_hextract(pTHX_ const NV nv, int* exponent, bool *subnormal,
 #    elif DOUBLEKIND == DOUBLE_IS_IEEE_754_64_BIT_MIXED_ENDIAN_BE_LE
         /* 3 2 1 0 7 6 5 4 (MSB = 7, LSB = 0, 7:6 = sign:exponent:nybble) */
         const U8* nvp = (const U8*)(&nv);
-       HEXTRACT_GET_SUBNORMAL(nv);
+        HEXTRACT_GET_SUBNORMAL(nv);
         HEXTRACT_IMPLICIT_BIT(nv);
         HEXTRACT_TOP_NYBBLE(5); /* 6 */
         HEXTRACT_BYTE(6); /* 5 */
@@ -11475,7 +11738,7 @@ S_hextract(pTHX_ const NV nv, int* exponent, bool *subnormal,
 #endif /* #if defined(USE_LONG_DOUBLE) && (NVSIZE > DOUBLESIZE) #else */
 
 #ifdef HEXTRACT_FALLBACK
-       HEXTRACT_GET_SUBNORMAL(nv);
+        HEXTRACT_GET_SUBNORMAL(nv);
 #  undef HEXTRACT_HAS_TOP_NYBBLE /* Meaningless, but consistent. */
         /* The fallback is used for the double-double format, and
          * for unknown long double formats, and for unknown double
@@ -11804,6 +12067,8 @@ S_format_hexfp(pTHX_ char * const buf, const STRLEN bufsize, const char c,
 
     if (hexradix) {
 #ifndef USE_LOCALE_NUMERIC
+        PERL_UNUSED_ARG(in_lc_numeric);
+
         *p++ = '.';
 #else
         if (in_lc_numeric) {
@@ -11875,29 +12140,30 @@ S_format_hexfp(pTHX_ char * const buf, const STRLEN bufsize, const char c,
     return elen;
 }
 
-
 /*
 =for apidoc sv_vcatpvfn
+=for apidoc_item sv_vcatpvfn_flags
 
-=for apidoc sv_vcatpvfn_flags
-
-Processes its arguments like C<vsprintf> and appends the formatted output
-to an SV.  Uses an array of SVs if the C-style variable argument list is
-missing (C<NULL>). Argument reordering (using format specifiers like C<%2$d>
-or C<%*2$d>) is supported only when using an array of SVs; using a C-style
+These process their arguments like C<L<vsprintf(3)>> and append the formatted output
+to an SV.  They use an array of SVs if the C-style variable argument list is
+missing (C<NULL>). Argument reordering (using format specifiers like C<%2$d> or
+C<%*2$d>) is supported only when using an array of SVs; using a C-style
 C<va_list> argument list with a format string that uses argument reordering
 will yield an exception.
 
-When running with taint checks enabled, indicates via
-C<maybe_tainted> if results are untrustworthy (often due to the use of
-locales).
-
-If called as C<sv_vcatpvfn> or flags has the C<SV_GMAGIC> bit set, calls get magic.
+When running with taint checks enabled, they indicate via C<maybe_tainted> if
+results are untrustworthy (often due to the use of locales).
 
-It assumes that pat has the same utf8-ness as sv.  It's the caller's
+They assume that C<pat> has the same utf8-ness as C<sv>.  It's the caller's
 responsibility to ensure that this is so.
 
-Usually used via one of its frontends C<sv_vcatpvf> and C<sv_vcatpvf_mg>.
+They differ in that C<sv_vcatpvfn_flags> has a C<flags> parameter in which you
+can set or clear the C<SV_GMAGIC> and/or S<SV_SMAGIC> flags, to specify which
+magic to handle or not handle; whereas plain C<sv_vcatpvfn> always specifies
+both 'get' and 'set' magic.
+
+They are usually used via one of the frontends L</C<sv_vcatpvf>> and
+L</C<sv_vcatpvf_mg>>.
 
 =cut
 */
@@ -11926,6 +12192,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
 #endif
     /* we never change this unless USE_LOCALE_NUMERIC */
     bool in_lc_numeric = FALSE;
+    SV *tmp_sv = NULL;
 
     PERL_ARGS_ASSERT_SV_VCATPVFN_FLAGS;
     PERL_UNUSED_ARG(maybe_tainted);
@@ -11949,7 +12216,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
      */
 
     if (patlen == 0 && (args || sv_count == 0))
-       return;
+        return;
 
     if (patlen <= 4 && pat[0] == '%' && (args || sv_count == 1)) {
 
@@ -11998,46 +12265,48 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
 
     patend = (char*)pat + patlen;
     for (fmtstart = pat; fmtstart < patend; fmtstart = q) {
-       char intsize     = 0;         /* size qualifier in "%hi..." etc */
-       bool alt         = FALSE;     /* has      "%#..."    */
-       bool left        = FALSE;     /* has      "%-..."    */
-       bool fill        = FALSE;     /* has      "%0..."    */
-       char plus        = 0;         /* has      "%+..."    */
-       STRLEN width     = 0;         /* value of "%NNN..."  */
-       bool has_precis  = FALSE;     /* has      "%.NNN..." */
-       STRLEN precis    = 0;         /* value of "%.NNN..." */
-       int base         = 0;         /* base to print in, e.g. 8 for %o */
-       UV uv            = 0;         /* the value to print of int-ish args */
-
-       bool vectorize   = FALSE;     /* has      "%v..."    */
-       bool vec_utf8    = FALSE;     /* SvUTF8(vec arg)     */
-       const U8 *vecstr = NULL;      /* SvPVX(vec arg)      */
-       STRLEN veclen    = 0;         /* SvCUR(vec arg)      */
-       const char *dotstr = NULL;    /* separator string for %v */
-       STRLEN dotstrlen;             /* length of separator string for %v */
-
-       Size_t efix      = 0;         /* explicit format parameter index */
-       const Size_t osvix  = svix;   /* original index in case of bad fmt */
-
-       SV *argsv        = NULL;
-       bool is_utf8     = FALSE;     /* is this item utf8?   */
+        char intsize     = 0;         /* size qualifier in "%hi..." etc */
+        bool alt         = FALSE;     /* has      "%#..."    */
+        bool left        = FALSE;     /* has      "%-..."    */
+        bool fill        = FALSE;     /* has      "%0..."    */
+        char plus        = 0;         /* has      "%+..."    */
+        STRLEN width     = 0;         /* value of "%NNN..."  */
+        bool has_precis  = FALSE;     /* has      "%.NNN..." */
+        STRLEN precis    = 0;         /* value of "%.NNN..." */
+        int base         = 0;         /* base to print in, e.g. 8 for %o */
+        UV uv            = 0;         /* the value to print of int-ish args */
+
+        bool vectorize   = FALSE;     /* has      "%v..."    */
+        bool vec_utf8    = FALSE;     /* SvUTF8(vec arg)     */
+        const U8 *vecstr = NULL;      /* SvPVX(vec arg)      */
+        STRLEN veclen    = 0;         /* SvCUR(vec arg)      */
+        const char *dotstr = NULL;    /* separator string for %v */
+        STRLEN dotstrlen;             /* length of separator string for %v */
+
+        Size_t efix      = 0;         /* explicit format parameter index */
+        const Size_t osvix  = svix;   /* original index in case of bad fmt */
+
+        SV *argsv        = NULL;
+        bool is_utf8     = FALSE;     /* is this item utf8?   */
         bool arg_missing = FALSE;     /* give "Missing argument" warning */
-       char esignbuf[4];             /* holds sign prefix, e.g. "-0x" */
-       STRLEN esignlen  = 0;         /* length of e.g. "-0x" */
-       STRLEN zeros     = 0;         /* how many '0' to prepend */
+        char esignbuf[4];             /* holds sign prefix, e.g. "-0x" */
+        STRLEN esignlen  = 0;         /* length of e.g. "-0x" */
+        STRLEN zeros     = 0;         /* how many '0' to prepend */
 
-       const char *eptr = NULL;      /* the address of the element string */
-       STRLEN elen      = 0;         /* the length  of the element string */
+        const char *eptr = NULL;      /* the address of the element string */
+        STRLEN elen      = 0;         /* the length  of the element string */
 
-       char c;                       /* the actual format ('d', s' etc) */
+        char c;                       /* the actual format ('d', s' etc) */
 
+        bool escape_it   = FALSE;     /* if this is a string should we quote and escape it? */
 
-       /* echo everything up to the next format specification */
-       for (q = fmtstart; q < patend && *q != '%'; ++q)
+
+        /* echo everything up to the next format specification */
+        for (q = fmtstart; q < patend && *q != '%'; ++q)
             {};
 
-       if (q > fmtstart) {
-           if (has_utf8 && !pat_utf8) {
+        if (q > fmtstart) {
+            if (has_utf8 && !pat_utf8) {
                 /* upgrade and copy the bytes of fmtstart..q-1 to utf8 on
                  * the fly */
                 const char *p;
@@ -12055,73 +12324,73 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 *dst = '\0';
                 SvCUR_set(sv, need - 1);
             }
-           else
+            else
                 S_sv_catpvn_simple(aTHX_ sv, fmtstart, q - fmtstart);
-       }
-       if (q++ >= patend)
-           break;
+        }
+        if (q++ >= patend)
+            break;
 
-       fmtstart = q; /* fmtstart is char following the '%' */
+        fmtstart = q; /* fmtstart is char following the '%' */
 
 /*
     We allow format specification elements in this order:
-       \d+\$              explicit format parameter index
-       [-+ 0#]+           flags
-       v|\*(\d+\$)?v      vector with optional (optionally specified) arg
-       0                  flag (as above): repeated to allow "v02"     
-       \d+|\*(\d+\$)?     width using optional (optionally specified) arg
-       \.(\d*|\*(\d+\$)?) precision using optional (optionally specified) arg
-       [hlqLV]            size
+        \d+\$              explicit format parameter index
+        [-+ 0#]+           flags
+        v|\*(\d+\$)?v      vector with optional (optionally specified) arg
+        0                 flag (as above): repeated to allow "v02"
+        \d+|\*(\d+\$)?     width using optional (optionally specified) arg
+        \.(\d*|\*(\d+\$)?) precision using optional (optionally specified) arg
+        [hlqLV]            size
     [%bcdefginopsuxDFOUX] format (mandatory)
 */
 
-       if (inRANGE(*q, '1', '9')) {
+        if (inRANGE(*q, '1', '9')) {
             width = expect_number(&q);
-           if (*q == '$') {
+            if (*q == '$') {
                 if (args)
                     Perl_croak_nocontext(
                         "Cannot yet reorder sv_vcatpvfn() arguments from va_list");
-               ++q;
-               efix = (Size_t)width;
+                ++q;
+                efix = (Size_t)width;
                 width = 0;
                 no_redundant_warning = TRUE;
-           } else {
-               goto gotwidth;
-           }
-       }
-
-       /* FLAGS */
-
-       while (*q) {
-           switch (*q) {
-           case ' ':
-           case '+':
-               if (plus == '+' && *q == ' ') /* '+' over ' ' */
-                   q++;
-               else
-                   plus = *q++;
-               continue;
-
-           case '-':
-               left = TRUE;
-               q++;
-               continue;
-
-           case '0':
-               fill = TRUE;
+            } else {
+                goto gotwidth;
+            }
+        }
+
+        /* FLAGS */
+
+        while (*q) {
+            switch (*q) {
+            case ' ':
+            case '+':
+                if (plus == '+' && *q == ' ') /* '+' over ' ' */
+                    q++;
+                else
+                    plus = *q++;
+                continue;
+
+            case '-':
+                left = TRUE;
+                q++;
+                continue;
+
+            case '0':
+                fill = TRUE;
                 q++;
-               continue;
+                continue;
 
-           case '#':
-               alt = TRUE;
-               q++;
-               continue;
+            case '#':
+                alt = TRUE;
+                q++;
+                continue;
 
-           default:
-               break;
-           }
-           break;
-       }
+            default:
+                break;
+            }
+            break;
+        }
 
       /* at this point we can expect one of:
        *
@@ -12140,18 +12409,18 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
        */
 
       tryasterisk:
-       if (*q == '*') {
+        if (*q == '*') {
             STRLEN ix; /* explicit width/vector separator index */
-           q++;
+            q++;
             if (inRANGE(*q, '1', '9')) {
                 ix = expect_number(&q);
-               if (*q++ == '$') {
+                if (*q++ == '$') {
                     if (args)
                         Perl_croak_nocontext(
                             "Cannot yet reorder sv_vcatpvfn() arguments from va_list");
                     no_redundant_warning = TRUE;
                 } else
-                   goto unknown;
+                    goto unknown;
             }
             else
                 ix = 0;
@@ -12199,35 +12468,35 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 width = S_sprintf_arg_num_val(aTHX_ args, i, width_sv, &left);
             }
         }
-       else if (*q == 'v') {
-           q++;
-           if (vectorize)
-               goto unknown;
-           vectorize = TRUE;
+        else if (*q == 'v') {
+            q++;
+            if (vectorize)
+                goto unknown;
+            vectorize = TRUE;
             dotstr = ".";
             dotstrlen = 1;
             goto tryasterisk;
 
         }
-       else {
+        else {
         /* explicit width? */
-           if(*q == '0') {
-               fill = TRUE;
+            if(*q == '0') {
+                fill = TRUE;
                 q++;
             }
             if (inRANGE(*q, '1', '9'))
                 width = expect_number(&q);
-       }
+        }
 
       gotwidth:
 
-       /* PRECISION */
+        /* PRECISION */
 
-       if (*q == '.') {
-           q++;
-           if (*q == '*') {
+        if (*q == '.') {
+            q++;
+            if (*q == '*') {
                 STRLEN ix; /* explicit precision index */
-               q++;
+                q++;
                 if (inRANGE(*q, '1', '9')) {
                     ix = expect_number(&q);
                     if (*q++ == '$') {
@@ -12259,8 +12528,8 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                     if (!has_precis)
                         precis = 0;
                 }
-           }
-           else {
+            }
+            else {
                 /* although it doesn't seem documented, this code has long
                  * behaved so that:
                  *   no digits following the '.' is treated like '.0'
@@ -12271,89 +12540,88 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 while (*q == '0')
                     q++;
                 precis = inRANGE(*q, '1', '9') ? expect_number(&q) : 0;
-               has_precis = TRUE;
-           }
-       }
+                has_precis = TRUE;
+            }
+        }
 
-       /* SIZE */
+        /* SIZE */
 
-       switch (*q) {
+        switch (*q) {
 #ifdef WIN32
-       case 'I':                       /* Ix, I32x, and I64x */
+        case 'I':                      /* Ix, I32x, and I64x */
 #  ifdef USE_64_BIT_INT
-           if (q[1] == '6' && q[2] == '4') {
-               q += 3;
-               intsize = 'q';
-               break;
-           }
+            if (q[1] == '6' && q[2] == '4') {
+                q += 3;
+                intsize = 'q';
+                break;
+            }
 #  endif
-           if (q[1] == '3' && q[2] == '2') {
-               q += 3;
-               break;
-           }
+            if (q[1] == '3' && q[2] == '2') {
+                q += 3;
+                break;
+            }
 #  ifdef USE_64_BIT_INT
-           intsize = 'q';
+            intsize = 'q';
 #  endif
-           q++;
-           break;
+            q++;
+            break;
 #endif
 #if (IVSIZE >= 8 || defined(HAS_LONG_DOUBLE)) || \
     (IVSIZE == 4 && !defined(HAS_LONG_DOUBLE))
-       case 'L':                       /* Ld */
-           /* FALLTHROUGH */
-#  ifdef USE_QUADMATH
-        case 'Q':
-           /* FALLTHROUGH */
-#  endif
+        case 'L':                      /* Ld */
+            /* FALLTHROUGH */
 #  if IVSIZE >= 8
-       case 'q':                       /* qd */
+        case 'q':                      /* qd */
 #  endif
-           intsize = 'q';
-           q++;
-           break;
+            intsize = 'q';
+            q++;
+            break;
 #endif
-       case 'l':
-           ++q;
+        case 'l':
+            ++q;
 #if (IVSIZE >= 8 || defined(HAS_LONG_DOUBLE)) || \
     (IVSIZE == 4 && !defined(HAS_LONG_DOUBLE))
-           if (*q == 'l') {    /* lld, llf */
-               intsize = 'q';
-               ++q;
-           }
-           else
+            if (*q == 'l') {   /* lld, llf */
+                intsize = 'q';
+                ++q;
+            }
+            else
 #endif
-               intsize = 'l';
-           break;
-       case 'h':
-           if (*++q == 'h') {  /* hhd, hhu */
-               intsize = 'c';
-               ++q;
-           }
-           else
-               intsize = 'h';
-           break;
-       case 'V':
-       case 'z':
-       case 't':
+                intsize = 'l';
+            break;
+        case 'h':
+            if (*++q == 'h') { /* hhd, hhu */
+                intsize = 'c';
+                ++q;
+            }
+            else
+                intsize = 'h';
+            break;
+#ifdef USE_QUADMATH
+        case 'Q':
+#endif
+        case 'V':
+        case 'z':
+        case 't':
         case 'j':
-           intsize = *q++;
-           break;
-       }
+            intsize = *q++;
+            break;
+        }
 
-       /* CONVERSION */
+        /* CONVERSION */
 
-       c = *q++; /* c now holds the conversion type */
+        c = *q++; /* c now holds the conversion type */
 
         /* '%' doesn't have an arg, so skip arg processing */
-       if (c == '%') {
-           eptr = q - 1;
-           elen = 1;
-           if (vectorize)
-               goto unknown;
-           goto string;
-       }
-
-       if (vectorize && !strchr("BbDdiOouUXx", c))
+        if (c == '%') {
+            eptr = q - 1;
+            elen = 1;
+            if (vectorize)
+                goto unknown;
+            goto string;
+        }
+
+        if (vectorize && !memCHRs("BbDdiOouUXx", c))
             goto unknown;
 
         /* get next arg (individual branches do their own va_arg()
@@ -12363,59 +12631,99 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
             efix = efix ? efix - 1 : svix++;
             argsv = efix < sv_count ? svargs[efix]
                                  : (arg_missing = TRUE, &PL_sv_no);
-       }
+        }
+
+
+        switch (c) {
+
+            /* STRINGS */
+
+        case 's':
+            if (args) {
+                eptr = va_arg(*args, char*);
+                if (eptr)
+                    if (has_precis)
+                        elen = my_strnlen(eptr, precis);
+                    else
+                        elen = strlen(eptr);
+                else {
+                    eptr = (char *)nullstr;
+                    elen = sizeof nullstr - 1;
+                }
+            }
+            else {
+                eptr = SvPV_const(argsv, elen);
+                if (DO_UTF8(argsv)) {
+                    STRLEN old_precis = precis;
+                    if (has_precis && precis < elen) {
+                        STRLEN ulen = sv_or_pv_len_utf8(argsv, eptr, elen);
+                        STRLEN p = precis > ulen ? ulen : precis;
+                        precis = sv_or_pv_pos_u2b(argsv, eptr, p, 0);
+                                                        /* sticks at end */
+                    }
+                    if (width) { /* fudge width (can't fudge elen) */
+                        if (has_precis && precis < elen)
+                            width += precis - old_precis;
+                        else
+                            width +=
+                                elen - sv_or_pv_len_utf8(argsv,eptr,elen);
+                    }
+                    is_utf8 = TRUE;
+                }
+            }
 
+        string:
+            if (escape_it) {
+                U32 flags = PERL_PV_PRETTY_QUOTEDPREFIX;
+                if (is_utf8)
+                    flags |= PERL_PV_ESCAPE_UNI;
+
+                if (!tmp_sv) {
+                    /* "blah"... where blah might be made up
+                     * of characters like \x{1234} */
+                    tmp_sv = newSV(1 + (PERL_QUOTEDPREFIX_LEN * 8) + 1 + 3);
+                    sv_2mortal(tmp_sv);
+                }
+                pv_pretty(tmp_sv, eptr, elen, PERL_QUOTEDPREFIX_LEN,
+                            NULL, NULL, flags);
+                eptr = SvPV_const(tmp_sv, elen);
+            }
+            if (has_precis && precis < elen)
+                elen = precis;
+            break;
 
-       switch (c) {
+            /* INTEGERS */
 
-           /* STRINGS */
+        case 'p':
 
-       case 's':
-           if (args) {
-               eptr = va_arg(*args, char*);
-               if (eptr)
-                    if (has_precis)
-                        elen = my_strnlen(eptr, precis);
-                    else
-                        elen = strlen(eptr);
-               else {
-                   eptr = (char *)nullstr;
-                   elen = sizeof nullstr - 1;
-               }
-           }
-           else {
-               eptr = SvPV_const(argsv, elen);
-               if (DO_UTF8(argsv)) {
-                   STRLEN old_precis = precis;
-                   if (has_precis && precis < elen) {
-                       STRLEN ulen = sv_or_pv_len_utf8(argsv, eptr, elen);
-                       STRLEN p = precis > ulen ? ulen : precis;
-                       precis = sv_or_pv_pos_u2b(argsv, eptr, p, 0);
-                                                       /* sticks at end */
-                   }
-                   if (width) { /* fudge width (can't fudge elen) */
-                       if (has_precis && precis < elen)
-                           width += precis - old_precis;
-                       else
-                           width +=
-                               elen - sv_or_pv_len_utf8(argsv,eptr,elen);
-                   }
-                   is_utf8 = TRUE;
-               }
-           }
-
-       string:
-           if (has_precis && precis < elen)
-               elen = precis;
-           break;
-
-           /* INTEGERS */
-
-       case 'p':
-           if (alt)
-               goto unknown;
-
-            /* %p extensions:
+            /* BEGIN NOTE
+             *
+             * We want to extend the C level sprintf format API with
+             * custom formats for specific types (eg SV*) and behavior.
+             * However some C compilers are "sprintf aware" and will
+             * throw compile time exceptions when an illegal sprintf is
+             * encountered, so we can't just add new format letters.
+             *
+             * However it turns out the length argument to the %p format
+             * is more or less useless (the size of a pointer does not
+             * change over time) and is not really used in the C level
+             * code. Accordingly we can map our special behavior to
+             * specific "length" options to the %p format. We hide these
+             * mappings behind defines anyway, so nobody needs to know
+             * that HEKf is actually %2p. This keeps the C compiler
+             * happy while allowing us to add new formats.
+             *
+             * Note the existing logic for which number is used for what
+             * is torturous. All negative values are used for SVf, and
+             * non-negative values have arbitrary meanings with no
+             * structure to them. This may change in the future.
+             *
+             * NEVER use the raw %p values directly. Always use the define
+             * as the underlying mapping may change in the future.
+             *
+             * END NOTE
+             *
+             * %p extensions:
              *
              * "%...p" is normally treated like "%...x", except that the
              * number to print is the SV's address (or a pointer address
@@ -12425,23 +12733,44 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
              * extensions. These are currently:
              *
              * %-p       (SVf)  Like %s, but gets the string from an SV*
-             *                  arg rather than a char* arg.
+             *                  arg rather than a char* arg. Use C<SVfARG()>
+             *                  to set up the argument properly.
              *                  (This was previously %_).
              *
-             * %-<num>p         Ditto but like %.<num>s (i.e. num is max width)
+             * %-<num>p         Ditto but like %.<num>s (i.e. num is max
+             *                  width), there is no escaped and quoted version
+             *                  of this.
+             *
+             * %1p       (PVf_QUOTEDPREFIX). Like raw %s, but it is escaped
+             *                  and quoted.
+             *
+             * %5p       (SVf_QUOTEDPREFIX) Like SVf, but length restricted,
+             *                  escaped and quoted with pv_pretty. Intended
+             *                  for error messages.
              *
              * %2p       (HEKf) Like %s, but using the key string in a HEK
+             * %7p       (HEKf_QUOTEDPREFIX) ... but escaped and quoted.
              *
              * %3p       (HEKf256) Ditto but like %.256s
+             * %8p       (HEKf256_QUOTEDPREFIX) ... but escaped and quoted
              *
              * %d%lu%4p  (UTF8f) A utf8 string. Consumes 3 args:
              *                       (cBOOL(utf8), len, string_buf).
              *                   It's handled by the "case 'd'" branch
              *                   rather than here.
+             * %d%lu%9p  (UTF8f_QUOTEDPREFIX) .. but escaped and quoted.
+             *
+             * %6p       (HvNAMEf) Like %s, but using the HvNAME() and HvNAMELEN()
+             * %10p      (HvNAMEf_QUOTEDPREFIX) ... but escaped and quoted
              *
-             * %<num>p   where num is 1 or > 4: reserved for future
+             * %<num>p   where num is > 9: reserved for future
              *           extensions. Warns, but then is treated as a
              *           general %p (print hex address) format.
+             *
+             * NOTE: If you add a new magic %p value you will
+             * need to update F<t/porting/diag.t> to be aware of it
+             * on top of adding the various defines and etc. Do not
+             * forget to add it to F<pod/perlguts.pod> as well.
              */
 
             if (   args
@@ -12453,10 +12782,12 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 && q[-2] != '*'
                 && q[-2] != '$'
             ) {
-                if (left) {                    /* %-p (SVf), %-NNNp */
-                    if (width) {
+                if (left || width == 5) {                /* %-p (SVf), %-NNNp, %5p */
+                    if (left && width) {
                         precis = width;
                         has_precis = TRUE;
+                    } else if (width == 5) {
+                        escape_it = TRUE;
                     }
                     argsv = MUTABLE_SV(va_arg(*args, void*));
                     eptr = SvPV_const(argsv, elen);
@@ -12465,7 +12796,9 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                     width = 0;
                     goto string;
                 }
-                else if (width == 2 || width == 3) {   /* HEKf, HEKf256 */
+                else if (width == 2 || width == 3 ||
+                         width == 7 || width == 8)
+                {        /* HEKf, HEKf256, HEKf_QUOTEDPREFIX, HEKf256_QUOTEDPREFIX */
                     HEK * const hek = va_arg(*args, HEK *);
                     eptr = HEK_KEY(hek);
                     elen = HEK_LEN(hek);
@@ -12475,10 +12808,31 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                         precis = 256;
                         has_precis = TRUE;
                     }
+                    if (width > 5)
+                        escape_it = TRUE;
+                    width = 0;
+                    goto string;
+                }
+                else if (width == 1) {
+                    eptr = va_arg(*args,char *);
+                    elen = strlen(eptr);
+                    escape_it = TRUE;
+                    width = 0;
+                    goto string;
+                }
+                else if (width == 6 || width == 10) {
+                    HV *hv = va_arg(*args, HV *);
+                    eptr = HvNAME(hv);
+                    elen = HvNAMELEN(hv);
+                    if (HvNAMEUTF8(hv))
+                        is_utf8 = TRUE;
+                    if (width == 10)
+                        escape_it = TRUE;
                     width = 0;
                     goto string;
                 }
                 else if (width) {
+                    /* note width=4 or width=9 is handled under %d */
                     Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),
                          "internal %%<num>p might conflict with future printf extensions");
                 }
@@ -12486,16 +12840,17 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
 
             /* treat as normal %...p */
 
-           uv = PTR2UV(args ? va_arg(*args, void*) : argsv);
-           base = 16;
-           goto do_integer;
+            uv = PTR2UV(args ? va_arg(*args, void*) : argsv);
+            base = 16;
+            c = 'x';    /* in case the format string contains '#' */
+            goto do_integer;
 
-       case 'c':
+        case 'c':
             /* Ignore any size specifiers, since they're not documented as
              * being allowed for %c (ideally we should warn on e.g. '%hc').
              * Setting a default intsize, along with a positive
              * (which signals unsigned) base, causes, for C-ish use, the
-             * va_arg to be interpreted as as unsigned int, when it's
+             * va_arg to be interpreted as an unsigned int, when it's
              * actually signed, which will convert -ve values to high +ve
              * values. Note that unlike the libc %c, values > 255 will
              * convert to high unicode points rather than being truncated
@@ -12506,84 +12861,90 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
             base = 1; /* special value that indicates we're doing a 'c' */
             goto get_int_arg_val;
 
-       case 'D':
+        case 'D':
 #ifdef IV_IS_QUAD
-           intsize = 'q';
+            intsize = 'q';
 #else
-           intsize = 'l';
+            intsize = 'l';
 #endif
             base = -10;
             goto get_int_arg_val;
 
-       case 'd':
+        case 'd':
             /* probably just a plain %d, but it might be the start of the
              * special UTF8f format, which usually looks something like
-             * "%d%lu%4p" (the lu may vary by platform)
+             * "%d%lu%4p" (the lu may vary by platform) or
+             * "%d%lu%9p" for an escaped version.
              */
             assert((UTF8f)[0] == 'd');
             assert((UTF8f)[1] == '%');
 
-            if (   args              /* UTF8f only valid for C-ish sprintf */
+             if (   args              /* UTF8f only valid for C-ish sprintf */
                  && q == fmtstart + 1 /* plain %d, not %....d */
                  && patend >= fmtstart + sizeof(UTF8f) - 1 /* long enough */
                  && *q == '%'
-                 && strnEQ(q + 1, UTF8f + 2, sizeof(UTF8f) - 3))
+                 && strnEQ(q + 1, (UTF8f) + 2, sizeof(UTF8f) - 5)
+                 && q[sizeof(UTF8f)-3] == 'p'
+                 && (q[sizeof(UTF8f)-4] == '4' ||
+                     q[sizeof(UTF8f)-4] == '9'))
             {
-               /* The argument has already gone through cBOOL, so the cast
-                  is safe. */
-               is_utf8 = (bool)va_arg(*args, int);
-               elen = va_arg(*args, UV);
+                /* The argument has already gone through cBOOL, so the cast
+                   is safe. */
+                if (q[sizeof(UTF8f)-4] == '9')
+                    escape_it = TRUE;
+                is_utf8 = (bool)va_arg(*args, int);
+                elen = va_arg(*args, UV);
                 /* if utf8 length is larger than 0x7ffff..., then it might
                  * have been a signed value that wrapped */
                 if (elen  > ((~(STRLEN)0) >> 1)) {
                     assert(0); /* in DEBUGGING build we want to crash */
                     elen = 0; /* otherwise we want to treat this as an empty string */
                 }
-               eptr = va_arg(*args, char *);
-               q += sizeof(UTF8f) - 2;
-               goto string;
-           }
+                eptr = va_arg(*args, char *);
+                q += sizeof(UTF8f) - 2;
+                goto string;
+            }
 
-           /* FALLTHROUGH */
-       case 'i':
+            /* FALLTHROUGH */
+        case 'i':
             base = -10;
             goto get_int_arg_val;
 
-       case 'U':
+        case 'U':
 #ifdef IV_IS_QUAD
-           intsize = 'q';
+            intsize = 'q';
 #else
-           intsize = 'l';
+            intsize = 'l';
 #endif
-           /* FALLTHROUGH */
-       case 'u':
-           base = 10;
-           goto get_int_arg_val;
+            /* FALLTHROUGH */
+        case 'u':
+            base = 10;
+            goto get_int_arg_val;
 
-       case 'B':
-       case 'b':
-           base = 2;
-           goto get_int_arg_val;
+        case 'B':
+        case 'b':
+            base = 2;
+            goto get_int_arg_val;
 
-       case 'O':
+        case 'O':
 #ifdef IV_IS_QUAD
-           intsize = 'q';
+            intsize = 'q';
 #else
-           intsize = 'l';
+            intsize = 'l';
 #endif
-           /* FALLTHROUGH */
-       case 'o':
-           base = 8;
-           goto get_int_arg_val;
+            /* FALLTHROUGH */
+        case 'o':
+            base = 8;
+            goto get_int_arg_val;
 
-       case 'X':
-       case 'x':
-           base = 16;
+        case 'X':
+        case 'x':
+            base = 16;
 
           get_int_arg_val:
 
-           if (vectorize) {
-               STRLEN ulen;
+            if (vectorize) {
+                STRLEN ulen;
                 SV *vecsv;
 
                 if (base < 0) {
@@ -12618,20 +12979,20 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
 
               /* This is the re-entry point for when we're iterating
                * over the individual characters of a vector arg */
-             vector:
-               if (!veclen)
+              vector:
+                if (!veclen)
                     goto done_valid_conversion;
-               if (vec_utf8)
-                   uv = utf8n_to_uvchr(vecstr, veclen, &ulen,
-                                       UTF8_ALLOW_ANYUV);
-               else {
-                   uv = *vecstr;
-                   ulen = 1;
-               }
-               vecstr += ulen;
-               veclen -= ulen;
-           }
-           else {
+                if (vec_utf8)
+                    uv = utf8n_to_uvchr(vecstr, veclen, &ulen,
+                                        UTF8_ALLOW_ANYUV);
+                else {
+                    uv = *vecstr;
+                    ulen = 1;
+                }
+                vecstr += ulen;
+                veclen -= ulen;
+            }
+            else {
                 /* test arg for inf/nan. This can trigger an unwanted
                  * 'str' overload, so manually force 'num' overload first
                  * if necessary */
@@ -12745,16 +13106,16 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 }
             }
 
-       do_integer:
-           {
-               char *ptr = ebuf + sizeof ebuf;
+        do_integer:
+            {
+                char *ptr = ebuf + sizeof ebuf;
                 unsigned dig;
-               zeros = 0;
+                zeros = 0;
 
-               switch (base) {
-               case 16:
+                switch (base) {
+                case 16:
                     {
-                   const char * const p =
+                    const char * const p =
                             (c == 'X') ? PL_hexdigit + 16 : PL_hexdigit;
 
                         do {
@@ -12767,26 +13128,26 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                         }
                         break;
                     }
-               case 8:
-                   do {
-                       dig = uv & 7;
-                       *--ptr = '0' + dig;
-                   } while (uv >>= 3);
-                   if (alt && *ptr != '0')
-                       *--ptr = '0';
-                   break;
-               case 2:
-                   do {
-                       dig = uv & 1;
-                       *--ptr = '0' + dig;
-                   } while (uv >>= 1);
-                   if (alt && *ptr != '0') {
-                       esignbuf[esignlen++] = '0';
-                       esignbuf[esignlen++] = c; /* 'b' or 'B' */
-                   }
-                   break;
-
-               case 1:
+                case 8:
+                    do {
+                        dig = uv & 7;
+                        *--ptr = '0' + dig;
+                    } while (uv >>= 3);
+                    if (alt && *ptr != '0')
+                        *--ptr = '0';
+                    break;
+                case 2:
+                    do {
+                        dig = uv & 1;
+                        *--ptr = '0' + dig;
+                    } while (uv >>= 1);
+                    if (alt && *ptr != '0') {
+                        esignbuf[esignlen++] = '0';
+                        esignbuf[esignlen++] = c; /* 'b' or 'B' */
+                    }
+                    break;
+
+                case 1:
                     /* special-case: base 1 indicates a 'c' format:
                      * we use the common code for extracting a uv,
                      * but handle that value differently here than
@@ -12795,7 +13156,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                          (!UVCHR_IS_INVARIANT(uv) && SvUTF8(sv)))
                         && !IN_BYTES)
                     {
-                        assert(sizeof(ebuf) >= UTF8_MAXBYTES + 1);
+                        STATIC_ASSERT_STMT(sizeof(ebuf) >= UTF8_MAXBYTES + 1);
                         eptr = ebuf;
                         elen = uvchr_to_utf8((U8*)eptr, uv) - (U8*)ebuf;
                         is_utf8 = TRUE;
@@ -12807,37 +13168,37 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                     }
                     goto string;
 
-               default:                /* it had better be ten or less */
-                   do {
-                       dig = uv % base;
-                       *--ptr = '0' + dig;
-                   } while (uv /= base);
-                   break;
-               }
-               elen = (ebuf + sizeof ebuf) - ptr;
-               eptr = ptr;
-               if (has_precis) {
-                   if (precis > elen)
-                       zeros = precis - elen;
-                   else if (precis == 0 && elen == 1 && *eptr == '0'
-                            && !(base == 8 && alt)) /* "%#.0o" prints "0" */
-                       elen = 0;
+                default:               /* it had better be ten or less */
+                    do {
+                        dig = uv % base;
+                        *--ptr = '0' + dig;
+                    } while (uv /= base);
+                    break;
+                }
+                elen = (ebuf + sizeof ebuf) - ptr;
+                eptr = ptr;
+                if (has_precis) {
+                    if (precis > elen)
+                        zeros = precis - elen;
+                    else if (precis == 0 && elen == 1 && *eptr == '0'
+                             && !(base == 8 && alt)) /* "%#.0o" prints "0" */
+                        elen = 0;
 
                     /* a precision nullifies the 0 flag. */
                     fill = FALSE;
-               }
-           }
-           break;
+                }
+            }
+            break;
 
-           /* FLOATING POINT */
+            /* FLOATING POINT */
 
-       case 'F':
-           c = 'f';            /* maybe %F isn't supported here */
-           /* FALLTHROUGH */
-       case 'e': case 'E':
-       case 'f':
-       case 'g': case 'G':
-       case 'a': case 'A':
+        case 'F':
+            c = 'f';           /* maybe %F isn't supported here */
+            /* FALLTHROUGH */
+        case 'e': case 'E':
+        case 'f':
+        case 'g': case 'G':
+        case 'a': case 'A':
 
         {
             STRLEN float_need; /* what PL_efloatsize needs to become */
@@ -12846,39 +13207,43 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
             vcatpvfn_long_double_t fv;
             NV                     nv;
 
-           /* This is evil, but floating point is even more evil */
+            /* This is evil, but floating point is even more evil */
 
-           /* for SV-style calling, we can only get NV
-              for C-style calling, we assume %f is double;
-              for simplicity we allow any of %Lf, %llf, %qf for long double
-           */
-           switch (intsize) {
-           case 'V':
+            /* for SV-style calling, we can only get NV
+               for C-style calling, we assume %f is double;
+               for simplicity we allow any of %Lf, %llf, %qf for long double
+            */
+            switch (intsize) {
+#if defined(USE_QUADMATH)
+            case 'Q':
+                break;
+#endif
+            case 'V':
 #if defined(USE_LONG_DOUBLE) || defined(USE_QUADMATH)
-               intsize = 'q';
+                intsize = 'q';
 #endif
-               break;
+                break;
 /* [perl #20339] - we should accept and ignore %lf rather than die */
-           case 'l':
-               /* FALLTHROUGH */
-           default:
+            case 'l':
+                /* FALLTHROUGH */
+            default:
 #if defined(USE_LONG_DOUBLE) || defined(USE_QUADMATH)
-               intsize = args ? 0 : 'q';
+                intsize = args ? 0 : 'q';
 #endif
-               break;
-           case 'q':
+                break;
+            case 'q':
 #if defined(HAS_LONG_DOUBLE)
-               break;
+                break;
 #else
-               /* FALLTHROUGH */
+                /* FALLTHROUGH */
 #endif
-           case 'c':
-           case 'h':
-           case 'z':
-           case 't':
-           case 'j':
-               goto unknown;
-           }
+            case 'c':
+            case 'h':
+            case 'z':
+            case 't':
+            case 'j':
+                goto unknown;
+            }
 
             /* Now we need (long double) if intsize == 'q', else (double). */
             if (args) {
@@ -12892,9 +13257,10 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                  * is when the format specifier explicitly asks so with
                  * e.g. "%Lg". */
 #ifdef USE_QUADMATH
-                fv = intsize == 'q' ?
-                    va_arg(*args, NV) : va_arg(*args, double);
-                nv = fv;
+                nv = intsize == 'Q' ? va_arg(*args, NV) :
+                    intsize == 'q' ? va_arg(*args, long double) :
+                    va_arg(*args, double);
+                fv = nv;
 #elif LONG_DOUBLESIZE > DOUBLESIZE
                 if (intsize == 'q') {
                     fv = va_arg(*args, long double);
@@ -12922,7 +13288,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
             if (Perl_isinfnan(nv)) {
                 if (c == 'c')
                     Perl_croak(aTHX_ "Cannot printf %" NVgf " with '%c'",
-                           SvNV_nomg(argsv), (int)c);
+                               nv, (int)c);
 
                 elen = S_infnan_2pv(nv, ebuf, sizeof(ebuf), plus);
                 assert(elen);
@@ -13026,7 +13392,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
 
             hexfp = FALSE;
 
-           if (isALPHA_FOLD_EQ(c, 'f')) {
+            if (isALPHA_FOLD_EQ(c, 'f')) {
                 /* Determine how many digits before the radix point
                  * might be emitted.  frexp() (or frexpl) has some
                  * unspecified behaviour for nan/inf/-inf, so lucky we've
@@ -13081,16 +13447,21 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                     assert(float_need < ((STRLEN)~0) - digits);
                     float_need += digits;
                 }
-           }
+            }
             /* special-case "%.<number>g" if it will fit in ebuf */
             else if (c == 'g'
                 && precis   /* See earlier comment about buggy Gconvert
                                when digits, aka precis, is 0  */
                 && has_precis
-                /* check, in manner not involving wrapping, that it will
-                 * fit in ebuf  */
-                && float_need < sizeof(ebuf)
+                /* check that "%.<number>g" formatting will fit in ebuf  */
                 && sizeof(ebuf) - float_need > precis
+                /* sizeof(ebuf) - float_need will have wrapped if float_need > sizeof(ebuf).     *
+                 * Therefore we should check that float_need < sizeof(ebuf). Normally, we would  *
+                 * have run this check first, but that triggers incorrect -Wformat-overflow      *
+                 * compilation warnings with some versions of gcc if Gconvert invokes sprintf(). *
+                 * ( See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89161 )                   *
+                 * So, instead, we check it next:                                                */
+                && float_need < sizeof(ebuf)
                 && !(width || left || plus || alt)
                 && !fill
                 && intsize != 'q'
@@ -13101,7 +13472,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 elen = strlen(ebuf);
                 eptr = ebuf;
                 goto float_concat;
-           }
+            }
 
 
             {
@@ -13114,8 +13485,8 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 float_need += pr;
             }
 
-           if (float_need < width)
-               float_need = width;
+            if (float_need < width)
+                float_need = width;
 
             if (float_need > INT_MAX) {
                 /* snprintf() returns an int, and we use that return value,
@@ -13124,7 +13495,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 Perl_croak(aTHX_ "Numeric format result too large");
             }
 
-           if (PL_efloatsize <= float_need) {
+            if (PL_efloatsize <= float_need) {
                 /* PL_efloatbuf should be at least 1 greater than
                  * float_need to allow a trailing \0 to be returned by
                  * snprintf().  If we need to grow, overgrow for the
@@ -13133,11 +13504,11 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 if (float_need >= ((STRLEN)~0) - extra)
                     croak_memory_wrap();
                 float_need += extra;
-               Safefree(PL_efloatbuf);
-               PL_efloatsize = float_need;
-               Newx(PL_efloatbuf, PL_efloatsize, char);
-               PL_efloatbuf[0] = '\0';
-           }
+                Safefree(PL_efloatbuf);
+                PL_efloatsize = float_need;
+                Newx(PL_efloatbuf, PL_efloatsize, char);
+                PL_efloatbuf[0] = '\0';
+            }
 
             if (UNLIKELY(hexfp)) {
                 elen = S_format_hexfp(aTHX_ PL_efloatbuf, PL_efloatsize, c,
@@ -13149,46 +13520,48 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 *--ptr = '\0';
                 *--ptr = c;
 #if defined(USE_QUADMATH)
-               if (intsize == 'q') {
-                    /* "g" -> "Qg" */
-                    *--ptr = 'Q';
-                }
+                /* always use Q here.  my_snprint() throws an exception if we
+                   fallthrough to the double/long double code, even when the
+                   format is correct, presumably to avoid any accidentally
+                   missing Q.
+                */
+                *--ptr = 'Q';
                 /* FIXME: what to do if HAS_LONG_DOUBLE but not PERL_PRIfldbl? */
 #elif defined(HAS_LONG_DOUBLE) && defined(PERL_PRIfldbl)
-               /* Note that this is HAS_LONG_DOUBLE and PERL_PRIfldbl,
-                * not USE_LONG_DOUBLE and NVff.  In other words,
-                * this needs to work without USE_LONG_DOUBLE. */
-               if (intsize == 'q') {
-                   /* Copy the one or more characters in a long double
-                    * format before the 'base' ([efgEFG]) character to
-                    * the format string. */
-                   static char const ldblf[] = PERL_PRIfldbl;
-                   char const *p = ldblf + sizeof(ldblf) - 3;
-                   while (p >= ldblf) { *--ptr = *p--; }
-               }
+                /* Note that this is HAS_LONG_DOUBLE and PERL_PRIfldbl,
+                 * not USE_LONG_DOUBLE and NVff.  In other words,
+                 * this needs to work without USE_LONG_DOUBLE. */
+                if (intsize == 'q') {
+                    /* Copy the one or more characters in a long double
+                     * format before the 'base' ([efgEFG]) character to
+                     * the format string. */
+                    static char const ldblf[] = PERL_PRIfldbl;
+                    char const *p = ldblf + sizeof(ldblf) - 3;
+                    while (p >= ldblf) { *--ptr = *p--; }
+                }
 #endif
-               if (has_precis) {
-                   base = precis;
-                   do { *--ptr = '0' + (base % 10); } while (base /= 10);
-                   *--ptr = '.';
-               }
-               if (width) {
-                   base = width;
-                   do { *--ptr = '0' + (base % 10); } while (base /= 10);
-               }
-               if (fill)
-                   *--ptr = '0';
-               if (left)
-                   *--ptr = '-';
-               if (plus)
-                   *--ptr = plus;
-               if (alt)
-                   *--ptr = '#';
-               *--ptr = '%';
-
-               /* No taint.  Otherwise we are in the strange situation
-                * where printf() taints but print($float) doesn't.
-                * --jhi */
+                if (has_precis) {
+                    base = precis;
+                    do { *--ptr = '0' + (base % 10); } while (base /= 10);
+                    *--ptr = '.';
+                }
+                if (width) {
+                    base = width;
+                    do { *--ptr = '0' + (base % 10); } while (base /= 10);
+                }
+                if (fill)
+                    *--ptr = '0';
+                if (left)
+                    *--ptr = '-';
+                if (plus)
+                    *--ptr = plus;
+                if (alt)
+                    *--ptr = '#';
+                *--ptr = '%';
+
+                /* No taint.  Otherwise we are in the strange situation
+                 * where printf() taints but print($float) doesn't.
+                 * --jhi */
 
                 /* hopefully the above makes ptr a very constrained format
                  * that is safe to use, even though it's not literal */
@@ -13217,11 +13590,11 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 );
 #endif
                 GCC_DIAG_RESTORE_STMT;
-           }
+            }
 
-           eptr = PL_efloatbuf;
+            eptr = PL_efloatbuf;
 
-         float_concat:
+          float_concat:
 
             /* Since floating-point formats do their own formatting and
              * padding, we skip the main block of code at the end of this
@@ -13238,9 +13611,9 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
             goto done_valid_conversion;
         }
 
-           /* SPECIAL */
+            /* SPECIAL */
 
-       case 'n':
+        case 'n':
             {
                 STRLEN len;
                 /* XXX ideally we should warn if any flags etc have been
@@ -13283,65 +13656,64 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 goto done_valid_conversion;
             }
 
-           /* UNKNOWN */
+            /* UNKNOWN */
 
-       default:
+        default:
       unknown:
-           if (!args
-               && (PL_op->op_type == OP_PRTF || PL_op->op_type == OP_SPRINTF)
-               && ckWARN(WARN_PRINTF))
-           {
-               SV * const msg = sv_newmortal();
-               Perl_sv_setpvf(aTHX_ msg, "Invalid conversion in %sprintf: ",
-                         (PL_op->op_type == OP_PRTF) ? "" : "s");
-               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_nomg(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 */
-           }
-
-           /* mangled format: output the '%', then continue from the
+            if (!args
+                && (PL_op->op_type == OP_PRTF || PL_op->op_type == OP_SPRINTF)
+                && ckWARN(WARN_PRINTF))
+            {
+                SV * const msg = sv_newmortal();
+                Perl_sv_setpvf(aTHX_ msg, "Invalid conversion in %sprintf: ",
+                          (PL_op->op_type == OP_PRTF) ? "" : "s");
+                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_nomg(msg, f, 1);
+                        } else {
+                            Perl_sv_catpvf(aTHX_ msg, "\\%03o", (U8) *f);
+                        }
+                    }
+                    sv_catpvs(msg, "\"");
+                } else {
+                    sv_catpvs(msg, "end of string");
+                }
+                Perl_warner(aTHX_ packWARN(WARN_PRINTF), "%" SVf, SVfARG(msg)); /* yes, this is reentrant */
+            }
+
+            /* mangled format: output the '%', then continue from the
              * character following that */
             sv_catpvn_nomg(sv, fmtstart-1, 1);
             q = fmtstart;
-           svix = osvix;
+            svix = osvix;
             /* Any "redundant arg" warning from now onwards will probably
              * just be misleading, so don't bother. */
             no_redundant_warning = TRUE;
-           continue;   /* not "break" */
-       }
-
-       if (is_utf8 != has_utf8) {
-           if (is_utf8) {
-               if (SvCUR(sv))
-                   sv_utf8_upgrade(sv);
-           }
-           else {
-               const STRLEN old_elen = elen;
-               SV * const nsv = newSVpvn_flags(eptr, elen, SVs_TEMP);
-               sv_utf8_upgrade(nsv);
-               eptr = SvPVX_const(nsv);
-               elen = SvCUR(nsv);
-
-               if (width) { /* fudge width (can't fudge elen) */
-                   width += elen - old_elen;
-               }
-               is_utf8 = TRUE;
-           }
-       }
+            continue;  /* not "break" */
+        }
+
+        if (is_utf8 != has_utf8) {
+            if (is_utf8) {
+                if (SvCUR(sv))
+                    sv_utf8_upgrade(sv);
+            }
+            else {
+                const STRLEN old_elen = elen;
+                SV * const nsv = newSVpvn_flags(eptr, elen, SVs_TEMP);
+                sv_utf8_upgrade(nsv);
+                eptr = SvPVX_const(nsv);
+                elen = SvCUR(nsv);
+
+                if (width) { /* fudge width (can't fudge elen) */
+                    width += elen - old_elen;
+                }
+                is_utf8 = TRUE;
+            }
+        }
 
 
         /* append esignbuf, filler, zeros, eptr and dotstr to sv */
@@ -13414,14 +13786,14 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
                 SvUTF8_on(sv);
         }
 
-       if (vectorize && veclen) {
+        if (vectorize && veclen) {
             /* we append the vector separator separately since %v isn't
              * very common: don't slow down the general case by adding
              * dotstrlen to need etc */
             sv_catpvn_nomg(sv, dotstr, dotstrlen);
             esignlen = 0;
             goto vector; /* do next iteration */
-       }
+        }
 
       done_valid_conversion:
 
@@ -13433,8 +13805,8 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
      * do we have things left on the stack that we didn't use?
      */
     if (!no_redundant_warning && sv_count >= svix + 1 && ckWARN(WARN_REDUNDANT)) {
-       Perl_warner(aTHX_ packWARN(WARN_REDUNDANT), "Redundant argument in %s",
-               PL_op ? OP_DESC(PL_op) : "sv_vcatpvfn()");
+        Perl_warner(aTHX_ packWARN(WARN_REDUNDANT), "Redundant argument in %s",
+                PL_op ? OP_DESC(PL_op) : "sv_vcatpvfn()");
     }
 
     if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
@@ -13449,7 +13821,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
 
 /* =========================================================================
 
-=head1 Cloning an interpreter
+=for apidoc_section $embedding
 
 =cut
 
@@ -13472,21 +13844,6 @@ ptr_table_* functions.
 #endif
 
 
-/* Certain cases in Perl_ss_dup have been merged, by relying on the fact
-   that currently av_dup, gv_dup and hv_dup are the same as sv_dup.
-   If this changes, please unmerge ss_dup.
-   Likewise, sv_dup_inc_multiple() relies on this fact.  */
-#define sv_dup_inc_NN(s,t)     SvREFCNT_inc_NN(sv_dup_inc(s,t))
-#define av_dup(s,t)    MUTABLE_AV(sv_dup((const SV *)s,t))
-#define av_dup_inc(s,t)        MUTABLE_AV(sv_dup_inc((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(sv_dup_inc((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(sv_dup_inc((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(sv_dup_inc((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(sv_dup_inc((const SV *)s,t))
 #define SAVEPV(p)      ((p) ? savepv(p) : NULL)
 #define SAVEPVN(p,n)   ((p) ? savepvn(p,n) : NULL)
 
@@ -13500,12 +13857,12 @@ Perl_parser_dup(pTHX_ const yy_parser *const proto, CLONE_PARAMS *const param)
     PERL_ARGS_ASSERT_PARSER_DUP;
 
     if (!proto)
-       return NULL;
+        return NULL;
 
     /* look for it in the table first */
     parser = (yy_parser *)ptr_table_fetch(PL_ptr_table, proto);
     if (parser)
-       return parser;
+        return parser;
 
     /* create anew and remember what it is */
     Newxz(parser, 1, yy_parser);
@@ -13516,9 +13873,9 @@ Perl_parser_dup(pTHX_ const yy_parser *const proto, CLONE_PARAMS *const param)
     parser->lex_brackets = proto->lex_brackets;
     parser->lex_casemods = proto->lex_casemods;
     parser->lex_brackstack = savepvn(proto->lex_brackstack,
-                   (proto->lex_brackets < 120 ? 120 : proto->lex_brackets));
+                    (proto->lex_brackets < 120 ? 120 : proto->lex_brackets));
     parser->lex_casestack = savepvn(proto->lex_casestack,
-                   (proto->lex_casemods < 12 ? 12 : proto->lex_casemods));
+                    (proto->lex_casemods < 12 ? 12 : proto->lex_casemods));
     parser->lex_defer  = proto->lex_defer;
     parser->lex_dojoin = proto->lex_dojoin;
     parser->lex_formbrack = proto->lex_formbrack;
@@ -13554,23 +13911,23 @@ Perl_parser_dup(pTHX_ const yy_parser *const proto, CLONE_PARAMS *const param)
     parser->recheck_utf8_validity = proto->recheck_utf8_validity;
 
     {
-       char * const ols = SvPVX(proto->linestr);
-       char * const ls  = SvPVX(parser->linestr);
+        char * const ols = SvPVX(proto->linestr);
+        char * const ls  = SvPVX(parser->linestr);
 
-       parser->bufptr      = ls + (proto->bufptr >= ols ?
-                                   proto->bufptr -  ols : 0);
-       parser->oldbufptr   = ls + (proto->oldbufptr >= ols ?
-                                   proto->oldbufptr -  ols : 0);
-       parser->oldoldbufptr= ls + (proto->oldoldbufptr >= ols ?
-                                   proto->oldoldbufptr -  ols : 0);
-       parser->linestart   = ls + (proto->linestart >= ols ?
-                                   proto->linestart -  ols : 0);
-       parser->last_uni    = ls + (proto->last_uni >= ols ?
-                                   proto->last_uni -  ols : 0);
-       parser->last_lop    = ls + (proto->last_lop >= ols ?
-                                   proto->last_lop -  ols : 0);
+        parser->bufptr     = ls + (proto->bufptr >= ols ?
+                                    proto->bufptr -  ols : 0);
+        parser->oldbufptr   = ls + (proto->oldbufptr >= ols ?
+                                    proto->oldbufptr -  ols : 0);
+        parser->oldoldbufptr= ls + (proto->oldoldbufptr >= ols ?
+                                    proto->oldoldbufptr -  ols : 0);
+        parser->linestart   = ls + (proto->linestart >= ols ?
+                                    proto->linestart -  ols : 0);
+        parser->last_uni    = ls + (proto->last_uni >= ols ?
+                                    proto->last_uni -  ols : 0);
+        parser->last_lop    = ls + (proto->last_lop >= ols ?
+                                    proto->last_lop -  ols : 0);
 
-       parser->bufend      = ls + SvCUR(parser->linestr);
+        parser->bufend     = ls + SvCUR(parser->linestr);
     }
 
     Copy(proto->tokenbuf, parser->tokenbuf, 256, char);
@@ -13586,8 +13943,14 @@ Perl_parser_dup(pTHX_ const yy_parser *const proto, CLONE_PARAMS *const param)
     return parser;
 }
 
+/*
+=for apidoc_section $io
+=for apidoc fp_dup
+
+Duplicate a file handle, returning a pointer to the cloned object.
 
-/* duplicate a file handle */
+=cut
+*/
 
 PerlIO *
 Perl_fp_dup(pTHX_ PerlIO *const fp, const char type, CLONE_PARAMS *const param)
@@ -13598,12 +13961,12 @@ Perl_fp_dup(pTHX_ PerlIO *const fp, const char type, CLONE_PARAMS *const param)
     PERL_UNUSED_ARG(type);
 
     if (!fp)
-       return (PerlIO*)NULL;
+        return (PerlIO*)NULL;
 
     /* look for it in the table first */
     ret = (PerlIO*)ptr_table_fetch(PL_ptr_table, fp);
     if (ret)
-       return ret;
+        return ret;
 
     /* create anew and remember what it is */
 #ifdef __amigaos4__
@@ -13615,7 +13978,14 @@ Perl_fp_dup(pTHX_ PerlIO *const fp, const char type, CLONE_PARAMS *const param)
     return ret;
 }
 
-/* duplicate a directory handle */
+/*
+=for apidoc_section $io
+=for apidoc dirp_dup
+
+Duplicate a directory handle, returning a pointer to the cloned object.
+
+=cut
+*/
 
 DIR *
 Perl_dirp_dup(pTHX_ DIR *const dp, CLONE_PARAMS *const param)
@@ -13635,12 +14005,12 @@ Perl_dirp_dup(pTHX_ DIR *const dp, CLONE_PARAMS *const param)
     PERL_ARGS_ASSERT_DIRP_DUP;
 
     if (!dp)
-       return (DIR*)NULL;
+        return (DIR*)NULL;
 
     /* look for it in the table first */
     ret = (DIR*)ptr_table_fetch(PL_ptr_table, dp);
     if (ret)
-       return ret;
+        return ret;
 
 #if defined(HAS_FCHDIR) && defined(HAS_TELLDIR) && defined(HAS_SEEKDIR)
 
@@ -13653,8 +14023,8 @@ Perl_dirp_dup(pTHX_ DIR *const dp, CLONE_PARAMS *const param)
 
     /* chdir to our dir handle and open the present working directory */
     if (fchdir(my_dirfd(dp)) < 0 || !(ret = PerlDir_open("."))) {
-       PerlDir_close(pwd);
-       return (DIR *)NULL;
+        PerlDir_close(pwd);
+        return (DIR *)NULL;
     }
     /* Now we should have two dir handles pointing to the same dir. */
 
@@ -13674,7 +14044,7 @@ Perl_dirp_dup(pTHX_ DIR *const dp, CLONE_PARAMS *const param)
        tion. Then step back. */
     pos = PerlDir_tell(dp);
     if ((dirent = PerlDir_read(dp))) {
-       len = d_namlen(dirent);
+        len = d_namlen(dirent);
         if (len > sizeof(dirent->d_name) && sizeof(dirent->d_name) > PTRSIZE) {
             /* If the len is somehow magically longer than the
              * maximum length of the directory entry, even though
@@ -13683,45 +14053,45 @@ Perl_dirp_dup(pTHX_ DIR *const dp, CLONE_PARAMS *const param)
             PerlDir_close(ret);
             return (DIR*)NULL;
         }
-       if (len <= sizeof smallbuf) name = smallbuf;
-       else Newx(name, len, char);
-       Move(dirent->d_name, name, len, char);
+        if (len <= sizeof smallbuf) name = smallbuf;
+        else Newx(name, len, char);
+        Move(dirent->d_name, name, len, char);
     }
     PerlDir_seek(dp, pos);
 
     /* Iterate through the new dir handle, till we find a file with the
        right name. */
     if (!dirent) /* just before the end */
-       for(;;) {
-           pos = PerlDir_tell(ret);
-           if (PerlDir_read(ret)) continue; /* not there yet */
-           PerlDir_seek(ret, pos); /* step back */
-           break;
-       }
+        for(;;) {
+            pos = PerlDir_tell(ret);
+            if (PerlDir_read(ret)) continue; /* not there yet */
+            PerlDir_seek(ret, pos); /* step back */
+            break;
+        }
     else {
-       const long pos0 = PerlDir_tell(ret);
-       for(;;) {
-           pos = PerlDir_tell(ret);
-           if ((dirent = PerlDir_read(ret))) {
-               if (len == (STRLEN)d_namlen(dirent)
+        const long pos0 = PerlDir_tell(ret);
+        for(;;) {
+            pos = PerlDir_tell(ret);
+            if ((dirent = PerlDir_read(ret))) {
+                if (len == (STRLEN)d_namlen(dirent)
                     && memEQ(name, dirent->d_name, len)) {
-                   /* found it */
-                   PerlDir_seek(ret, pos); /* step back */
-                   break;
-               }
-               /* else we are not there yet; keep iterating */
-           }
-           else { /* This is not meant to happen. The best we can do is
-                     reset the iterator to the beginning. */
-               PerlDir_seek(ret, pos0);
-               break;
-           }
-       }
+                    /* found it */
+                    PerlDir_seek(ret, pos); /* step back */
+                    break;
+                }
+                /* else we are not there yet; keep iterating */
+            }
+            else { /* This is not meant to happen. The best we can do is
+                      reset the iterator to the beginning. */
+                PerlDir_seek(ret, pos0);
+                break;
+            }
+        }
     }
 #undef d_namlen
 
     if (name && name != smallbuf)
-       Safefree(name);
+        Safefree(name);
 #endif
 
 #ifdef WIN32
@@ -13730,12 +14100,19 @@ Perl_dirp_dup(pTHX_ DIR *const dp, CLONE_PARAMS *const param)
 
     /* pop it in the pointer table */
     if (ret)
-       ptr_table_store(PL_ptr_table, dp, ret);
+        ptr_table_store(PL_ptr_table, dp, ret);
 
     return ret;
 }
 
-/* duplicate a typeglob */
+/*
+=for apidoc_section $GV
+=for apidoc gp_dup
+
+Duplicate a typeglob, returning a pointer to the cloned object.
+
+=cut
+*/
 
 GP *
 Perl_gp_dup(pTHX_ GP *const gp, CLONE_PARAMS *const param)
@@ -13745,11 +14122,11 @@ Perl_gp_dup(pTHX_ GP *const gp, CLONE_PARAMS *const param)
     PERL_ARGS_ASSERT_GP_DUP;
 
     if (!gp)
-       return (GP*)NULL;
+        return (GP*)NULL;
     /* look for it in the table first */
     ret = (GP*)ptr_table_fetch(PL_ptr_table, gp);
     if (ret)
-       return ret;
+        return ret;
 
     /* create anew and remember what it is */
     Newxz(ret, 1, GP);
@@ -13771,7 +14148,15 @@ Perl_gp_dup(pTHX_ GP *const gp, CLONE_PARAMS *const param)
     return ret;
 }
 
-/* duplicate a chain of magic */
+
+/*
+=for apidoc_section $magic
+=for apidoc mg_dup
+
+Duplicate a chain of magic, returning a pointer to the cloned object.
+
+=cut
+*/
 
 MAGIC *
 Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *const param)
@@ -13782,60 +14167,60 @@ Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *const param)
     PERL_ARGS_ASSERT_MG_DUP;
 
     for (; mg; mg = mg->mg_moremagic) {
-       MAGIC *nmg;
-
-       if ((param->flags & CLONEf_JOIN_IN)
-               && mg->mg_type == PERL_MAGIC_backref)
-           /* when joining, we let the individual SVs add themselves to
-            * backref as needed. */
-           continue;
-
-       Newx(nmg, 1, MAGIC);
-       *mgprev_p = nmg;
-       mgprev_p = &(nmg->mg_moremagic);
-
-       /* There was a comment "XXX copy dynamic vtable?" but as we don't have
-          dynamic vtables, I'm not sure why Sarathy wrote it. The comment dates
-          from the original commit adding Perl_mg_dup() - revision 4538.
-          Similarly there is the annotation "XXX random ptr?" next to the
-          assignment to nmg->mg_ptr.  */
-       *nmg = *mg;
-
-       /* FIXME for plugins
-       if (nmg->mg_type == PERL_MAGIC_qr) {
-           nmg->mg_obj = MUTABLE_SV(CALLREGDUPE((REGEXP*)nmg->mg_obj, param));
-       }
-       else
-       */
-       nmg->mg_obj = (nmg->mg_flags & MGf_REFCOUNTED)
-                         ? nmg->mg_type == PERL_MAGIC_backref
-                               /* The backref AV has its reference
-                                * count deliberately bumped by 1 */
-                               ? SvREFCNT_inc(av_dup_inc((const AV *)
-                                                   nmg->mg_obj, param))
-                               : sv_dup_inc(nmg->mg_obj, param)
+        MAGIC *nmg;
+
+        if ((param->flags & CLONEf_JOIN_IN)
+                && mg->mg_type == PERL_MAGIC_backref)
+            /* when joining, we let the individual SVs add themselves to
+             * backref as needed. */
+            continue;
+
+        Newx(nmg, 1, MAGIC);
+        *mgprev_p = nmg;
+        mgprev_p = &(nmg->mg_moremagic);
+
+        /* There was a comment "XXX copy dynamic vtable?" but as we don't have
+           dynamic vtables, I'm not sure why Sarathy wrote it. The comment dates
+           from the original commit adding Perl_mg_dup() - revision 4538.
+           Similarly there is the annotation "XXX random ptr?" next to the
+           assignment to nmg->mg_ptr.  */
+        *nmg = *mg;
+
+        /* FIXME for plugins
+        if (nmg->mg_type == PERL_MAGIC_qr) {
+            nmg->mg_obj        = MUTABLE_SV(CALLREGDUPE((REGEXP*)nmg->mg_obj, param));
+        }
+        else
+        */
+        nmg->mg_obj = (nmg->mg_flags & MGf_REFCOUNTED)
+                          ? nmg->mg_type == PERL_MAGIC_backref
+                                /* The backref AV has its reference
+                                 * count deliberately bumped by 1 */
+                                ? SvREFCNT_inc(av_dup_inc((const AV *)
+                                                    nmg->mg_obj, param))
+                                : sv_dup_inc(nmg->mg_obj, param)
                           : (nmg->mg_type == PERL_MAGIC_regdatum ||
                              nmg->mg_type == PERL_MAGIC_regdata)
                                   ? nmg->mg_obj
                                   : sv_dup(nmg->mg_obj, param);
 
-       if (nmg->mg_ptr && nmg->mg_type != PERL_MAGIC_regex_global) {
-           if (nmg->mg_len > 0) {
-               nmg->mg_ptr     = SAVEPVN(nmg->mg_ptr, nmg->mg_len);
-               if (nmg->mg_type == PERL_MAGIC_overload_table &&
-                       AMT_AMAGIC((AMT*)nmg->mg_ptr))
-               {
-                   AMT * const namtp = (AMT*)nmg->mg_ptr;
-                   sv_dup_inc_multiple((SV**)(namtp->table),
-                                       (SV**)(namtp->table), NofAMmeth, param);
-               }
-           }
-           else if (nmg->mg_len == HEf_SVKEY)
-               nmg->mg_ptr = (char*)sv_dup_inc((const SV *)nmg->mg_ptr, param);
-       }
-       if ((nmg->mg_flags & MGf_DUP) && nmg->mg_virtual && nmg->mg_virtual->svt_dup) {
-           nmg->mg_virtual->svt_dup(aTHX_ nmg, param);
-       }
+        if (nmg->mg_ptr && nmg->mg_type != PERL_MAGIC_regex_global) {
+            if (nmg->mg_len > 0) {
+                nmg->mg_ptr    = SAVEPVN(nmg->mg_ptr, nmg->mg_len);
+                if (nmg->mg_type == PERL_MAGIC_overload_table &&
+                        AMT_AMAGIC((AMT*)nmg->mg_ptr))
+                {
+                    AMT * const namtp = (AMT*)nmg->mg_ptr;
+                    sv_dup_inc_multiple((SV**)(namtp->table),
+                                        (SV**)(namtp->table), NofAMmeth, param);
+                }
+            }
+            else if (nmg->mg_len == HEf_SVKEY)
+                nmg->mg_ptr = (char*)sv_dup_inc((const SV *)nmg->mg_ptr, param);
+        }
+        if ((nmg->mg_flags & MGf_DUP) && nmg->mg_virtual && nmg->mg_virtual->svt_dup) {
+            nmg->mg_virtual->svt_dup(aTHX_ nmg, param);
+        }
     }
     return mgret;
 }
@@ -13847,7 +14232,14 @@ struct ptr_tbl_arena {
     struct ptr_tbl_ent array[1023/3]; /* as ptr_tbl_ent has 3 pointers.  */
 };
 
-/* create a new pointer-mapping table */
+/*
+=for apidoc_section $embedding
+=for apidoc ptr_table_new
+
+Create a new pointer-mapping table
+
+=cut
+*/
 
 PTR_TBL_t *
 Perl_ptr_table_new(pTHX)
@@ -13880,12 +14272,21 @@ S_ptr_table_find(PTR_TBL_t *const tbl, const void *const sv)
 
     tblent = tbl->tbl_ary[hash & tbl->tbl_max];
     for (; tblent; tblent = tblent->next) {
-       if (tblent->oldval == sv)
-           return tblent;
+        if (tblent->oldval == sv)
+            return tblent;
     }
     return NULL;
 }
 
+/*
+=for apidoc ptr_table_fetch
+
+Look for C<sv> in the pointer-mapping table C<tbl>, returning its value, or
+NULL if not found.
+
+=cut
+*/
+
 void *
 Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *const tbl, const void *const sv)
 {
@@ -13897,9 +14298,17 @@ Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *const tbl, const void *const sv)
     return tblent ? tblent->newval : NULL;
 }
 
-/* add a new entry to a pointer-mapping table 'tbl'.  In hash terms, 'oldsv' is
- * the key; 'newsv' is the value.  The names "old" and "new" are specific to
- * the core's typical use of ptr_tables in thread cloning. */
+/*
+=for apidoc ptr_table_store
+
+Add a new entry to a pointer-mapping table C<tbl>.
+In hash terms, C<oldsv> is the key; Cnewsv> is the value.
+
+The names "old" and "new" are specific to the core's typical use of ptr_tables
+in thread cloning.
+
+=cut
+*/
 
 void
 Perl_ptr_table_store(pTHX_ PTR_TBL_t *const tbl, const void *const oldsv, void *const newsv)
@@ -13910,33 +14319,39 @@ Perl_ptr_table_store(pTHX_ PTR_TBL_t *const tbl, const void *const oldsv, void *
     PERL_UNUSED_CONTEXT;
 
     if (tblent) {
-       tblent->newval = newsv;
+        tblent->newval = newsv;
     } else {
-       const UV entry = PTR_TABLE_HASH(oldsv) & tbl->tbl_max;
+        const UV entry = PTR_TABLE_HASH(oldsv) & tbl->tbl_max;
 
-       if (tbl->tbl_arena_next == tbl->tbl_arena_end) {
-           struct ptr_tbl_arena *new_arena;
+        if (tbl->tbl_arena_next == tbl->tbl_arena_end) {
+            struct ptr_tbl_arena *new_arena;
 
-           Newx(new_arena, 1, struct ptr_tbl_arena);
-           new_arena->next = tbl->tbl_arena;
-           tbl->tbl_arena = new_arena;
-           tbl->tbl_arena_next = new_arena->array;
-           tbl->tbl_arena_end = C_ARRAY_END(new_arena->array);
-       }
+            Newx(new_arena, 1, struct ptr_tbl_arena);
+            new_arena->next = tbl->tbl_arena;
+            tbl->tbl_arena = new_arena;
+            tbl->tbl_arena_next = new_arena->array;
+            tbl->tbl_arena_end = C_ARRAY_END(new_arena->array);
+        }
 
-       tblent = tbl->tbl_arena_next++;
+        tblent = tbl->tbl_arena_next++;
 
-       tblent->oldval = oldsv;
-       tblent->newval = newsv;
-       tblent->next = tbl->tbl_ary[entry];
-       tbl->tbl_ary[entry] = tblent;
-       tbl->tbl_items++;
-       if (tblent->next && tbl->tbl_items > tbl->tbl_max)
-           ptr_table_split(tbl);
+        tblent->oldval = oldsv;
+        tblent->newval = newsv;
+        tblent->next = tbl->tbl_ary[entry];
+        tbl->tbl_ary[entry] = tblent;
+        tbl->tbl_items++;
+        if (tblent->next && tbl->tbl_items > tbl->tbl_max)
+            ptr_table_split(tbl);
     }
 }
 
-/* double the hash bucket size of an existing ptr table */
+/*
+=for apidoc ptr_table_split
+
+Double the hash bucket size of an existing ptr table
+
+=cut
+*/
 
 void
 Perl_ptr_table_split(pTHX_ PTR_TBL_t *const tbl)
@@ -13954,52 +14369,32 @@ Perl_ptr_table_split(pTHX_ PTR_TBL_t *const tbl)
     tbl->tbl_max = --newsize;
     tbl->tbl_ary = ary;
     for (i=0; i < oldsize; i++, ary++) {
-       PTR_TBL_ENT_t **entp = ary;
-       PTR_TBL_ENT_t *ent = *ary;
-       PTR_TBL_ENT_t **curentp;
-       if (!ent)
-           continue;
-       curentp = ary + oldsize;
-       do {
-           if ((newsize & PTR_TABLE_HASH(ent->oldval)) != i) {
-               *entp = ent->next;
-               ent->next = *curentp;
-               *curentp = ent;
-           }
-           else
-               entp = &ent->next;
-           ent = *entp;
-       } while (ent);
+        PTR_TBL_ENT_t **entp = ary;
+        PTR_TBL_ENT_t *ent = *ary;
+        PTR_TBL_ENT_t **curentp;
+        if (!ent)
+            continue;
+        curentp = ary + oldsize;
+        do {
+            if ((newsize & PTR_TABLE_HASH(ent->oldval)) != i) {
+                *entp = ent->next;
+                ent->next = *curentp;
+                *curentp = ent;
+            }
+            else
+                entp = &ent->next;
+            ent = *entp;
+        } while (ent);
     }
 }
 
-/* remove all the entries from a ptr table */
-/* Deprecated - will be removed post 5.14 */
-
-void
-Perl_ptr_table_clear(pTHX_ PTR_TBL_t *const tbl)
-{
-    PERL_UNUSED_CONTEXT;
-    if (tbl && tbl->tbl_items) {
-       struct ptr_tbl_arena *arena = tbl->tbl_arena;
-
-       Zero(tbl->tbl_ary, tbl->tbl_max + 1, struct ptr_tbl_ent *);
-
-       while (arena) {
-           struct ptr_tbl_arena *next = arena->next;
-
-           Safefree(arena);
-           arena = next;
-       };
+/*
+=for apidoc ptr_table_free
 
-       tbl->tbl_items = 0;
-       tbl->tbl_arena = NULL;
-       tbl->tbl_arena_next = NULL;
-       tbl->tbl_arena_end = NULL;
-    }
-}
+Clear and free a ptr table
 
-/* clear and free a ptr table */
+=cut
+*/
 
 void
 Perl_ptr_table_free(pTHX_ PTR_TBL_t *const tbl)
@@ -14015,10 +14410,10 @@ Perl_ptr_table_free(pTHX_ PTR_TBL_t *const tbl)
     arena = tbl->tbl_arena;
 
     while (arena) {
-       struct ptr_tbl_arena *next = arena->next;
+        struct ptr_tbl_arena *next = arena->next;
 
-       Safefree(arena);
-       arena = next;
+        Safefree(arena);
+        arena = next;
     }
 
     Safefree(tbl->tbl_ary);
@@ -14028,502 +14423,544 @@ Perl_ptr_table_free(pTHX_ PTR_TBL_t *const tbl)
 #if defined(USE_ITHREADS)
 
 void
-Perl_rvpv_dup(pTHX_ SV *const dstr, const SV *const sstr, CLONE_PARAMS *const param)
+Perl_rvpv_dup(pTHX_ SV *const dsv, const SV *const ssv, CLONE_PARAMS *const param)
 {
     PERL_ARGS_ASSERT_RVPV_DUP;
 
-    assert(!isREGEXP(sstr));
-    if (SvROK(sstr)) {
-       if (SvWEAKREF(sstr)) {
-           SvRV_set(dstr, sv_dup(SvRV_const(sstr), param));
-           if (param->flags & CLONEf_JOIN_IN) {
-               /* if joining, we add any back references individually rather
-                * than copying the whole backref array */
-               Perl_sv_add_backref(aTHX_ SvRV(dstr), dstr);
-           }
-       }
-       else
-           SvRV_set(dstr, sv_dup_inc(SvRV_const(sstr), param));
-    }
-    else if (SvPVX_const(sstr)) {
-       /* Has something there */
-       if (SvLEN(sstr)) {
-           /* Normal PV - clone whole allocated space */
-           SvPV_set(dstr, SAVEPVN(SvPVX_const(sstr), SvLEN(sstr)-1));
-           /* sstr may not be that normal, but actually copy on write.
-              But we are a true, independent SV, so:  */
-           SvIsCOW_off(dstr);
-       }
-       else {
-           /* Special case - not normally malloced for some reason */
-           if (isGV_with_GP(sstr)) {
-               /* Don't need to do anything here.  */
-           }
-           else if ((SvIsCOW(sstr))) {
-               /* A "shared" PV - clone it as "shared" PV */
-               SvPV_set(dstr,
-                        HEK_KEY(hek_dup(SvSHARED_HEK_FROM_PV(SvPVX_const(sstr)),
-                                        param)));
-           }
-           else {
-               /* Some other special case - random pointer */
-               SvPV_set(dstr, (char *) SvPVX_const(sstr));             
-           }
-       }
+    assert(!isREGEXP(ssv));
+    if (SvROK(ssv)) {
+        if (SvWEAKREF(ssv)) {
+            SvRV_set(dsv, sv_dup(SvRV_const(ssv), param));
+            if (param->flags & CLONEf_JOIN_IN) {
+                /* if joining, we add any back references individually rather
+                 * than copying the whole backref array */
+                Perl_sv_add_backref(aTHX_ SvRV(dsv), dsv);
+            }
+        }
+        else
+            SvRV_set(dsv, sv_dup_inc(SvRV_const(ssv), param));
+    }
+    else if (SvPVX_const(ssv)) {
+        /* Has something there */
+        if (SvLEN(ssv)) {
+            /* Normal PV - clone whole allocated space */
+            SvPV_set(dsv, SAVEPVN(SvPVX_const(ssv), SvLEN(ssv)-1));
+            /* ssv may not be that normal, but actually copy on write.
+               But we are a true, independent SV, so:  */
+            SvIsCOW_off(dsv);
+        }
+        else {
+            /* Special case - not normally malloced for some reason */
+            if (isGV_with_GP(ssv)) {
+                /* Don't need to do anything here.  */
+            }
+            else if ((SvIsCOW_shared_hash(ssv))) {
+                /* A "shared" PV - clone it as "shared" PV */
+                SvPV_set(dsv,
+                         HEK_KEY(hek_dup(SvSHARED_HEK_FROM_PV(SvPVX_const(ssv)),
+                                         param)));
+            }
+            else {
+                /* Some other special case - random pointer */
+                SvPV_set(dsv, (char *) SvPVX_const(ssv));
+            }
+        }
     }
     else {
-       /* Copy the NULL */
-       SvPV_set(dstr, NULL);
+        /* Copy the NULL */
+        SvPV_set(dsv, NULL);
     }
 }
 
 /* duplicate a list of SVs. source and dest may point to the same memory.  */
 static SV **
 S_sv_dup_inc_multiple(pTHX_ SV *const *source, SV **dest,
-                     SSize_t items, CLONE_PARAMS *const param)
+                      SSize_t items, CLONE_PARAMS *const param)
 {
     PERL_ARGS_ASSERT_SV_DUP_INC_MULTIPLE;
 
     while (items-- > 0) {
-       *dest++ = sv_dup_inc(*source++, param);
+        *dest++ = sv_dup_inc(*source++, param);
     }
 
     return dest;
 }
 
+/* duplicate the HvAUX of an HV */
+static void
+S_sv_dup_hvaux(pTHX_ const SV *const ssv, SV *dsv, CLONE_PARAMS *const param)
+{
+    PERL_ARGS_ASSERT_SV_DUP_HVAUX;
+
+    const struct xpvhv_aux * const saux = HvAUX(ssv);
+    struct xpvhv_aux * const daux = HvAUX(dsv);
+    /* This flag isn't copied.  */
+    SvFLAGS(dsv) |= SVphv_HasAUX;
+
+    if (saux->xhv_name_count) {
+        HEK ** const sname = saux->xhv_name_u.xhvnameu_names;
+        const I32 count = saux->xhv_name_count < 0
+            ? -saux->xhv_name_count
+            :  saux->xhv_name_count;
+        HEK **shekp = sname + count;
+        HEK **dhekp;
+        Newx(daux->xhv_name_u.xhvnameu_names, count, HEK *);
+        dhekp = daux->xhv_name_u.xhvnameu_names + count;
+        while (shekp-- > sname) {
+            dhekp--;
+            *dhekp = hek_dup(*shekp, param);
+        }
+    }
+    else {
+        daux->xhv_name_u.xhvnameu_name = hek_dup(saux->xhv_name_u.xhvnameu_name, param);
+    }
+    daux->xhv_name_count = saux->xhv_name_count;
+
+    daux->xhv_aux_flags = saux->xhv_aux_flags;
+#ifdef PERL_HASH_RANDOMIZE_KEYS
+    daux->xhv_rand = saux->xhv_rand;
+    daux->xhv_last_rand = saux->xhv_last_rand;
+#endif
+    daux->xhv_riter = saux->xhv_riter;
+    daux->xhv_eiter = saux->xhv_eiter ? he_dup(saux->xhv_eiter, FALSE, param) : 0;
+    /* backref array needs refcnt=2; see sv_add_backref */
+    daux->xhv_backreferences =
+        (param->flags & CLONEf_JOIN_IN)
+            /* when joining, we let the individual GVs and
+             * CVs add themselves to backref as
+             * needed. This avoids pulling in stuff
+             * that isn't required, and simplifies the
+             * case where stashes aren't cloned back
+             * if they already exist in the parent
+             * thread */
+        ? NULL
+        : saux->xhv_backreferences
+            ? (SvTYPE(saux->xhv_backreferences) == SVt_PVAV)
+                ? MUTABLE_AV(SvREFCNT_inc(
+                      sv_dup_inc((const SV *)
+                        saux->xhv_backreferences, param)))
+                : MUTABLE_AV(sv_dup((const SV *)
+                        saux->xhv_backreferences, param))
+            : 0;
+
+    daux->xhv_mro_meta = saux->xhv_mro_meta
+        ? mro_meta_dup(saux->xhv_mro_meta, param)
+        : 0;
+
+    /* Record stashes for possible cloning in Perl_clone(). */
+    if (HvNAME(ssv))
+        av_push(param->stashes, dsv);
+
+    if (HvSTASH_IS_CLASS(ssv)) {
+        daux->xhv_class_superclass    = hv_dup_inc(saux->xhv_class_superclass,    param);
+        daux->xhv_class_initfields_cv = cv_dup_inc(saux->xhv_class_initfields_cv, param);
+        daux->xhv_class_adjust_blocks = av_dup_inc(saux->xhv_class_adjust_blocks, param);
+        daux->xhv_class_fields        = padnamelist_dup_inc(saux->xhv_class_fields, param);
+        daux->xhv_class_next_fieldix  = saux->xhv_class_next_fieldix;
+        daux->xhv_class_param_map     = hv_dup_inc(saux->xhv_class_param_map,     param);
+
+        /* TODO: This does mean that we can't compile more `field` expressions
+         * in the cloned thread, but surely we're done with compiletime now..?
+         */
+        daux->xhv_class_suspended_initfields_compcv = NULL;
+    }
+}
+
 /* duplicate an SV of any type (including AV, HV etc) */
 
 static SV *
-S_sv_dup_common(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
+S_sv_dup_common(pTHX_ const SV *const ssv, CLONE_PARAMS *const param)
 {
-    dVAR;
-    SV *dstr;
+    SV *dsv;
 
     PERL_ARGS_ASSERT_SV_DUP_COMMON;
 
-    if (SvTYPE(sstr) == (svtype)SVTYPEMASK) {
+    if (SvIS_FREED(ssv)) {
 #ifdef DEBUG_LEAKING_SCALARS_ABORT
-       abort();
+        abort();
 #endif
-       return NULL;
+        return NULL;
     }
     /* look for it in the table first */
-    dstr = MUTABLE_SV(ptr_table_fetch(PL_ptr_table, sstr));
-    if (dstr)
-       return dstr;
+    dsv = MUTABLE_SV(ptr_table_fetch(PL_ptr_table, ssv));
+    if (dsv)
+        return dsv;
 
     if(param->flags & CLONEf_JOIN_IN) {
         /** We are joining here so we don't want do clone
-           something that is bad **/
-       if (SvTYPE(sstr) == SVt_PVHV) {
-           const HEK * const hvname = HvNAME_HEK(sstr);
-           if (hvname) {
-               /** don't clone stashes if they already exist **/
-               dstr = MUTABLE_SV(gv_stashpvn(HEK_KEY(hvname), HEK_LEN(hvname),
+            something that is bad **/
+        if (SvTYPE(ssv) == SVt_PVHV) {
+            const HEK * const hvname = HvNAME_HEK(ssv);
+            if (hvname) {
+                /** don't clone stashes if they already exist **/
+                dsv = MUTABLE_SV(gv_stashpvn(HEK_KEY(hvname), HEK_LEN(hvname),
                                                 HEK_UTF8(hvname) ? SVf_UTF8 : 0));
-               ptr_table_store(PL_ptr_table, sstr, dstr);
-               return dstr;
-           }
-        }
-       else if (SvTYPE(sstr) == SVt_PVGV && !SvFAKE(sstr)) {
-           HV *stash = GvSTASH(sstr);
-           const HEK * hvname;
-           if (stash && (hvname = HvNAME_HEK(stash))) {
-               /** don't clone GVs if they already exist **/
-               SV **svp;
-               stash = gv_stashpvn(HEK_KEY(hvname), HEK_LEN(hvname),
-                                   HEK_UTF8(hvname) ? SVf_UTF8 : 0);
-               svp = hv_fetch(
-                       stash, GvNAME(sstr),
-                       GvNAMEUTF8(sstr)
-                           ? -GvNAMELEN(sstr)
-                           :  GvNAMELEN(sstr),
-                       0
-                     );
-               if (svp && *svp && SvTYPE(*svp) == SVt_PVGV) {
-                   ptr_table_store(PL_ptr_table, sstr, *svp);
-                   return *svp;
-               }
-           }
+                ptr_table_store(PL_ptr_table, ssv, dsv);
+                return dsv;
+            }
+        }
+        else if (SvTYPE(ssv) == SVt_PVGV && !SvFAKE(ssv)) {
+            HV *stash = GvSTASH(ssv);
+            const HEK * hvname;
+            if (stash && (hvname = HvNAME_HEK(stash))) {
+                /** don't clone GVs if they already exist **/
+                SV **svp;
+                stash = gv_stashpvn(HEK_KEY(hvname), HEK_LEN(hvname),
+                                    HEK_UTF8(hvname) ? SVf_UTF8 : 0);
+                svp = hv_fetch(
+                        stash, GvNAME(ssv),
+                        GvNAMEUTF8(ssv)
+                            ? -GvNAMELEN(ssv)
+                            :  GvNAMELEN(ssv),
+                        0
+                      );
+                if (svp && *svp && SvTYPE(*svp) == SVt_PVGV) {
+                    ptr_table_store(PL_ptr_table, ssv, *svp);
+                    return *svp;
+                }
+            }
         }
     }
 
     /* create anew and remember what it is */
-    new_SV(dstr);
+    new_SV(dsv);
 
 #ifdef DEBUG_LEAKING_SCALARS
-    dstr->sv_debug_optype = sstr->sv_debug_optype;
-    dstr->sv_debug_line = sstr->sv_debug_line;
-    dstr->sv_debug_inpad = sstr->sv_debug_inpad;
-    dstr->sv_debug_parent = (SV*)sstr;
-    FREE_SV_DEBUG_FILE(dstr);
-    dstr->sv_debug_file = savesharedpv(sstr->sv_debug_file);
+    dsv->sv_debug_optype = ssv->sv_debug_optype;
+    dsv->sv_debug_line = ssv->sv_debug_line;
+    dsv->sv_debug_inpad = ssv->sv_debug_inpad;
+    dsv->sv_debug_parent = (SV*)ssv;
+    FREE_SV_DEBUG_FILE(dsv);
+    dsv->sv_debug_file = savesharedpv(ssv->sv_debug_file);
+#endif
+
+    ptr_table_store(PL_ptr_table, ssv, dsv);
+
+    /* clone */
+    SvFLAGS(dsv)       = SvFLAGS(ssv);
+    SvFLAGS(dsv)       &= ~SVf_OOK;            /* don't propagate OOK hack */
+    SvREFCNT(dsv)      = 0;                    /* must be before any other dups! */
+
+#ifdef DEBUGGING
+    if (SvANY(ssv) && PL_watch_pvx && SvPVX_const(ssv) == PL_watch_pvx)
+        PerlIO_printf(Perl_debug_log, "watch at %p hit, found string \"%s\"\n",
+                      (void*)PL_watch_pvx, SvPVX_const(ssv));
+#endif
+
+    /* don't clone objects whose class has asked us not to */
+    if (SvOBJECT(ssv)
+     && ! (SvFLAGS(SvSTASH(ssv)) & SVphv_CLONEABLE))
+    {
+        SvFLAGS(dsv) = 0;
+        return dsv;
+    }
+
+    switch (SvTYPE(ssv)) {
+    case SVt_NULL:
+        SvANY(dsv)     = NULL;
+        break;
+    case SVt_IV:
+        SET_SVANY_FOR_BODYLESS_IV(dsv);
+        if(SvROK(ssv)) {
+            Perl_rvpv_dup(aTHX_ dsv, ssv, param);
+        } else {
+            SvIV_set(dsv, SvIVX(ssv));
+        }
+        break;
+    case SVt_NV:
+#if NVSIZE <= IVSIZE
+        SET_SVANY_FOR_BODYLESS_NV(dsv);
+#else
+        SvANY(dsv)     = new_XNV();
+#endif
+        SvNV_set(dsv, SvNVX(ssv));
+        break;
+    default:
+        {
+            /* These are all the types that need complex bodies allocating.  */
+            void *new_body;
+            const svtype sv_type = SvTYPE(ssv);
+            const struct body_details *sv_type_details
+                = bodies_by_type + sv_type;
+
+            switch (sv_type) {
+            default:
+                Perl_croak(param->proto_perl, "Bizarre SvTYPE [%" IVdf "]", (IV)SvTYPE(ssv));
+                NOT_REACHED; /* NOTREACHED */
+                break;
+
+            case SVt_PVHV:
+                if (HvHasAUX(ssv)) {
+                    sv_type_details = &fake_hv_with_aux;
+#ifdef PURIFY
+                    new_body = new_NOARENA(sv_type_details);
+#else
+                    new_body_from_arena(new_body, HVAUX_ARENA_ROOT_IX, fake_hv_with_aux);
+#endif
+                    goto have_body;
+                }
+                /* FALLTHROUGH */
+            case SVt_PVOBJ:
+            case SVt_PVGV:
+            case SVt_PVIO:
+            case SVt_PVFM:
+            case SVt_PVAV:
+            case SVt_PVCV:
+            case SVt_PVLV:
+            case SVt_REGEXP:
+            case SVt_PVMG:
+            case SVt_PVNV:
+            case SVt_PVIV:
+            case SVt_INVLIST:
+            case SVt_PV:
+                assert(sv_type_details->body_size);
+#ifndef PURIFY
+                if (sv_type_details->arena) {
+                    new_body = S_new_body(aTHX_ sv_type);
+                    new_body
+                        = (void*)((char*)new_body - sv_type_details->offset);
+                } else
 #endif
+                {
+                    new_body = new_NOARENA(sv_type_details);
+                }
+            }
+        have_body:
+            assert(new_body);
+            SvANY(dsv) = new_body;
+
+#ifndef PURIFY
+            Copy(((char*)SvANY(ssv)) + sv_type_details->offset,
+                 ((char*)SvANY(dsv)) + sv_type_details->offset,
+                 sv_type_details->copy, char);
+#else
+            Copy(((char*)SvANY(ssv)),
+                 ((char*)SvANY(dsv)),
+                 sv_type_details->body_size + sv_type_details->offset, char);
+#endif
+
+            if (sv_type != SVt_PVAV && sv_type != SVt_PVHV && sv_type != SVt_PVOBJ
+                && !isGV_with_GP(dsv)
+                && !isREGEXP(dsv)
+                && !(sv_type == SVt_PVIO && !(IoFLAGS(dsv) & IOf_FAKE_DIRP)))
+                Perl_rvpv_dup(aTHX_ dsv, ssv, param);
+
+            /* The Copy above means that all the source (unduplicated) pointers
+               are now in the destination.  We can check the flags and the
+               pointers in either, but it's possible that there's less cache
+               missing by always going for the destination.
+               FIXME - instrument and check that assumption  */
+            if (sv_type >= SVt_PVMG) {
+                if (SvMAGIC(dsv))
+                    SvMAGIC_set(dsv, mg_dup(SvMAGIC(dsv), param));
+                if (SvOBJECT(dsv) && SvSTASH(dsv))
+                    SvSTASH_set(dsv, hv_dup_inc(SvSTASH(dsv), param));
+                else SvSTASH_set(dsv, 0); /* don't copy DESTROY cache */
+            }
 
-    ptr_table_store(PL_ptr_table, sstr, dstr);
+            /* The cast silences a GCC warning about unhandled types.  */
+            switch ((int)sv_type) {
+            case SVt_PV:
+                break;
+            case SVt_PVIV:
+                break;
+            case SVt_PVNV:
+                break;
+            case SVt_PVMG:
+                break;
+            case SVt_REGEXP:
+              duprex:
+                /* FIXME for plugins */
+                re_dup_guts((REGEXP*) ssv, (REGEXP*) dsv, param);
+                break;
+            case SVt_PVLV:
+                /* XXX LvTARGOFF sometimes holds PMOP* when DEBUGGING */
+                if (LvTYPE(dsv) == 't') /* for tie: unrefcnted fake (SV**) */
+                    LvTARG(dsv) = dsv;
+                else if (LvTYPE(dsv) == 'T') /* for tie: fake HE */
+                    LvTARG(dsv) = MUTABLE_SV(he_dup((HE*)LvTARG(dsv), FALSE, param));
+                else
+                    LvTARG(dsv) = sv_dup_inc(LvTARG(dsv), param);
+                if (isREGEXP(ssv)) goto duprex;
+                /* FALLTHROUGH */
+            case SVt_PVGV:
+                /* non-GP case already handled above */
+                if(isGV_with_GP(ssv)) {
+                    GvNAME_HEK(dsv) = hek_dup(GvNAME_HEK(dsv), param);
+                    /* Don't call sv_add_backref here as it's going to be
+                       created as part of the magic cloning of the symbol
+                       table--unless this is during a join and the stash
+                       is not actually being cloned.  */
+                    /* Danger Will Robinson - GvGP(dsv) isn't initialised
+                       at the point of this comment.  */
+                    GvSTASH(dsv) = hv_dup(GvSTASH(dsv), param);
+                    if (param->flags & CLONEf_JOIN_IN)
+                        Perl_sv_add_backref(aTHX_ MUTABLE_SV(GvSTASH(dsv)), dsv);
+                    GvGP_set(dsv, gp_dup(GvGP(ssv), param));
+                    (void)GpREFCNT_inc(GvGP(dsv));
+                }
+                break;
+            case SVt_PVIO:
+                /* PL_parser->rsfp_filters entries have fake IoDIRP() */
+                if(IoFLAGS(dsv) & IOf_FAKE_DIRP) {
+                    /* I have no idea why fake dirp (rsfps)
+                       should be treated differently but otherwise
+                       we end up with leaks -- sky*/
+                    IoTOP_GV(dsv)      = gv_dup_inc(IoTOP_GV(dsv), param);
+                    IoFMT_GV(dsv)      = gv_dup_inc(IoFMT_GV(dsv), param);
+                    IoBOTTOM_GV(dsv)   = gv_dup_inc(IoBOTTOM_GV(dsv), param);
+                } else {
+                    IoTOP_GV(dsv)      = gv_dup(IoTOP_GV(dsv), param);
+                    IoFMT_GV(dsv)      = gv_dup(IoFMT_GV(dsv), param);
+                    IoBOTTOM_GV(dsv)   = gv_dup(IoBOTTOM_GV(dsv), param);
+                    if (IoDIRP(dsv)) {
+                        IoDIRP(dsv)    = dirp_dup(IoDIRP(dsv), param);
+                    } else {
+                        NOOP;
+                        /* IoDIRP(dsv) is already a copy of IoDIRP(ssv)  */
+                    }
+                    IoIFP(dsv) = fp_dup(IoIFP(ssv), IoTYPE(dsv), param);
+                }
+                if (IoOFP(dsv) == IoIFP(ssv))
+                    IoOFP(dsv) = IoIFP(dsv);
+                else
+                    IoOFP(dsv) = fp_dup(IoOFP(dsv), IoTYPE(dsv), param);
+                IoTOP_NAME(dsv)        = SAVEPV(IoTOP_NAME(dsv));
+                IoFMT_NAME(dsv)        = SAVEPV(IoFMT_NAME(dsv));
+                IoBOTTOM_NAME(dsv)     = SAVEPV(IoBOTTOM_NAME(dsv));
+                break;
+            case SVt_PVAV:
+                /* avoid cloning an empty array */
+                if (AvARRAY((const AV *)ssv) && AvFILLp((const AV *)ssv) >= 0) {
+                    SV **dst_ary, **src_ary;
+                    SSize_t items = AvFILLp((const AV *)ssv) + 1;
+
+                    src_ary = AvARRAY((const AV *)ssv);
+                    Newx(dst_ary, AvMAX((const AV *)ssv)+1, SV*);
+                    ptr_table_store(PL_ptr_table, src_ary, dst_ary);
+                    AvARRAY(MUTABLE_AV(dsv)) = dst_ary;
+                    AvALLOC((const AV *)dsv) = dst_ary;
+                    if (AvREAL((const AV *)ssv)) {
+                        dst_ary = sv_dup_inc_multiple(src_ary, dst_ary, items,
+                                                      param);
+                    }
+                    else {
+                        while (items-- > 0)
+                            *dst_ary++ = sv_dup(*src_ary++, param);
+                    }
+                    items = AvMAX((const AV *)ssv) - AvFILLp((const AV *)ssv);
+                    while (items-- > 0) {
+                        *dst_ary++ = NULL;
+                    }
+                }
+                else {
+                    AvARRAY(MUTABLE_AV(dsv))   = NULL;
+                    AvALLOC((const AV *)dsv)   = (SV**)NULL;
+                    AvMAX(  (const AV *)dsv)   = -1;
+                    AvFILLp((const AV *)dsv)   = -1;
+                }
+                break;
+            case SVt_PVHV:
+                if (HvARRAY((const HV *)ssv)) {
+                    STRLEN i = 0;
+                    XPVHV * const dxhv = (XPVHV*)SvANY(dsv);
+                    XPVHV * const sxhv = (XPVHV*)SvANY(ssv);
+                    char *darray;
+                    Newx(darray, PERL_HV_ARRAY_ALLOC_BYTES(dxhv->xhv_max+1),
+                        char);
+                    HvARRAY(dsv) = (HE**)darray;
+                    while (i <= sxhv->xhv_max) {
+                        const HE * const source = HvARRAY(ssv)[i];
+                        HvARRAY(dsv)[i] = source
+                            ? he_dup(source, FALSE, param) : 0;
+                        ++i;
+                    }
+                    if (HvHasAUX(ssv))
+                        sv_dup_hvaux(ssv, dsv, param);
+                }
+                else
+                    HvARRAY(MUTABLE_HV(dsv)) = NULL;
+                break;
+            case SVt_PVCV:
+                if (!(param->flags & CLONEf_COPY_STACKS)) {
+                    CvDEPTH(dsv) = 0;
+                }
+                /* FALLTHROUGH */
+            case SVt_PVFM:
+                /* NOTE: not refcounted */
+                SvANY(MUTABLE_CV(dsv))->xcv_stash =
+                    hv_dup(CvSTASH(dsv), param);
+                if ((param->flags & CLONEf_JOIN_IN) && CvSTASH(dsv))
+                    Perl_sv_add_backref(aTHX_ MUTABLE_SV(CvSTASH(dsv)), dsv);
+                if (!CvISXSUB(dsv)) {
+                    OP_REFCNT_LOCK;
+                    CvROOT(dsv) = OpREFCNT_inc(CvROOT(dsv));
+                    OP_REFCNT_UNLOCK;
+                    CvSLABBED_off(dsv);
+                } else if (CvCONST(dsv)) {
+                    CvXSUBANY(dsv).any_ptr =
+                        sv_dup_inc((const SV *)CvXSUBANY(dsv).any_ptr, param);
+                } else if (CvREFCOUNTED_ANYSV(dsv)) {
+                    CvXSUBANY(dsv).any_sv =
+                        sv_dup_inc((const SV *)CvXSUBANY(dsv).any_sv, param);
+                }
+                assert(!CvSLABBED(dsv));
+                if (CvDYNFILE(dsv)) CvFILE(dsv) = SAVEPV(CvFILE(dsv));
+                if (CvNAMED(dsv))
+                    SvANY((CV *)dsv)->xcv_gv_u.xcv_hek =
+                        hek_dup(CvNAME_HEK((CV *)ssv), 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 */
+                else
+                  SvANY(MUTABLE_CV(dsv))->xcv_gv_u.xcv_gv =
+                    CvCVGV_RC(dsv)
+                    ? gv_dup_inc(CvGV(ssv), param)
+                    : (param->flags & CLONEf_JOIN_IN)
+                        ? NULL
+                        : gv_dup(CvGV(ssv), param);
+
+                if (!CvISXSUB(ssv)) {
+                    PADLIST * padlist = CvPADLIST(ssv);
+                    if(padlist)
+                        padlist = padlist_dup(padlist, param);
+                    CvPADLIST_set(dsv, padlist);
+                } else
+/* unthreaded perl can't sv_dup so we don't support unthreaded's CvHSCXT */
+                    PoisonPADLIST(dsv);
 
-    /* clone */
-    SvFLAGS(dstr)      = SvFLAGS(sstr);
-    SvFLAGS(dstr)      &= ~SVf_OOK;            /* don't propagate OOK hack */
-    SvREFCNT(dstr)     = 0;                    /* must be before any other dups! */
+                CvOUTSIDE(dsv) =
+                    CvWEAKOUTSIDE(ssv)
+                    ? cv_dup(    CvOUTSIDE(dsv), param)
+                    : cv_dup_inc(CvOUTSIDE(dsv), param);
+                break;
+            case SVt_PVOBJ:
+                {
+                    Size_t fieldcount = ObjectMAXFIELD(ssv) + 1;
 
-#ifdef DEBUGGING
-    if (SvANY(sstr) && PL_watch_pvx && SvPVX_const(sstr) == PL_watch_pvx)
-       PerlIO_printf(Perl_debug_log, "watch at %p hit, found string \"%s\"\n",
-                     (void*)PL_watch_pvx, SvPVX_const(sstr));
-#endif
+                    Newx(ObjectFIELDS(dsv), fieldcount, SV *);
+                    ObjectMAXFIELD(dsv) = fieldcount - 1;
 
-    /* don't clone objects whose class has asked us not to */
-    if (SvOBJECT(sstr)
-     && ! (SvFLAGS(SvSTASH(sstr)) & SVphv_CLONEABLE))
-    {
-       SvFLAGS(dstr) = 0;
-       return dstr;
+                    sv_dup_inc_multiple(ObjectFIELDS(ssv), ObjectFIELDS(dsv), fieldcount, param);
+                }
+                break;
+            }
+        }
     }
 
-    switch (SvTYPE(sstr)) {
-    case SVt_NULL:
-       SvANY(dstr)     = NULL;
-       break;
-    case SVt_IV:
-       SET_SVANY_FOR_BODYLESS_IV(dstr);
-       if(SvROK(sstr)) {
-           Perl_rvpv_dup(aTHX_ dstr, sstr, param);
-       } else {
-           SvIV_set(dstr, SvIVX(sstr));
-       }
-       break;
-    case SVt_NV:
-#if NVSIZE <= IVSIZE
-       SET_SVANY_FOR_BODYLESS_NV(dstr);
-#else
-       SvANY(dstr)     = new_XNV();
-#endif
-       SvNV_set(dstr, SvNVX(sstr));
-       break;
-    default:
-       {
-           /* These are all the types that need complex bodies allocating.  */
-           void *new_body;
-           const svtype sv_type = SvTYPE(sstr);
-           const struct body_details *const sv_type_details
-               = bodies_by_type + sv_type;
-
-           switch (sv_type) {
-           default:
-               Perl_croak(aTHX_ "Bizarre SvTYPE [%" IVdf "]", (IV)SvTYPE(sstr));
-                NOT_REACHED; /* NOTREACHED */
-               break;
-
-           case SVt_PVGV:
-           case SVt_PVIO:
-           case SVt_PVFM:
-           case SVt_PVHV:
-           case SVt_PVAV:
-           case SVt_PVCV:
-           case SVt_PVLV:
-           case SVt_REGEXP:
-           case SVt_PVMG:
-           case SVt_PVNV:
-           case SVt_PVIV:
-            case SVt_INVLIST:
-           case SVt_PV:
-               assert(sv_type_details->body_size);
-               if (sv_type_details->arena) {
-                   new_body_inline(new_body, sv_type);
-                   new_body
-                       = (void*)((char*)new_body - sv_type_details->offset);
-               } else {
-                   new_body = new_NOARENA(sv_type_details);
-               }
-           }
-           assert(new_body);
-           SvANY(dstr) = new_body;
-
-#ifndef PURIFY
-           Copy(((char*)SvANY(sstr)) + sv_type_details->offset,
-                ((char*)SvANY(dstr)) + sv_type_details->offset,
-                sv_type_details->copy, char);
-#else
-           Copy(((char*)SvANY(sstr)),
-                ((char*)SvANY(dstr)),
-                sv_type_details->body_size + sv_type_details->offset, char);
-#endif
-
-           if (sv_type != SVt_PVAV && sv_type != SVt_PVHV
-               && !isGV_with_GP(dstr)
-               && !isREGEXP(dstr)
-               && !(sv_type == SVt_PVIO && !(IoFLAGS(dstr) & IOf_FAKE_DIRP)))
-               Perl_rvpv_dup(aTHX_ dstr, sstr, param);
-
-           /* The Copy above means that all the source (unduplicated) pointers
-              are now in the destination.  We can check the flags and the
-              pointers in either, but it's possible that there's less cache
-              missing by always going for the destination.
-              FIXME - instrument and check that assumption  */
-           if (sv_type >= SVt_PVMG) {
-               if (SvMAGIC(dstr))
-                   SvMAGIC_set(dstr, mg_dup(SvMAGIC(dstr), param));
-               if (SvOBJECT(dstr) && SvSTASH(dstr))
-                   SvSTASH_set(dstr, hv_dup_inc(SvSTASH(dstr), param));
-               else SvSTASH_set(dstr, 0); /* don't copy DESTROY cache */
-           }
-
-           /* The cast silences a GCC warning about unhandled types.  */
-           switch ((int)sv_type) {
-           case SVt_PV:
-               break;
-           case SVt_PVIV:
-               break;
-           case SVt_PVNV:
-               break;
-           case SVt_PVMG:
-               break;
-           case SVt_REGEXP:
-             duprex:
-               /* FIXME for plugins */
-               re_dup_guts((REGEXP*) sstr, (REGEXP*) dstr, param);
-               break;
-           case SVt_PVLV:
-               /* XXX LvTARGOFF sometimes holds PMOP* when DEBUGGING */
-               if (LvTYPE(dstr) == 't') /* for tie: unrefcnted fake (SV**) */
-                   LvTARG(dstr) = dstr;
-               else if (LvTYPE(dstr) == 'T') /* for tie: fake HE */
-                   LvTARG(dstr) = MUTABLE_SV(he_dup((HE*)LvTARG(dstr), 0, param));
-               else
-                   LvTARG(dstr) = sv_dup_inc(LvTARG(dstr), param);
-               if (isREGEXP(sstr)) goto duprex;
-               /* FALLTHROUGH */
-           case SVt_PVGV:
-               /* non-GP case already handled above */
-               if(isGV_with_GP(sstr)) {
-                   GvNAME_HEK(dstr) = hek_dup(GvNAME_HEK(dstr), param);
-                   /* Don't call sv_add_backref here as it's going to be
-                      created as part of the magic cloning of the symbol
-                      table--unless this is during a join and the stash
-                      is not actually being cloned.  */
-                   /* Danger Will Robinson - GvGP(dstr) isn't initialised
-                      at the point of this comment.  */
-                   GvSTASH(dstr) = hv_dup(GvSTASH(dstr), param);
-                   if (param->flags & CLONEf_JOIN_IN)
-                       Perl_sv_add_backref(aTHX_ MUTABLE_SV(GvSTASH(dstr)), dstr);
-                   GvGP_set(dstr, gp_dup(GvGP(sstr), param));
-                   (void)GpREFCNT_inc(GvGP(dstr));
-               }
-               break;
-           case SVt_PVIO:
-               /* PL_parser->rsfp_filters entries have fake IoDIRP() */
-               if(IoFLAGS(dstr) & IOf_FAKE_DIRP) {
-                   /* I have no idea why fake dirp (rsfps)
-                      should be treated differently but otherwise
-                      we end up with leaks -- sky*/
-                   IoTOP_GV(dstr)      = gv_dup_inc(IoTOP_GV(dstr), param);
-                   IoFMT_GV(dstr)      = gv_dup_inc(IoFMT_GV(dstr), param);
-                   IoBOTTOM_GV(dstr)   = gv_dup_inc(IoBOTTOM_GV(dstr), param);
-               } else {
-                   IoTOP_GV(dstr)      = gv_dup(IoTOP_GV(dstr), param);
-                   IoFMT_GV(dstr)      = gv_dup(IoFMT_GV(dstr), param);
-                   IoBOTTOM_GV(dstr)   = gv_dup(IoBOTTOM_GV(dstr), param);
-                   if (IoDIRP(dstr)) {
-                       IoDIRP(dstr)    = dirp_dup(IoDIRP(dstr), param);
-                   } else {
-                       NOOP;
-                       /* IoDIRP(dstr) is already a copy of IoDIRP(sstr)  */
-                   }
-                   IoIFP(dstr) = fp_dup(IoIFP(sstr), IoTYPE(dstr), param);
-               }
-               if (IoOFP(dstr) == IoIFP(sstr))
-                   IoOFP(dstr) = IoIFP(dstr);
-               else
-                   IoOFP(dstr) = fp_dup(IoOFP(dstr), IoTYPE(dstr), param);
-               IoTOP_NAME(dstr)        = SAVEPV(IoTOP_NAME(dstr));
-               IoFMT_NAME(dstr)        = SAVEPV(IoFMT_NAME(dstr));
-               IoBOTTOM_NAME(dstr)     = SAVEPV(IoBOTTOM_NAME(dstr));
-               break;
-           case SVt_PVAV:
-               /* avoid cloning an empty array */
-               if (AvARRAY((const AV *)sstr) && AvFILLp((const AV *)sstr) >= 0) {
-                   SV **dst_ary, **src_ary;
-                   SSize_t items = AvFILLp((const AV *)sstr) + 1;
-
-                   src_ary = AvARRAY((const AV *)sstr);
-                   Newx(dst_ary, AvMAX((const AV *)sstr)+1, SV*);
-                   ptr_table_store(PL_ptr_table, src_ary, dst_ary);
-                   AvARRAY(MUTABLE_AV(dstr)) = dst_ary;
-                   AvALLOC((const AV *)dstr) = dst_ary;
-                   if (AvREAL((const AV *)sstr)) {
-                       dst_ary = sv_dup_inc_multiple(src_ary, dst_ary, items,
-                                                     param);
-                   }
-                   else {
-                       while (items-- > 0)
-                           *dst_ary++ = sv_dup(*src_ary++, param);
-                   }
-                   items = AvMAX((const AV *)sstr) - AvFILLp((const AV *)sstr);
-                   while (items-- > 0) {
-                       *dst_ary++ = NULL;
-                   }
-               }
-               else {
-                   AvARRAY(MUTABLE_AV(dstr))   = NULL;
-                   AvALLOC((const AV *)dstr)   = (SV**)NULL;
-                   AvMAX(  (const AV *)dstr)   = -1;
-                   AvFILLp((const AV *)dstr)   = -1;
-               }
-               break;
-           case SVt_PVHV:
-               if (HvARRAY((const HV *)sstr)) {
-                   STRLEN i = 0;
-                   const bool sharekeys = !!HvSHAREKEYS(sstr);
-                   XPVHV * const dxhv = (XPVHV*)SvANY(dstr);
-                   XPVHV * const sxhv = (XPVHV*)SvANY(sstr);
-                   char *darray;
-                   Newx(darray, PERL_HV_ARRAY_ALLOC_BYTES(dxhv->xhv_max+1)
-                       + (SvOOK(sstr) ? sizeof(struct xpvhv_aux) : 0),
-                       char);
-                   HvARRAY(dstr) = (HE**)darray;
-                   while (i <= sxhv->xhv_max) {
-                       const HE * const source = HvARRAY(sstr)[i];
-                       HvARRAY(dstr)[i] = source
-                           ? he_dup(source, sharekeys, param) : 0;
-                       ++i;
-                   }
-                   if (SvOOK(sstr)) {
-                       const struct xpvhv_aux * const saux = HvAUX(sstr);
-                       struct xpvhv_aux * const daux = HvAUX(dstr);
-                       /* This flag isn't copied.  */
-                       SvOOK_on(dstr);
-
-                       if (saux->xhv_name_count) {
-                           HEK ** const sname = saux->xhv_name_u.xhvnameu_names;
-                           const I32 count
-                            = saux->xhv_name_count < 0
-                               ? -saux->xhv_name_count
-                               :  saux->xhv_name_count;
-                           HEK **shekp = sname + count;
-                           HEK **dhekp;
-                           Newx(daux->xhv_name_u.xhvnameu_names, count, HEK *);
-                           dhekp = daux->xhv_name_u.xhvnameu_names + count;
-                           while (shekp-- > sname) {
-                               dhekp--;
-                               *dhekp = hek_dup(*shekp, param);
-                           }
-                       }
-                       else {
-                           daux->xhv_name_u.xhvnameu_name
-                               = hek_dup(saux->xhv_name_u.xhvnameu_name,
-                                         param);
-                       }
-                       daux->xhv_name_count = saux->xhv_name_count;
-
-                       daux->xhv_aux_flags = saux->xhv_aux_flags;
-#ifdef PERL_HASH_RANDOMIZE_KEYS
-                       daux->xhv_rand = saux->xhv_rand;
-                       daux->xhv_last_rand = saux->xhv_last_rand;
-#endif
-                       daux->xhv_riter = saux->xhv_riter;
-                       daux->xhv_eiter = saux->xhv_eiter
-                           ? he_dup(saux->xhv_eiter,
-                                       cBOOL(HvSHAREKEYS(sstr)), param) : 0;
-                       /* backref array needs refcnt=2; see sv_add_backref */
-                       daux->xhv_backreferences =
-                           (param->flags & CLONEf_JOIN_IN)
-                               /* when joining, we let the individual GVs and
-                                * CVs add themselves to backref as
-                                * needed. This avoids pulling in stuff
-                                * that isn't required, and simplifies the
-                                * case where stashes aren't cloned back
-                                * if they already exist in the parent
-                                * thread */
-                           ? NULL
-                           : saux->xhv_backreferences
-                               ? (SvTYPE(saux->xhv_backreferences) == SVt_PVAV)
-                                   ? MUTABLE_AV(SvREFCNT_inc(
-                                         sv_dup_inc((const SV *)
-                                           saux->xhv_backreferences, param)))
-                                   : MUTABLE_AV(sv_dup((const SV *)
-                                           saux->xhv_backreferences, param))
-                               : 0;
-
-                        daux->xhv_mro_meta = saux->xhv_mro_meta
-                            ? mro_meta_dup(saux->xhv_mro_meta, param)
-                            : 0;
-
-                       /* Record stashes for possible cloning in Perl_clone(). */
-                       if (HvNAME(sstr))
-                           av_push(param->stashes, dstr);
-                   }
-               }
-               else
-                   HvARRAY(MUTABLE_HV(dstr)) = NULL;
-               break;
-           case SVt_PVCV:
-               if (!(param->flags & CLONEf_COPY_STACKS)) {
-                   CvDEPTH(dstr) = 0;
-               }
-               /* FALLTHROUGH */
-           case SVt_PVFM:
-               /* NOTE: not refcounted */
-               SvANY(MUTABLE_CV(dstr))->xcv_stash =
-                   hv_dup(CvSTASH(dstr), param);
-               if ((param->flags & CLONEf_JOIN_IN) && CvSTASH(dstr))
-                   Perl_sv_add_backref(aTHX_ MUTABLE_SV(CvSTASH(dstr)), dstr);
-               if (!CvISXSUB(dstr)) {
-                   OP_REFCNT_LOCK;
-                   CvROOT(dstr) = OpREFCNT_inc(CvROOT(dstr));
-                   OP_REFCNT_UNLOCK;
-                   CvSLABBED_off(dstr);
-               } else if (CvCONST(dstr)) {
-                   CvXSUBANY(dstr).any_ptr =
-                       sv_dup_inc((const SV *)CvXSUBANY(dstr).any_ptr, param);
-               }
-               assert(!CvSLABBED(dstr));
-               if (CvDYNFILE(dstr)) CvFILE(dstr) = SAVEPV(CvFILE(dstr));
-               if (CvNAMED(dstr))
-                   SvANY((CV *)dstr)->xcv_gv_u.xcv_hek =
-                       hek_dup(CvNAME_HEK((CV *)sstr), 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 */
-               else
-                 SvANY(MUTABLE_CV(dstr))->xcv_gv_u.xcv_gv =
-                   CvCVGV_RC(dstr)
-                   ? gv_dup_inc(CvGV(sstr), param)
-                   : (param->flags & CLONEf_JOIN_IN)
-                       ? NULL
-                       : gv_dup(CvGV(sstr), param);
-
-               if (!CvISXSUB(sstr)) {
-                   PADLIST * padlist = CvPADLIST(sstr);
-                   if(padlist)
-                       padlist = padlist_dup(padlist, param);
-                   CvPADLIST_set(dstr, padlist);
-               } else
-/* unthreaded perl can't sv_dup so we dont support unthreaded's CvHSCXT */
-                   PoisonPADLIST(dstr);
-
-               CvOUTSIDE(dstr) =
-                   CvWEAKOUTSIDE(sstr)
-                   ? cv_dup(    CvOUTSIDE(dstr), param)
-                   : cv_dup_inc(CvOUTSIDE(dstr), param);
-               break;
-           }
-       }
-    }
-
-    return dstr;
+    return dsv;
  }
 
 SV *
-Perl_sv_dup_inc(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
+Perl_sv_dup_inc(pTHX_ const SV *const ssv, CLONE_PARAMS *const param)
 {
     PERL_ARGS_ASSERT_SV_DUP_INC;
-    return sstr ? SvREFCNT_inc(sv_dup_common(sstr, param)) : NULL;
+    return ssv ? SvREFCNT_inc(sv_dup_common(ssv, param)) : NULL;
 }
 
 SV *
-Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
+Perl_sv_dup(pTHX_ const SV *const ssv, CLONE_PARAMS *const param)
 {
-    SV *dstr = sstr ? sv_dup_common(sstr, param) : NULL;
+    SV *dsv = ssv ? sv_dup_common(ssv, param) : NULL;
     PERL_ARGS_ASSERT_SV_DUP;
 
     /* Track every SV that (at least initially) had a reference count of 0.
@@ -14540,12 +14977,12 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
        added to the temps stack. At which point we have the same SV considered
        to be in use, and free to be re-used. Not good.
     */
-    if (dstr && !(param->flags & CLONEf_COPY_STACKS) && !SvREFCNT(dstr)) {
-       assert(param->unreferenced);
-       av_push(param->unreferenced, SvREFCNT_inc(dstr));
+    if (dsv && !(param->flags & CLONEf_COPY_STACKS) && !SvREFCNT(dsv)) {
+        assert(param->unreferenced);
+        av_push(param->unreferenced, SvREFCNT_inc(dsv));
     }
 
-    return dstr;
+    return dsv;
 }
 
 /* duplicate a context */
@@ -14558,12 +14995,12 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max, CLONE_PARAMS* param)
     PERL_ARGS_ASSERT_CX_DUP;
 
     if (!cxs)
-       return (PERL_CONTEXT*)NULL;
+        return (PERL_CONTEXT*)NULL;
 
     /* look for it in the table first */
     ncxs = (PERL_CONTEXT*)ptr_table_fetch(PL_ptr_table, cxs);
     if (ncxs)
-       return ncxs;
+        return ncxs;
 
     /* create anew and remember what it is */
     Newx(ncxs, max + 1, PERL_CONTEXT);
@@ -14571,97 +15008,104 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max, CLONE_PARAMS* param)
     Copy(cxs, ncxs, max + 1, PERL_CONTEXT);
 
     while (ix >= 0) {
-       PERL_CONTEXT * const ncx = &ncxs[ix];
-       if (CxTYPE(ncx) == CXt_SUBST) {
-           Perl_croak(aTHX_ "Cloning substitution context is unimplemented");
-       }
-       else {
-           ncx->blk_oldcop = (COP*)any_dup(ncx->blk_oldcop, param->proto_perl);
-           switch (CxTYPE(ncx)) {
-           case CXt_SUB:
-               ncx->blk_sub.cv         = cv_dup_inc(ncx->blk_sub.cv, param);
-               if(CxHASARGS(ncx)){
-                   ncx->blk_sub.savearray = av_dup_inc(ncx->blk_sub.savearray,param);
-               } else {
-                   ncx->blk_sub.savearray = NULL;
-               }
-               ncx->blk_sub.prevcomppad = (PAD*)ptr_table_fetch(PL_ptr_table,
-                                          ncx->blk_sub.prevcomppad);
-               break;
-           case CXt_EVAL:
-               ncx->blk_eval.old_namesv = sv_dup_inc(ncx->blk_eval.old_namesv,
-                                                     param);
+        PERL_CONTEXT * const ncx = &ncxs[ix];
+        if (CxTYPE(ncx) == CXt_SUBST) {
+            Perl_croak(aTHX_ "Cloning substitution context is unimplemented");
+        }
+        else {
+            ncx->blk_oldcop = (COP*)any_dup(ncx->blk_oldcop, param->proto_perl);
+            switch (CxTYPE(ncx)) {
+            case CXt_SUB:
+                ncx->blk_sub.cv                = cv_dup_inc(ncx->blk_sub.cv, param);
+                if(CxHASARGS(ncx)){
+                    ncx->blk_sub.savearray = av_dup_inc(ncx->blk_sub.savearray,param);
+                } else {
+                    ncx->blk_sub.savearray = NULL;
+                }
+                ncx->blk_sub.prevcomppad = (PAD*)ptr_table_fetch(PL_ptr_table,
+                                           ncx->blk_sub.prevcomppad);
+                break;
+            case CXt_EVAL:
+                ncx->blk_eval.old_namesv = sv_dup_inc(ncx->blk_eval.old_namesv,
+                                                      param);
                 /* XXX should this sv_dup_inc? Or only if CxEVAL_TXT_REFCNTED ???? */
-               ncx->blk_eval.cur_text  = sv_dup(ncx->blk_eval.cur_text, param);
-               ncx->blk_eval.cv = cv_dup(ncx->blk_eval.cv, param);
-                /* XXX what do do with cur_top_env ???? */
-               break;
-           case CXt_LOOP_LAZYSV:
-               ncx->blk_loop.state_u.lazysv.end
-                   = sv_dup_inc(ncx->blk_loop.state_u.lazysv.end, param);
+                ncx->blk_eval.cur_text = sv_dup(ncx->blk_eval.cur_text, param);
+                ncx->blk_eval.cv = cv_dup(ncx->blk_eval.cv, param);
+                /* XXX what to do with cur_top_env ???? */
+                break;
+            case CXt_LOOP_LAZYSV:
+                ncx->blk_loop.state_u.lazysv.end
+                    = sv_dup_inc(ncx->blk_loop.state_u.lazysv.end, param);
                 /* Fallthrough: duplicate lazysv.cur by using the ary.ary
                    duplication code instead.
                    We are taking advantage of (1) av_dup_inc and sv_dup_inc
                    actually being the same function, and (2) order
                    equivalence 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);
+                   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);
                 /* FALLTHROUGH */
-           case CXt_LOOP_ARY:
-               ncx->blk_loop.state_u.ary.ary
-                   = av_dup_inc(ncx->blk_loop.state_u.ary.ary, param);
+            case CXt_LOOP_ARY:
+                ncx->blk_loop.state_u.ary.ary
+                    = av_dup_inc(ncx->blk_loop.state_u.ary.ary, param);
                 /* FALLTHROUGH */
-           case CXt_LOOP_LIST:
-           case CXt_LOOP_LAZYIV:
+            case CXt_LOOP_LIST:
+            case CXt_LOOP_LAZYIV:
                 /* code common to all 'for' CXt_LOOP_* types */
-               ncx->blk_loop.itersave =
+                ncx->blk_loop.itersave =
                                     sv_dup_inc(ncx->blk_loop.itersave, param);
-               if (CxPADLOOP(ncx)) {
+                if (CxPADLOOP(ncx)) {
                     PADOFFSET off = ncx->blk_loop.itervar_u.svp
                                     - &CX_CURPAD_SV(ncx->blk_loop, 0);
                     ncx->blk_loop.oldcomppad =
                                     (PAD*)ptr_table_fetch(PL_ptr_table,
                                                 ncx->blk_loop.oldcomppad);
-                   ncx->blk_loop.itervar_u.svp =
+                    ncx->blk_loop.itervar_u.svp =
                                     &CX_CURPAD_SV(ncx->blk_loop, off);
                 }
-               else {
+                else {
                     /* this copies the GV if CXp_FOR_GV, or the SV for an
                      * alias (for \$x (...)) - relies on gv_dup being the
                      * same as sv_dup */
-                   ncx->blk_loop.itervar_u.gv
-                       = gv_dup((const GV *)ncx->blk_loop.itervar_u.gv,
-                                   param);
-               }
-               break;
-           case CXt_LOOP_PLAIN:
-               break;
-           case CXt_FORMAT:
-               ncx->blk_format.prevcomppad =
+                    ncx->blk_loop.itervar_u.gv
+                        = gv_dup((const GV *)ncx->blk_loop.itervar_u.gv,
+                                    param);
+                }
+                break;
+            case CXt_LOOP_PLAIN:
+                break;
+            case CXt_FORMAT:
+                ncx->blk_format.prevcomppad =
                         (PAD*)ptr_table_fetch(PL_ptr_table,
-                                          ncx->blk_format.prevcomppad);
-               ncx->blk_format.cv      = cv_dup_inc(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_GIVEN:
-               ncx->blk_givwhen.defsv_save =
+                                           ncx->blk_format.prevcomppad);
+                ncx->blk_format.cv     = cv_dup_inc(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_GIVEN:
+                ncx->blk_givwhen.defsv_save =
                                 sv_dup_inc(ncx->blk_givwhen.defsv_save, param);
-               break;
-           case CXt_BLOCK:
-           case CXt_NULL:
-           case CXt_WHEN:
-               break;
-           }
-       }
-       --ix;
+                break;
+            case CXt_BLOCK:
+            case CXt_NULL:
+            case CXt_WHEN:
+            case CXt_DEFER:
+                break;
+            }
+        }
+        --ix;
     }
     return ncxs;
 }
 
-/* duplicate a stack info structure */
+/*
+=for apidoc si_dup
+
+Duplicate a stack info structure, returning a pointer to the cloned object.
+
+=cut
+*/
 
 PERL_SI *
 Perl_si_dup(pTHX_ PERL_SI *si, CLONE_PARAMS* param)
@@ -14671,12 +15115,12 @@ Perl_si_dup(pTHX_ PERL_SI *si, CLONE_PARAMS* param)
     PERL_ARGS_ASSERT_SI_DUP;
 
     if (!si)
-       return (PERL_SI*)NULL;
+        return (PERL_SI*)NULL;
 
     /* look for it in the table first */
     nsi = (PERL_SI*)ptr_table_fetch(PL_ptr_table, si);
     if (nsi)
-       return nsi;
+        return nsi;
 
     /* create anew and remember what it is */
     Newx(nsi, 1, PERL_SI);
@@ -14691,6 +15135,9 @@ Perl_si_dup(pTHX_ PERL_SI *si, CLONE_PARAMS* param)
     nsi->si_prev       = si_dup(si->si_prev, param);
     nsi->si_next       = si_dup(si->si_next, param);
     nsi->si_markoff    = si->si_markoff;
+#ifdef PERL_RC_STACK
+    nsi->si_stack_nonrc_base = si->si_stack_nonrc_base;
+#endif
 #if defined DEBUGGING && !defined DEBUGGING_RE_ONLY
     nsi->si_stack_hwm   = 0;
 #endif
@@ -14720,7 +15167,7 @@ Perl_si_dup(pTHX_ PERL_SI *si, CLONE_PARAMS* param)
 #define pv_dup(p)      SAVEPV(p)
 #define svp_dup_inc(p,pp)      any_dup(p,pp)
 
-/* map any object to the new equivent - either something in the
+/* map any object to the new equivalent - either something in the
  * ptr table, or something in the interpreter structure
  */
 
@@ -14732,29 +15179,34 @@ Perl_any_dup(pTHX_ void *v, const PerlInterpreter *proto_perl)
     PERL_ARGS_ASSERT_ANY_DUP;
 
     if (!v)
-       return (void*)NULL;
+        return (void*)NULL;
 
     /* look for it in the table first */
     ret = ptr_table_fetch(PL_ptr_table, v);
     if (ret)
-       return ret;
+        return ret;
 
     /* see if it is part of the interpreter structure */
     if (v >= (void*)proto_perl && v < (void*)(proto_perl+1))
-       ret = (void*)(((char*)aTHX) + (((char*)v) - (char*)proto_perl));
+        ret = (void*)(((char*)aTHX) + (((char*)v) - (char*)proto_perl));
     else {
-       ret = v;
+        ret = v;
     }
 
     return ret;
 }
 
-/* duplicate the save stack */
+/*
+=for apidoc ss_dup
+
+Duplicate the save stack, returning a pointer to the cloned object.
+
+=cut
+*/
 
 ANY *
 Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
 {
-    dVAR;
     ANY * const ss     = proto_perl->Isavestack;
     const I32 max      = proto_perl->Isavestack_max + SS_MAXPUSH;
     I32 ix             = proto_perl->Isavestack_ix;
@@ -14763,6 +15215,7 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
     const GV *gv;
     const AV *av;
     const HV *hv;
+    char *pv; /* no const deliberately */
     void* ptr;
     int intval;
     long longval;
@@ -14778,254 +15231,273 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
     Newx(nss, max, ANY);
 
     while (ix > 0) {
-       const UV uv = POPUV(ss,ix);
-       const U8 type = (U8)uv & SAVE_MASK;
-
-       TOPUV(nss,ix) = uv;
-       switch (type) {
-       case SAVEt_CLEARSV:
-       case SAVEt_CLEARPADRANGE:
-           break;
-       case SAVEt_HELEM:               /* hash element */
-       case SAVEt_SV:                  /* scalar reference */
-           sv = (const SV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = SvREFCNT_inc(sv_dup_inc(sv, param));
-           /* FALLTHROUGH */
-       case SAVEt_ITEM:                        /* normal string */
+        const UV uv = POPUV(ss,ix);
+        const U8 type = (U8)uv & SAVE_MASK;
+
+        TOPUV(nss,ix) = uv;
+        switch (type) {
+        case SAVEt_CLEARSV:
+        case SAVEt_CLEARPADRANGE:
+            break;
+        case SAVEt_HELEM:              /* hash element */
+        case SAVEt_SV:                 /* scalar reference */
+            sv = (const SV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = SvREFCNT_inc(sv_dup_inc(sv, param));
+            /* FALLTHROUGH */
+        case SAVEt_ITEM:                       /* normal string */
         case SAVEt_GVSV:                       /* scalar slot in GV */
-           sv = (const SV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup_inc(sv, param);
-           if (type == SAVEt_SV)
-               break;
-           /* FALLTHROUGH */
-       case SAVEt_FREESV:
-       case SAVEt_MORTALIZESV:
-       case SAVEt_READONLY_OFF:
-           sv = (const SV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup_inc(sv, param);
-           break;
-       case SAVEt_FREEPADNAME:
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = padname_dup((PADNAME *)ptr, param);
-           PadnameREFCNT((PADNAME *)TOPPTR(nss,ix))++;
-           break;
-       case SAVEt_SHARED_PVREF:                /* char* in shared space */
-           c = (char*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = savesharedpv(c);
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           break;
+            sv = (const SV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
+            if (type == SAVEt_SV)
+                break;
+            /* FALLTHROUGH */
+        case SAVEt_FREESV:
+        case SAVEt_MORTALIZESV:
+        case SAVEt_READONLY_OFF:
+            sv = (const SV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
+            break;
+        case SAVEt_FREEPADNAME:
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = padname_dup((PADNAME *)ptr, param);
+            PadnameREFCNT((PADNAME *)TOPPTR(nss,ix))++;
+            break;
+        case SAVEt_SHARED_PVREF:               /* char* in shared space */
+            c = (char*)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = savesharedpv(c);
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+            break;
         case SAVEt_GENERIC_SVREF:              /* generic sv */
         case SAVEt_SVREF:                      /* scalar reference */
-           sv = (const SV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup_inc(sv, param);
-           if (type == SAVEt_SVREF)
-               SvREFCNT_inc_simple_void((SV *)TOPPTR(nss,ix));
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = svp_dup_inc((SV**)ptr, proto_perl);/* XXXXX */
-           break;
+            sv = (const SV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
+            if (type == SAVEt_SVREF)
+                SvREFCNT_inc_simple_void((SV *)TOPPTR(nss,ix));
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = svp_dup_inc((SV**)ptr, proto_perl);/* XXXXX */
+            /* this feels very strange, we have a **SV from one thread,
+             * we copy the SV, but dont change the **SV. But in this thread
+             * the target of the **SV could be something from the *other* thread.
+             * So how can this possibly work correctly? */
+            break;
+        case SAVEt_RCPV:
+            pv = (char *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = rcpv_copy(pv);
+            ptr = POPPTR(ss,ix);
+            (void)rcpv_copy(*((char **)ptr));
+            TOPPTR(nss,ix) = ptr;
+            /* XXXXX: see comment above. */
+            break;
         case SAVEt_GVSLOT:             /* any slot in GV */
-           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 */
-           sv = (const SV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup_inc(sv, param);
-           break;
+            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 */
+            sv = (const SV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
+            break;
         case SAVEt_HV:                         /* hash reference */
         case SAVEt_AV:                         /* array reference */
-           sv = (const SV *) POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup_inc(sv, param);
-           /* FALLTHROUGH */
-       case SAVEt_COMPPAD:
-       case SAVEt_NSTAB:
-           sv = (const SV *) POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup(sv, param);
-           break;
-       case SAVEt_INT:                         /* int reference */
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           intval = (int)POPINT(ss,ix);
-           TOPINT(nss,ix) = intval;
-           break;
-       case SAVEt_LONG:                        /* long reference */
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           longval = (long)POPLONG(ss,ix);
-           TOPLONG(nss,ix) = longval;
-           break;
-       case SAVEt_I32:                         /* I32 reference */
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           i = POPINT(ss,ix);
-           TOPINT(nss,ix) = i;
-           break;
-       case SAVEt_IV:                          /* IV reference */
-       case SAVEt_STRLEN:                      /* STRLEN/size_t ref */
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           iv = POPIV(ss,ix);
-           TOPIV(nss,ix) = iv;
-           break;
-       case SAVEt_TMPSFLOOR:
-           iv = POPIV(ss,ix);
-           TOPIV(nss,ix) = iv;
-           break;
-       case SAVEt_HPTR:                        /* HV* reference */
-       case SAVEt_APTR:                        /* AV* reference */
-       case SAVEt_SPTR:                        /* SV* reference */
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           sv = (const SV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup(sv, param);
-           break;
-       case SAVEt_VPTR:                        /* random* reference */
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           /* FALLTHROUGH */
-       case SAVEt_INT_SMALL:
-       case SAVEt_I32_SMALL:
-       case SAVEt_I16:                         /* I16 reference */
-       case SAVEt_I8:                          /* I8 reference */
-       case SAVEt_BOOL:
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           break;
-       case SAVEt_GENERIC_PVREF:               /* generic char* */
-       case SAVEt_PPTR:                        /* char* reference */
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           c = (char*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = pv_dup(c);
-           break;
-       case SAVEt_GP:                          /* scalar reference */
-           gp = (GP*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = gp = gp_dup(gp, param);
-           (void)GpREFCNT_inc(gp);
-           gv = (const GV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = gv_dup_inc(gv, param);
-           break;
-       case SAVEt_FREEOP:
-           ptr = POPPTR(ss,ix);
-           if (ptr && (((OP*)ptr)->op_private & OPpREFCOUNTED)) {
-               /* these are assumed to be refcounted properly */
-               OP *o;
-               switch (((OP*)ptr)->op_type) {
-               case OP_LEAVESUB:
-               case OP_LEAVESUBLV:
-               case OP_LEAVEEVAL:
-               case OP_LEAVE:
-               case OP_SCOPE:
-               case OP_LEAVEWRITE:
-                   TOPPTR(nss,ix) = ptr;
-                   o = (OP*)ptr;
-                   OP_REFCNT_LOCK;
-                   (void) OpREFCNT_inc(o);
-                   OP_REFCNT_UNLOCK;
-                   break;
-               default:
-                   TOPPTR(nss,ix) = NULL;
-                   break;
-               }
-           }
-           else
-               TOPPTR(nss,ix) = NULL;
-           break;
-       case SAVEt_FREECOPHH:
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = cophh_copy((COPHH *)ptr);
-           break;
-       case SAVEt_ADELETE:
-           av = (const AV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = av_dup_inc(av, param);
-           i = POPINT(ss,ix);
-           TOPINT(nss,ix) = i;
-           break;
-       case SAVEt_DELETE:
-           hv = (const HV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = hv_dup_inc(hv, param);
-           i = POPINT(ss,ix);
-           TOPINT(nss,ix) = i;
-           /* FALLTHROUGH */
-       case SAVEt_FREEPV:
-           c = (char*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = pv_dup_inc(c);
-           break;
-       case SAVEt_STACK_POS:           /* Position on Perl stack */
-           i = POPINT(ss,ix);
-           TOPINT(nss,ix) = i;
-           break;
-       case SAVEt_DESTRUCTOR:
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);  /* XXX quite arbitrary */
-           dptr = POPDPTR(ss,ix);
-           TOPDPTR(nss,ix) = DPTR2FPTR(void (*)(void*),
-                                       any_dup(FPTR2DPTR(void *, dptr),
-                                               proto_perl));
-           break;
-       case SAVEt_DESTRUCTOR_X:
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);  /* XXX quite arbitrary */
-           dxptr = POPDXPTR(ss,ix);
-           TOPDXPTR(nss,ix) = DPTR2FPTR(void (*)(pTHX_ void*),
-                                        any_dup(FPTR2DPTR(void *, dxptr),
-                                                proto_perl));
-           break;
-       case SAVEt_REGCONTEXT:
-       case SAVEt_ALLOC:
-           ix -= uv >> SAVE_TIGHT_SHIFT;
-           break;
-       case SAVEt_AELEM:               /* array element */
-           sv = (const SV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = SvREFCNT_inc(sv_dup_inc(sv, param));
-           iv = POPIV(ss,ix);
-           TOPIV(nss,ix) = iv;
-           av = (const AV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = av_dup_inc(av, param);
-           break;
-       case SAVEt_OP:
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = ptr;
-           break;
-       case SAVEt_HINTS:
-           ptr = POPPTR(ss,ix);
-           ptr = cophh_copy((COPHH*)ptr);
-           TOPPTR(nss,ix) = ptr;
-           i = POPINT(ss,ix);
-           TOPINT(nss,ix) = i;
-           if (i & HINT_LOCALIZE_HH) {
-               hv = (const HV *)POPPTR(ss,ix);
-               TOPPTR(nss,ix) = hv_dup_inc(hv, param);
-           }
-           break;
-       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 = (const SV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup_inc(sv, param);
-           break;
-       case SAVEt_SET_SVFLAGS:
-           i = POPINT(ss,ix);
-           TOPINT(nss,ix) = i;
-           i = POPINT(ss,ix);
-           TOPINT(nss,ix) = i;
-           sv = (const SV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup(sv, param);
-           break;
-       case SAVEt_COMPILE_WARNINGS:
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = DUP_WARNINGS((STRLEN*)ptr);
-           break;
-       case SAVEt_PARSER:
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = parser_dup((const yy_parser*)ptr, param);
-           break;
-       default:
-           Perl_croak(aTHX_
-                      "panic: ss_dup inconsistency (%" IVdf ")", (IV) type);
-       }
+            sv = (const SV *) POPPTR(ss,ix);
+            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
+            /* FALLTHROUGH */
+        case SAVEt_COMPPAD:
+        case SAVEt_NSTAB:
+            sv = (const SV *) POPPTR(ss,ix);
+            TOPPTR(nss,ix) = sv_dup(sv, param);
+            break;
+        case SAVEt_INT:                                /* int reference */
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+            intval = (int)POPINT(ss,ix);
+            TOPINT(nss,ix) = intval;
+            break;
+        case SAVEt_LONG:                       /* long reference */
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+            longval = (long)POPLONG(ss,ix);
+            TOPLONG(nss,ix) = longval;
+            break;
+        case SAVEt_I32:                                /* I32 reference */
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+            i = POPINT(ss,ix);
+            TOPINT(nss,ix) = i;
+            break;
+        case SAVEt_IV:                         /* IV reference */
+        case SAVEt_STRLEN:                     /* STRLEN/size_t ref */
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+            iv = POPIV(ss,ix);
+            TOPIV(nss,ix) = iv;
+            break;
+        case SAVEt_TMPSFLOOR:
+            iv = POPIV(ss,ix);
+            TOPIV(nss,ix) = iv;
+            break;
+        case SAVEt_HPTR:                       /* HV* reference */
+        case SAVEt_APTR:                       /* AV* reference */
+        case SAVEt_SPTR:                       /* SV* reference */
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+            sv = (const SV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = sv_dup(sv, param);
+            break;
+        case SAVEt_VPTR:                       /* random* reference */
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+            /* FALLTHROUGH */
+        case SAVEt_STRLEN_SMALL:
+        case SAVEt_INT_SMALL:
+        case SAVEt_I32_SMALL:
+        case SAVEt_I16:                                /* I16 reference */
+        case SAVEt_I8:                         /* I8 reference */
+        case SAVEt_BOOL:
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+            break;
+        case SAVEt_GENERIC_PVREF:              /* generic char* */
+        case SAVEt_PPTR:                       /* char* reference */
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+            c = (char*)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = pv_dup(c);
+            break;
+        case SAVEt_GP:                         /* scalar reference */
+            gp = (GP*)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = gp = gp_dup(gp, param);
+            (void)GpREFCNT_inc(gp);
+            gv = (const GV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = gv_dup_inc(gv, param);
+            break;
+        case SAVEt_FREEOP:
+            ptr = POPPTR(ss,ix);
+            if (ptr && (((OP*)ptr)->op_private & OPpREFCOUNTED)) {
+                /* these are assumed to be refcounted properly */
+                OP *o;
+                switch (((OP*)ptr)->op_type) {
+                case OP_LEAVESUB:
+                case OP_LEAVESUBLV:
+                case OP_LEAVEEVAL:
+                case OP_LEAVE:
+                case OP_SCOPE:
+                case OP_LEAVEWRITE:
+                    TOPPTR(nss,ix) = ptr;
+                    o = (OP*)ptr;
+                    OP_REFCNT_LOCK;
+                    (void) OpREFCNT_inc(o);
+                    OP_REFCNT_UNLOCK;
+                    break;
+                default:
+                    TOPPTR(nss,ix) = NULL;
+                    break;
+                }
+            }
+            else
+                TOPPTR(nss,ix) = NULL;
+            break;
+        case SAVEt_FREECOPHH:
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = cophh_copy((COPHH *)ptr);
+            break;
+        case SAVEt_ADELETE:
+            av = (const AV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = av_dup_inc(av, param);
+            i = POPINT(ss,ix);
+            TOPINT(nss,ix) = i;
+            break;
+        case SAVEt_DELETE:
+            hv = (const HV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = hv_dup_inc(hv, param);
+            i = POPINT(ss,ix);
+            TOPINT(nss,ix) = i;
+            /* FALLTHROUGH */
+        case SAVEt_FREEPV:
+            c = (char*)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = pv_dup_inc(c);
+            break;
+        case SAVEt_FREERCPV:
+            c = (char *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = rcpv_copy(c);
+            break;
+        case SAVEt_STACK_POS:          /* Position on Perl stack */
+            i = POPINT(ss,ix);
+            TOPINT(nss,ix) = i;
+            break;
+        case SAVEt_DESTRUCTOR:
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = any_dup(ptr, proto_perl); /* XXX quite arbitrary */
+            dptr = POPDPTR(ss,ix);
+            TOPDPTR(nss,ix) = DPTR2FPTR(void (*)(void*),
+                                        any_dup(FPTR2DPTR(void *, dptr),
+                                                proto_perl));
+            break;
+        case SAVEt_DESTRUCTOR_X:
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = any_dup(ptr, proto_perl); /* XXX quite arbitrary */
+            dxptr = POPDXPTR(ss,ix);
+            TOPDXPTR(nss,ix) = DPTR2FPTR(void (*)(pTHX_ void*),
+                                         any_dup(FPTR2DPTR(void *, dxptr),
+                                                 proto_perl));
+            break;
+        case SAVEt_REGCONTEXT:
+        case SAVEt_ALLOC:
+            ix -= uv >> SAVE_TIGHT_SHIFT;
+            break;
+        case SAVEt_AELEM:              /* array element */
+            sv = (const SV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = SvREFCNT_inc(sv_dup_inc(sv, param));
+            iv = POPIV(ss,ix);
+            TOPIV(nss,ix) = iv;
+            av = (const AV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = av_dup_inc(av, param);
+            break;
+        case SAVEt_OP:
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = ptr;
+            break;
+        case SAVEt_HINTS_HH:
+            hv = (const HV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = hv_dup_inc(hv, param);
+            /* FALLTHROUGH */
+        case SAVEt_HINTS:
+            ptr = POPPTR(ss,ix);
+            ptr = cophh_copy((COPHH*)ptr);
+            TOPPTR(nss,ix) = ptr;
+            i = POPINT(ss,ix);
+            TOPINT(nss,ix) = i;
+            break;
+        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 = (const SV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
+            break;
+        case SAVEt_SET_SVFLAGS:
+            i = POPINT(ss,ix);
+            TOPINT(nss,ix) = i;
+            i = POPINT(ss,ix);
+            TOPINT(nss,ix) = i;
+            sv = (const SV *)POPPTR(ss,ix);
+            TOPPTR(nss,ix) = sv_dup(sv, param);
+            break;
+        case SAVEt_CURCOP_WARNINGS:
+            /* FALLTHROUGH */
+        case SAVEt_COMPILE_WARNINGS:
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = DUP_WARNINGS((char*)ptr);
+            break;
+        case SAVEt_PARSER:
+            ptr = POPPTR(ss,ix);
+            TOPPTR(nss,ix) = parser_dup((const yy_parser*)ptr, param);
+            break;
+        default:
+            Perl_croak(aTHX_
+                       "panic: ss_dup inconsistency (%" IVdf ")", (IV) type);
+        }
     }
 
     return nss;
@@ -15041,26 +15513,26 @@ do_mark_cloneable_stash(pTHX_ SV *const sv)
 {
     const HEK * const hvname = HvNAME_HEK((const HV *)sv);
     if (hvname) {
-       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;
-           UV status;
-
-           ENTER;
-           SAVETMPS;
-           PUSHMARK(SP);
-           mXPUSHs(newSVhek(hvname));
-           PUTBACK;
-           call_sv(MUTABLE_SV(GvCV(cloner)), G_SCALAR);
-           SPAGAIN;
-           status = POPu;
-           PUTBACK;
-           FREETMPS;
-           LEAVE;
-           if (status)
-               SvFLAGS(sv) &= ~SVphv_CLONEABLE;
-       }
+        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;
+            UV status;
+
+            ENTER;
+            SAVETMPS;
+            PUSHMARK(SP);
+            mXPUSHs(newSVhek(hvname));
+            PUTBACK;
+            call_sv(MUTABLE_SV(GvCV(cloner)), G_SCALAR);
+            SPAGAIN;
+            status = POPu;
+            PUTBACK;
+            FREETMPS;
+            LEAVE;
+            if (status)
+                SvFLAGS(sv) &= ~SVphv_CLONEABLE;
+        }
     }
 }
 
@@ -15109,7 +15581,6 @@ perl_clone_host(PerlInterpreter* proto_perl, UV flags);
 PerlInterpreter *
 perl_clone(PerlInterpreter *proto_perl, UV flags)
 {
-   dVAR;
 #ifdef PERL_IMPLICIT_SYS
 
     PERL_ARGS_ASSERT_PERL_CLONE;
@@ -15123,24 +15594,24 @@ perl_clone(PerlInterpreter *proto_perl, UV flags)
    }
 #endif
    return perl_clone_using(proto_perl, flags,
-                           proto_perl->IMem,
-                           proto_perl->IMemShared,
-                           proto_perl->IMemParse,
-                           proto_perl->IEnv,
-                           proto_perl->IStdIO,
-                           proto_perl->ILIO,
-                           proto_perl->IDir,
-                           proto_perl->ISock,
-                           proto_perl->IProc);
+                            proto_perl->IMem,
+                            proto_perl->IMemShared,
+                            proto_perl->IMemParse,
+                            proto_perl->IEnv,
+                            proto_perl->IStdIO,
+                            proto_perl->ILIO,
+                            proto_perl->IDir,
+                            proto_perl->ISock,
+                            proto_perl->IProc);
 }
 
 PerlInterpreter *
 perl_clone_using(PerlInterpreter *proto_perl, UV flags,
-                struct IPerlMem* ipM, struct IPerlMem* ipMS,
-                struct IPerlMem* ipMP, struct IPerlEnv* ipE,
-                struct IPerlStdIO* ipStd, struct IPerlLIO* ipLIO,
-                struct IPerlDir* ipD, struct IPerlSock* ipS,
-                struct IPerlProc* ipP)
+                 struct IPerlMem* ipM, struct IPerlMem* ipMS,
+                 struct IPerlMem* ipMP, struct IPerlEnv* ipE,
+                 struct IPerlStdIO* ipStd, struct IPerlLIO* ipLIO,
+                 struct IPerlDir* ipD, struct IPerlSock* ipS,
+                 struct IPerlProc* ipP)
 {
     /* XXX many of the string copies here can be optimized if they're
      * constants; they need to be allocated as common memory and just
@@ -15164,6 +15635,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     /* for each stash, determine whether its objects should be cloned */
     S_visit(proto_perl, do_mark_cloneable_stash, SVt_PVHV, SVTYPEMASK);
+    my_perl->Iphase = PERL_PHASE_CONSTRUCT;
     PERL_SET_THX(my_perl);
 
 #ifdef DEBUGGING
@@ -15179,6 +15651,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_savestack_max = -1;
     PL_sig_pending = 0;
     PL_parser = NULL;
+    PL_eval_begin_nest_depth = proto_perl->Ieval_begin_nest_depth;
     Zero(&PL_debug_pad, 1, struct perl_debug_pad);
     Zero(&PL_padname_undef, 1, PADNAME);
     Zero(&PL_padname_const, 1, PADNAME);
@@ -15220,7 +15693,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     PL_body_arenas = NULL;
     Zero(&PL_body_roots, 1, PL_body_roots);
-    
+
     PL_sv_count                = 0;
     PL_sv_root         = NULL;
     PL_sv_arenaroot    = NULL;
@@ -15248,7 +15721,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_minus_c         = proto_perl->Iminus_c;
 
     PL_localpatches    = proto_perl->Ilocalpatches;
-    PL_splitstr                = proto_perl->Isplitstr;
+    PL_splitstr                = SAVEPV(proto_perl->Isplitstr);
     PL_minus_n         = proto_perl->Iminus_n;
     PL_minus_p         = proto_perl->Iminus_p;
     PL_minus_l         = proto_perl->Iminus_l;
@@ -15313,43 +15786,17 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_nomemok         = proto_perl->Inomemok;
     PL_an              = proto_perl->Ian;
     PL_evalseq         = proto_perl->Ievalseq;
-    PL_origenviron     = proto_perl->Iorigenviron;     /* XXX not quite right */
     PL_origalen                = proto_perl->Iorigalen;
 
     PL_sighandlerp     = proto_perl->Isighandlerp;
+    PL_sighandler1p    = proto_perl->Isighandler1p;
+    PL_sighandler3p    = proto_perl->Isighandler3p;
 
     PL_runops          = proto_perl->Irunops;
 
     PL_subline         = proto_perl->Isubline;
 
     PL_cv_has_eval     = proto_perl->Icv_has_eval;
-
-#ifdef FCRYPT
-    PL_cryptseen       = proto_perl->Icryptseen;
-#endif
-
-#ifdef USE_LOCALE_COLLATE
-    PL_collation_ix    = proto_perl->Icollation_ix;
-    PL_collation_standard      = proto_perl->Icollation_standard;
-    PL_collxfrm_base   = proto_perl->Icollxfrm_base;
-    PL_collxfrm_mult   = proto_perl->Icollxfrm_mult;
-    PL_strxfrm_max_cp   = proto_perl->Istrxfrm_max_cp;
-#endif /* USE_LOCALE_COLLATE */
-
-#ifdef USE_LOCALE_NUMERIC
-    PL_numeric_standard        = proto_perl->Inumeric_standard;
-    PL_numeric_underlying      = proto_perl->Inumeric_underlying;
-    PL_numeric_underlying_is_standard  = proto_perl->Inumeric_underlying_is_standard;
-#endif /* !USE_LOCALE_NUMERIC */
-
-    /* Did the locale setup indicate UTF-8? */
-    PL_utf8locale      = proto_perl->Iutf8locale;
-    PL_in_utf8_CTYPE_locale = proto_perl->Iin_utf8_CTYPE_locale;
-    PL_in_utf8_COLLATE_locale = proto_perl->Iin_utf8_COLLATE_locale;
-    my_strlcpy(PL_locale_utf8ness, proto_perl->Ilocale_utf8ness, sizeof(PL_locale_utf8ness));
-#if defined(USE_ITHREADS) && ! defined(USE_THREAD_SAFE_LOCALE)
-    PL_lc_numeric_mutex_depth = 0;
-#endif
     /* Unicode features (see perlrun/-C) */
     PL_unicode         = proto_perl->Iunicode;
 
@@ -15362,9 +15809,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     /* Recursion stopper for PerlIO_find_layer */
     PL_in_load_module  = proto_perl->Iin_load_module;
 
-    /* sort() routine */
-    PL_sort_RealCmp    = proto_perl->Isort_RealCmp;
-
     /* Not really needed/useful since the reenrant_retint is "volatile",
      * but do it for consistency's sake. */
     PL_reentrant_retint        = proto_perl->Ireentrant_retint;
@@ -15381,22 +15825,24 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     PL_srand_called    = proto_perl->Isrand_called;
     Copy(&(proto_perl->Irandom_state), &PL_random_state, 1, PL_RANDOM_STATE_TYPE);
+    PL_srand_override   = proto_perl->Isrand_override;
+    PL_srand_override_next = proto_perl->Isrand_override_next;
 
     if (flags & CLONEf_COPY_STACKS) {
-       /* next allocation will be PL_tmps_stack[PL_tmps_ix+1] */
-       PL_tmps_ix              = proto_perl->Itmps_ix;
-       PL_tmps_max             = proto_perl->Itmps_max;
-       PL_tmps_floor           = proto_perl->Itmps_floor;
+        /* next allocation will be PL_tmps_stack[PL_tmps_ix+1] */
+        PL_tmps_ix             = proto_perl->Itmps_ix;
+        PL_tmps_max            = proto_perl->Itmps_max;
+        PL_tmps_floor          = proto_perl->Itmps_floor;
 
-       /* next push_scope()/ENTER sets PL_scopestack[PL_scopestack_ix]
-        * NOTE: unlike the others! */
-       PL_scopestack_ix        = proto_perl->Iscopestack_ix;
-       PL_scopestack_max       = proto_perl->Iscopestack_max;
+        /* next push_scope()/ENTER sets PL_scopestack[PL_scopestack_ix]
+         * NOTE: unlike the others! */
+        PL_scopestack_ix       = proto_perl->Iscopestack_ix;
+        PL_scopestack_max      = proto_perl->Iscopestack_max;
 
-       /* next SSPUSHFOO() sets PL_savestack[PL_savestack_ix]
-        * NOTE: unlike the others! */
-       PL_savestack_ix         = proto_perl->Isavestack_ix;
-       PL_savestack_max        = proto_perl->Isavestack_max;
+        /* next SSPUSHFOO() sets PL_savestack[PL_savestack_ix]
+         * NOTE: unlike the others! */
+        PL_savestack_ix                = proto_perl->Isavestack_ix;
+        PL_savestack_max       = proto_perl->Isavestack_max;
     }
 
     PL_start_env       = proto_perl->Istart_env;       /* XXXXXX */
@@ -15445,6 +15891,10 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     /* op_free() hook */
     PL_opfreehook      = proto_perl->Iopfreehook;
 
+#  ifdef PERL_MEM_LOG
+    Zero(PL_mem_log, sizeof(PL_mem_log), char);
+#  endif
+
 #ifdef USE_REENTRANT_API
     /* XXX: things like -Dm will segfault here in perlio, but doing
      *  PERL_SET_CONTEXT(proto_perl);
@@ -15463,7 +15913,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     ptr_table_store(PL_ptr_table, &proto_perl->Isv_zero, &PL_sv_zero);
     ptr_table_store(PL_ptr_table, &proto_perl->Isv_yes, &PL_sv_yes);
     ptr_table_store(PL_ptr_table, &proto_perl->Ipadname_const,
-                   &PL_padname_const);
+                    &PL_padname_const);
 
     /* create (a non-shared!) shared string table */
     PL_strtab          = newHV();
@@ -15473,9 +15923,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     Zero(PL_sv_consts, SV_CONSTS_COUNT, SV*);
 
-    /* This PV will be free'd special way so must set it same way op.c does */
-    PL_compiling.cop_file    = savesharedpv(PL_compiling.cop_file);
-    ptr_table_store(PL_ptr_table, proto_perl->Icompiling.cop_file, PL_compiling.cop_file);
+    PL_compiling.cop_file    = rcpv_copy(proto_perl->Icompiling.cop_file);
 
     ptr_table_store(PL_ptr_table, &proto_perl->Icompiling, &PL_compiling);
     PL_compiling.cop_warnings = DUP_WARNINGS(PL_compiling.cop_warnings);
@@ -15492,7 +15940,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     AvREAL_off(param->stashes);
 
     if (!(flags & CLONEf_COPY_STACKS)) {
-       param->unreferenced = newAV();
+        param->unreferenced = newAV();
     }
 
 #ifdef PERLIO_LAYERS
@@ -15508,6 +15956,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_diehook         = sv_dup_inc(proto_perl->Idiehook, param);
     PL_warnhook                = sv_dup_inc(proto_perl->Iwarnhook, param);
 
+    PL_hook__require__before = sv_dup_inc(proto_perl->Ihook__require__before, param);
+    PL_hook__require__after  = sv_dup_inc(proto_perl->Ihook__require__after, param);
+
     /* switches */
     PL_patchlevel      = sv_dup_inc(proto_perl->Ipatchlevel, param);
     PL_inplace         = SAVEPV(proto_perl->Iinplace);
@@ -15519,7 +15970,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     SvPVCLEAR(PERL_DEBUG_PAD(1));        /* ext/re needs these */
     SvPVCLEAR(PERL_DEBUG_PAD(2));        /* even without DEBUGGING. */
 
-   
+
     /* Clone the regex array */
     /* ORANGE FIXME for plugins, probably in the SV dup code.
        newSViv(PTR2IV(CALLREGDUPE(
@@ -15532,9 +15983,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_stashpadix      = proto_perl->Istashpadix ;
     Newx(PL_stashpad, PL_stashpadmax, HV *);
     {
-       PADOFFSET o = 0;
-       for (; o < PL_stashpadmax; ++o)
-           PL_stashpad[o] = hv_dup(proto_perl->Istashpad[o], param);
+        PADOFFSET o = 0;
+        for (; o < PL_stashpadmax; ++o)
+            PL_stashpad[o] = hv_dup(proto_perl->Istashpad[o], param);
     }
 
     /* shortcuts to various I/O objects */
@@ -15584,9 +16035,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_fdpid           = av_dup_inc(proto_perl->Ifdpid, param);
 
     if (proto_perl->Iop_mask)
-       PL_op_mask      = SAVEPVN(proto_perl->Iop_mask, PL_maxo);
+        PL_op_mask     = SAVEPVN(proto_perl->Iop_mask, PL_maxo);
     else
-       PL_op_mask      = NULL;
+        PL_op_mask     = NULL;
     /* PL_asserting        = proto_perl->Iasserting; */
 
     /* current interpreter roots */
@@ -15605,19 +16056,19 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     /* interpreter atexit processing */
     PL_exitlistlen     = proto_perl->Iexitlistlen;
     if (PL_exitlistlen) {
-       Newx(PL_exitlist, PL_exitlistlen, PerlExitListEntry);
-       Copy(proto_perl->Iexitlist, PL_exitlist, PL_exitlistlen, PerlExitListEntry);
+        Newx(PL_exitlist, PL_exitlistlen, PerlExitListEntry);
+        Copy(proto_perl->Iexitlist, PL_exitlist, PL_exitlistlen, PerlExitListEntry);
     }
     else
-       PL_exitlist     = (PerlExitListEntry*)NULL;
+        PL_exitlist    = (PerlExitListEntry*)NULL;
 
     PL_my_cxt_size = proto_perl->Imy_cxt_size;
     if (PL_my_cxt_size) {
-       Newx(PL_my_cxt_list, PL_my_cxt_size, void *);
-       Copy(proto_perl->Imy_cxt_list, PL_my_cxt_list, PL_my_cxt_size, void *);
+        Newx(PL_my_cxt_list, PL_my_cxt_size, void *);
+        Copy(proto_perl->Imy_cxt_list, PL_my_cxt_list, PL_my_cxt_size, void *);
     }
     else {
-       PL_my_cxt_list  = (void**)NULL;
+        PL_my_cxt_list = (void**)NULL;
     }
     PL_modglobal       = hv_dup_inc(proto_perl->Imodglobal, param);
     PL_custom_op_names  = hv_dup_inc(proto_perl->Icustom_op_names,param);
@@ -15642,114 +16093,198 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     /* XXX this only works if the saved cop has already been cloned */
     if (proto_perl->Iparser) {
-       PL_parser->saved_curcop = (COP*)any_dup(
-                                   proto_perl->Iparser->saved_curcop,
-                                   proto_perl);
+        PL_parser->saved_curcop = (COP*)any_dup(
+                                    proto_perl->Iparser->saved_curcop,
+                                    proto_perl);
     }
 
     PL_subname         = sv_dup_inc(proto_perl->Isubname, param);
 
-#if   defined(USE_POSIX_2008_LOCALE)      \
- &&   defined(USE_THREAD_SAFE_LOCALE)     \
- && ! defined(HAS_QUERYLOCALE)
+#ifdef USE_PL_CURLOCALES
     for (i = 0; i < (int) C_ARRAY_LENGTH(PL_curlocales); i++) {
-        PL_curlocales[i] = savepv("."); /* An illegal value */
+        PL_curlocales[i] = SAVEPV("C");
     }
 #endif
+#ifdef USE_PL_CUR_LC_ALL
+    PL_cur_LC_ALL = SAVEPV("C");
+#endif
 #ifdef USE_LOCALE_CTYPE
+    Copy(PL_fold, PL_fold_locale, 256, U8);
+
     /* Should we warn if uses locale? */
+    PL_ctype_name      = SAVEPV("C");
     PL_warn_locale      = sv_dup_inc(proto_perl->Iwarn_locale, param);
+    PL_in_utf8_CTYPE_locale   = false;
+    PL_in_utf8_turkic_locale  = false;
 #endif
 
+    /* Did the locale setup indicate UTF-8? */
+    PL_utf8locale      = false;
+
 #ifdef USE_LOCALE_COLLATE
-    PL_collation_name  = SAVEPV(proto_perl->Icollation_name);
+    PL_in_utf8_COLLATE_locale = false;
+    PL_collation_name  = SAVEPV("C");
+    PL_collation_ix    = proto_perl->Icollation_ix;
+    PL_collation_standard = true;
+    PL_collxfrm_base   = 0;
+    PL_collxfrm_mult   = 0;
+    PL_strxfrm_max_cp   = 0;
+    PL_strxfrm_is_behaved = proto_perl->Istrxfrm_is_behaved;
+    PL_strxfrm_NUL_replacement = '\0';
 #endif /* USE_LOCALE_COLLATE */
 
+#ifdef USE_LOCALE_THREADS
+    assert(PL_locale_mutex_depth <= 0);
+    PL_locale_mutex_depth = 0;
+#endif
+
 #ifdef USE_LOCALE_NUMERIC
-    PL_numeric_name    = SAVEPV(proto_perl->Inumeric_name);
-    PL_numeric_radix_sv        = sv_dup_inc(proto_perl->Inumeric_radix_sv, param);
+    PL_numeric_name    = SAVEPV("C");
+    PL_numeric_radix_sv        = newSVpvs(".");
+    PL_underlying_radix_sv = newSVpvs(".");
+    PL_numeric_standard        = true;
+    PL_numeric_underlying = true;
+    PL_numeric_underlying_is_standard = true;
 
-#  if defined(HAS_POSIX_2008_LOCALE)
-    PL_underlying_numeric_obj = NULL;
-#  endif
 #endif /* !USE_LOCALE_NUMERIC */
+#if defined(USE_POSIX_2008_LOCALE)
+    PL_scratch_locale_obj = NULL;
+    PL_cur_locale_obj = PL_C_locale_obj;
+#endif
 
-    PL_langinfo_buf = NULL;
-    PL_langinfo_bufsize = 0;
+#ifdef HAS_MBRLEN
+    PL_mbrlen_ps = proto_perl->Imbrlen_ps;
+#endif
+#ifdef HAS_MBRTOWC
+    PL_mbrtowc_ps = proto_perl->Imbrtowc_ps;
+#endif
+#ifdef HAS_WCRTOMB
+    PL_wcrtomb_ps = proto_perl->Iwcrtomb_ps;
+#endif
+
+    PL_langinfo_sv = newSVpvs("");
+    PL_scratch_langinfo = newSVpvs("");
 
     PL_setlocale_buf = NULL;
     PL_setlocale_bufsize = 0;
 
+#if defined(USE_LOCALE_THREADS) && ! defined(USE_THREAD_SAFE_LOCALE)
+    PL_less_dicey_locale_buf = NULL;
+    PL_less_dicey_locale_bufsize = 0;
+#endif
+
+    /* Unicode inversion lists */
+
+    PL_AboveLatin1            = sv_dup_inc(proto_perl->IAboveLatin1, param);
+    PL_Assigned_invlist       = sv_dup_inc(proto_perl->IAssigned_invlist, param);
+    PL_GCB_invlist            = sv_dup_inc(proto_perl->IGCB_invlist, param);
+    PL_HasMultiCharFold       = sv_dup_inc(proto_perl->IHasMultiCharFold, param);
+    PL_InMultiCharFold        = sv_dup_inc(proto_perl->IInMultiCharFold, param);
+    PL_Latin1                 = sv_dup_inc(proto_perl->ILatin1, param);
+    PL_LB_invlist             = sv_dup_inc(proto_perl->ILB_invlist, param);
+    PL_SB_invlist             = sv_dup_inc(proto_perl->ISB_invlist, param);
+    PL_SCX_invlist            = sv_dup_inc(proto_perl->ISCX_invlist, param);
+    PL_UpperLatin1            = sv_dup_inc(proto_perl->IUpperLatin1, param);
+    PL_in_some_fold           = sv_dup_inc(proto_perl->Iin_some_fold, param);
+    PL_utf8_foldclosures      = sv_dup_inc(proto_perl->Iutf8_foldclosures, param);
+    PL_utf8_idcont            = sv_dup_inc(proto_perl->Iutf8_idcont, param);
+    PL_utf8_idstart           = sv_dup_inc(proto_perl->Iutf8_idstart, param);
+    PL_utf8_perl_idcont       = sv_dup_inc(proto_perl->Iutf8_perl_idcont, param);
+    PL_utf8_perl_idstart      = sv_dup_inc(proto_perl->Iutf8_perl_idstart, param);
+    PL_utf8_xidcont           = sv_dup_inc(proto_perl->Iutf8_xidcont, param);
+    PL_utf8_xidstart          = sv_dup_inc(proto_perl->Iutf8_xidstart, param);
+    PL_WB_invlist             = sv_dup_inc(proto_perl->IWB_invlist, param);
+    for (i = 0; i < POSIX_CC_COUNT; i++) {
+        PL_XPosix_ptrs[i]     = sv_dup_inc(proto_perl->IXPosix_ptrs[i], param);
+        if (i != CC_CASED_ && i != CC_VERTSPACE_) {
+            PL_Posix_ptrs[i]  = sv_dup_inc(proto_perl->IPosix_ptrs[i], param);
+        }
+    }
+    PL_Posix_ptrs[CC_CASED_]  = PL_Posix_ptrs[CC_ALPHA_];
+    PL_Posix_ptrs[CC_VERTSPACE_] = NULL;
+
+    PL_utf8_toupper           = sv_dup_inc(proto_perl->Iutf8_toupper, param);
+    PL_utf8_totitle           = sv_dup_inc(proto_perl->Iutf8_totitle, param);
+    PL_utf8_tolower           = sv_dup_inc(proto_perl->Iutf8_tolower, param);
+    PL_utf8_tofold            = sv_dup_inc(proto_perl->Iutf8_tofold, param);
+    PL_utf8_tosimplefold      = sv_dup_inc(proto_perl->Iutf8_tosimplefold, param);
+    PL_utf8_charname_begin    = sv_dup_inc(proto_perl->Iutf8_charname_begin, param);
+    PL_utf8_charname_continue = sv_dup_inc(proto_perl->Iutf8_charname_continue, param);
+    PL_utf8_mark              = sv_dup_inc(proto_perl->Iutf8_mark, param);
+    PL_InBitmap               = sv_dup_inc(proto_perl->IInBitmap, param);
+    PL_CCC_non0_non230        = sv_dup_inc(proto_perl->ICCC_non0_non230, param);
+    PL_Private_Use            = sv_dup_inc(proto_perl->IPrivate_Use, param);
+
 #if 0
     PL_seen_deprecated_macro = hv_dup_inc(proto_perl->Iseen_deprecated_macro, param);
 #endif
 
     if (proto_perl->Ipsig_pend) {
-       Newxz(PL_psig_pend, SIG_SIZE, int);
+        Newxz(PL_psig_pend, SIG_SIZE, int);
     }
     else {
-       PL_psig_pend    = (int*)NULL;
+        PL_psig_pend   = (int*)NULL;
     }
 
     if (proto_perl->Ipsig_name) {
-       Newx(PL_psig_name, 2 * SIG_SIZE, SV*);
-       sv_dup_inc_multiple(proto_perl->Ipsig_name, PL_psig_name, 2 * SIG_SIZE,
-                           param);
-       PL_psig_ptr = PL_psig_name + SIG_SIZE;
+        Newx(PL_psig_name, 2 * SIG_SIZE, SV*);
+        sv_dup_inc_multiple(proto_perl->Ipsig_name, PL_psig_name, 2 * SIG_SIZE,
+                            param);
+        PL_psig_ptr = PL_psig_name + SIG_SIZE;
     }
     else {
-       PL_psig_ptr     = (SV**)NULL;
-       PL_psig_name    = (SV**)NULL;
+        PL_psig_ptr    = (SV**)NULL;
+        PL_psig_name   = (SV**)NULL;
     }
 
     if (flags & CLONEf_COPY_STACKS) {
-       Newx(PL_tmps_stack, PL_tmps_max, SV*);
-       sv_dup_inc_multiple(proto_perl->Itmps_stack, PL_tmps_stack,
-                           PL_tmps_ix+1, param);
-
-       /* next PUSHMARK() sets *(PL_markstack_ptr+1) */
-       i = proto_perl->Imarkstack_max - proto_perl->Imarkstack;
-       Newx(PL_markstack, i, I32);
-       PL_markstack_max        = PL_markstack + (proto_perl->Imarkstack_max
-                                                 - proto_perl->Imarkstack);
-       PL_markstack_ptr        = PL_markstack + (proto_perl->Imarkstack_ptr
-                                                 - proto_perl->Imarkstack);
-       Copy(proto_perl->Imarkstack, PL_markstack,
-            PL_markstack_ptr - PL_markstack + 1, I32);
-
-       /* next push_scope()/ENTER sets PL_scopestack[PL_scopestack_ix]
-        * NOTE: unlike the others! */
-       Newx(PL_scopestack, PL_scopestack_max, I32);
-       Copy(proto_perl->Iscopestack, PL_scopestack, PL_scopestack_ix, I32);
+        Newx(PL_tmps_stack, PL_tmps_max, SV*);
+        sv_dup_inc_multiple(proto_perl->Itmps_stack, PL_tmps_stack,
+                            PL_tmps_ix+1, param);
+
+        /* next PUSHMARK() sets *(PL_markstack_ptr+1) */
+        i = proto_perl->Imarkstack_max - proto_perl->Imarkstack;
+        Newx(PL_markstack, i, Stack_off_t);
+        PL_markstack_max       = PL_markstack + (proto_perl->Imarkstack_max
+                                                  - proto_perl->Imarkstack);
+        PL_markstack_ptr       = PL_markstack + (proto_perl->Imarkstack_ptr
+                                                  - proto_perl->Imarkstack);
+        Copy(proto_perl->Imarkstack, PL_markstack,
+             PL_markstack_ptr - PL_markstack + 1, Stack_off_t);
+
+        /* next push_scope()/ENTER sets PL_scopestack[PL_scopestack_ix]
+         * NOTE: unlike the others! */
+        Newx(PL_scopestack, PL_scopestack_max, I32);
+        Copy(proto_perl->Iscopestack, PL_scopestack, PL_scopestack_ix, I32);
 
 #ifdef DEBUGGING
-       Newx(PL_scopestack_name, PL_scopestack_max, const char *);
-       Copy(proto_perl->Iscopestack_name, PL_scopestack_name, PL_scopestack_ix, const char *);
+        Newx(PL_scopestack_name, PL_scopestack_max, const char *);
+        Copy(proto_perl->Iscopestack_name, PL_scopestack_name, PL_scopestack_ix, const char *);
 #endif
         /* reset stack AV to correct length before its duped via
          * PL_curstackinfo */
         AvFILLp(proto_perl->Icurstack) =
                             proto_perl->Istack_sp - proto_perl->Istack_base;
 
-       /* NOTE: si_dup() looks at PL_markstack */
-       PL_curstackinfo         = si_dup(proto_perl->Icurstackinfo, param);
+        /* NOTE: si_dup() looks at PL_markstack */
+        PL_curstackinfo                = si_dup(proto_perl->Icurstackinfo, param);
 
-       /* PL_curstack          = PL_curstackinfo->si_stack; */
-       PL_curstack             = av_dup(proto_perl->Icurstack, param);
-       PL_mainstack            = av_dup(proto_perl->Imainstack, param);
+        /* PL_curstack         = PL_curstackinfo->si_stack; */
+        PL_curstack            = av_dup(proto_perl->Icurstack, param);
+        PL_mainstack           = av_dup(proto_perl->Imainstack, param);
 
-       /* next PUSHs() etc. set *(PL_stack_sp+1) */
-       PL_stack_base           = AvARRAY(PL_curstack);
-       PL_stack_sp             = PL_stack_base + (proto_perl->Istack_sp
-                                                  - proto_perl->Istack_base);
-       PL_stack_max            = PL_stack_base + AvMAX(PL_curstack);
+        /* next PUSHs() etc. set *(PL_stack_sp+1) */
+        PL_stack_base          = AvARRAY(PL_curstack);
+        PL_stack_sp            = PL_stack_base + (proto_perl->Istack_sp
+                                                   - proto_perl->Istack_base);
+        PL_stack_max           = PL_stack_base + AvMAX(PL_curstack);
 
-       /*Newxz(PL_savestack, PL_savestack_max, ANY);*/
-       PL_savestack            = ss_dup(proto_perl, param);
+        /*Newxz(PL_savestack, PL_savestack_max, ANY);*/
+        PL_savestack           = ss_dup(proto_perl, param);
     }
     else {
-       init_stacks();
-       ENTER;                  /* perl_destruct() wants to LEAVE; */
+        init_stacks();
+        ENTER;                 /* perl_destruct() wants to LEAVE; */
     }
 
     PL_statgv          = gv_dup(proto_perl->Istatgv, param);
@@ -15771,13 +16306,13 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_stashcache       = newHV();
 
     PL_watchaddr       = (char **) ptr_table_fetch(PL_ptr_table,
-                                           proto_perl->Iwatchaddr);
+                                            proto_perl->Iwatchaddr);
     PL_watchok         = PL_watchaddr ? * PL_watchaddr : NULL;
     if (PL_debug && PL_watchaddr) {
-       PerlIO_printf(Perl_debug_log,
-         "WATCHING: %" UVxf " cloned as %" UVxf " with value %" UVxf "\n",
-         PTR2UV(proto_perl->Iwatchaddr), PTR2UV(PL_watchaddr),
-         PTR2UV(PL_watchok));
+        PerlIO_printf(Perl_debug_log,
+          "WATCHING: %" UVxf " cloned as %" UVxf " with value %" UVxf "\n",
+          PTR2UV(proto_perl->Iwatchaddr), PTR2UV(PL_watchaddr),
+          PTR2UV(PL_watchok));
     }
 
     PL_registered_mros  = hv_dup_inc(proto_perl->Iregistered_mros, param);
@@ -15786,20 +16321,22 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     /* Call the ->CLONE method, if it exists, for each of the stashes
        identified by sv_dup() above.
     */
-    while(av_tindex(param->stashes) != -1) {
-       HV* const stash = MUTABLE_HV(av_shift(param->stashes));
-       GV* const cloner = gv_fetchmethod_autoload(stash, "CLONE", 0);
-       if (cloner && GvCV(cloner)) {
-           dSP;
-           ENTER;
-           SAVETMPS;
-           PUSHMARK(SP);
-           mXPUSHs(newSVhek(HvNAME_HEK(stash)));
-           PUTBACK;
-           call_sv(MUTABLE_SV(GvCV(cloner)), G_DISCARD);
-           FREETMPS;
-           LEAVE;
-       }
+    while(av_count(param->stashes) != 0) {
+        HV* const stash = MUTABLE_HV(av_shift(param->stashes));
+        GV* const cloner = gv_fetchmethod_autoload(stash, "CLONE", 0);
+        if (cloner && GvCV(cloner)) {
+            ENTER;
+            SAVETMPS;
+            PUSHMARK(PL_stack_sp);
+            rpp_extend(1);
+            SV *newsv = newSVhek(HvNAME_HEK(stash));
+            *++PL_stack_sp = newsv;
+            if (!rpp_stack_is_rc())
+                sv_2mortal(newsv);
+            call_sv(MUTABLE_SV(GvCV(cloner)), G_DISCARD);
+            FREETMPS;
+            LEAVE;
+        }
     }
 
     if (!(flags & CLONEf_KEEP_PTR_TABLE)) {
@@ -15808,15 +16345,15 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     }
 
     if (!(flags & CLONEf_COPY_STACKS)) {
-       unreferenced_to_tmp_stack(param->unreferenced);
+        unreferenced_to_tmp_stack(param->unreferenced);
     }
 
     SvREFCNT_dec(param->stashes);
 
     /* orphaned? eg threads->new inside BEGIN or use */
     if (PL_compcv && ! SvREFCNT(PL_compcv)) {
-       SvREFCNT_inc_simple_void(PL_compcv);
-       SAVEFREESV(PL_compcv);
+        SvREFCNT_inc_simple_void(PL_compcv);
+        SAVEFREESV(PL_compcv);
     }
 
     return my_perl;
@@ -15826,42 +16363,42 @@ static void
 S_unreferenced_to_tmp_stack(pTHX_ AV *const unreferenced)
 {
     PERL_ARGS_ASSERT_UNREFERENCED_TO_TMP_STACK;
-    
+
     if (AvFILLp(unreferenced) > -1) {
-       SV **svp = AvARRAY(unreferenced);
-       SV **const last = svp + AvFILLp(unreferenced);
-       SSize_t count = 0;
-
-       do {
-           if (SvREFCNT(*svp) == 1)
-               ++count;
-       } while (++svp <= last);
-
-       EXTEND_MORTAL(count);
-       svp = AvARRAY(unreferenced);
-
-       do {
-           if (SvREFCNT(*svp) == 1) {
-               /* Our reference is the only one to this SV. This means that
-                  in this thread, the scalar effectively has a 0 reference.
-                  That doesn't work (cleanup never happens), so donate our
-                  reference to it onto the save stack. */
-               PL_tmps_stack[++PL_tmps_ix] = *svp;
-           } else {
-               /* As an optimisation, because we are already walking the
-                  entire array, instead of above doing either
-                  SvREFCNT_inc(*svp) or *svp = &PL_sv_undef, we can instead
-                  release our reference to the scalar, so that at the end of
-                  the array owns zero references to the scalars it happens to
-                  point to. We are effectively converting the array from
-                  AvREAL() on to AvREAL() off. This saves the av_clear()
-                  (triggered by the SvREFCNT_dec(unreferenced) below) from
-                  walking the array a second time.  */
-               SvREFCNT_dec(*svp);
-           }
-
-       } while (++svp <= last);
-       AvREAL_off(unreferenced);
+        SV **svp = AvARRAY(unreferenced);
+        SV **const last = svp + AvFILLp(unreferenced);
+        SSize_t count = 0;
+
+        do {
+            if (SvREFCNT(*svp) == 1)
+                ++count;
+        } while (++svp <= last);
+
+        EXTEND_MORTAL(count);
+        svp = AvARRAY(unreferenced);
+
+        do {
+            if (SvREFCNT(*svp) == 1) {
+                /* Our reference is the only one to this SV. This means that
+                   in this thread, the scalar effectively has a 0 reference.
+                   That doesn't work (cleanup never happens), so donate our
+                   reference to it onto the save stack. */
+                PL_tmps_stack[++PL_tmps_ix] = *svp;
+            } else {
+                /* As an optimisation, because we are already walking the
+                   entire array, instead of above doing either
+                   SvREFCNT_inc(*svp) or *svp = &PL_sv_undef, we can instead
+                   release our reference to the scalar, so that at the end of
+                   the array owns zero references to the scalars it happens to
+                   point to. We are effectively converting the array from
+                   AvREAL() on to AvREAL() off. This saves the av_clear()
+                   (triggered by the SvREFCNT_dec(unreferenced) below) from
+                   walking the array a second time.  */
+                SvREFCNT_dec(*svp);
+            }
+
+        } while (++svp <= last);
+        AvREAL_off(unreferenced);
     }
     SvREFCNT_dec_NN(unreferenced);
 }
@@ -15869,33 +16406,30 @@ S_unreferenced_to_tmp_stack(pTHX_ AV *const unreferenced)
 void
 Perl_clone_params_del(CLONE_PARAMS *param)
 {
-    /* This seemingly funky ordering keeps the build with PERL_GLOBAL_STRUCT
-       happy: */
+    PerlInterpreter *const was = PERL_GET_THX;
     PerlInterpreter *const to = param->new_perl;
     dTHXa(to);
-    PerlInterpreter *const was = PERL_GET_THX;
 
     PERL_ARGS_ASSERT_CLONE_PARAMS_DEL;
 
     if (was != to) {
-       PERL_SET_THX(to);
+        PERL_SET_THX(to);
     }
 
     SvREFCNT_dec(param->stashes);
     if (param->unreferenced)
-       unreferenced_to_tmp_stack(param->unreferenced);
+        unreferenced_to_tmp_stack(param->unreferenced);
 
     Safefree(param);
 
     if (was != to) {
-       PERL_SET_THX(was);
+        PERL_SET_THX(was);
     }
 }
 
 CLONE_PARAMS *
 Perl_clone_params_new(PerlInterpreter *const from, PerlInterpreter *const to)
 {
-    dVAR;
     /* Need to play this game, as newAV() can call safesysmalloc(), and that
        does a dTHX; to get the context from thread local storage.
        FIXME - under PERL_CORE Newx(), Safefree() and friends should expand to
@@ -15906,7 +16440,7 @@ Perl_clone_params_new(PerlInterpreter *const from, PerlInterpreter *const to)
     PERL_ARGS_ASSERT_CLONE_PARAMS_NEW;
 
     if (was != to) {
-       PERL_SET_THX(to);
+        PERL_SET_THX(to);
     }
 
     /* Given that we've set the context, we can do this unshared.  */
@@ -15920,7 +16454,7 @@ Perl_clone_params_new(PerlInterpreter *const from, PerlInterpreter *const to)
     param->unreferenced = (AV *)Perl_newSV_type(to, SVt_PVAV);
 
     if (was != to) {
-       PERL_SET_THX(was);
+        PERL_SET_THX(was);
     }
     return param;
 }
@@ -15930,7 +16464,6 @@ Perl_clone_params_new(PerlInterpreter *const from, PerlInterpreter *const to)
 void
 Perl_init_constants(pTHX)
 {
-    dVAR;
 
     SvREFCNT(&PL_sv_undef)     = SvREFCNT_IMMORTAL;
     SvFLAGS(&PL_sv_undef)      = SVf_READONLY|SVf_PROTECT|SVt_NULL;
@@ -15939,20 +16472,20 @@ Perl_init_constants(pTHX)
     SvANY(&PL_sv_no)           = new_XPVNV();
     SvREFCNT(&PL_sv_no)                = SvREFCNT_IMMORTAL;
     SvFLAGS(&PL_sv_no)         = SVt_PVNV|SVf_READONLY|SVf_PROTECT
-                                 |SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
-                                 |SVp_POK|SVf_POK;
+                                  |SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
+                                  |SVp_POK|SVf_POK|SVf_IsCOW|SVppv_STATIC;
 
     SvANY(&PL_sv_yes)          = new_XPVNV();
     SvREFCNT(&PL_sv_yes)       = SvREFCNT_IMMORTAL;
     SvFLAGS(&PL_sv_yes)                = SVt_PVNV|SVf_READONLY|SVf_PROTECT
-                                 |SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
-                                 |SVp_POK|SVf_POK;
+                                  |SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
+                                  |SVp_POK|SVf_POK|SVf_IsCOW|SVppv_STATIC;
 
     SvANY(&PL_sv_zero)         = new_XPVNV();
     SvREFCNT(&PL_sv_zero)      = SvREFCNT_IMMORTAL;
     SvFLAGS(&PL_sv_zero)       = SVt_PVNV|SVf_READONLY|SVf_PROTECT
-                                 |SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
-                                 |SVp_POK|SVf_POK
+                                  |SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
+                                  |SVp_POK|SVf_POK
                                   |SVs_PADTMP;
 
     SvPV_set(&PL_sv_no, (char*)PL_No);
@@ -15997,7 +16530,7 @@ Perl_init_constants(pTHX)
 }
 
 /*
-=head1 Unicode Support
+=for apidoc_section $unicode
 
 =for apidoc sv_recode_to_utf8
 
@@ -16008,7 +16541,7 @@ will be converted into Unicode (and UTF-8).
 If C<sv> already is UTF-8 (or if it is not C<POK>), or if C<encoding>
 is not a reference, nothing is done to C<sv>.  If C<encoding> is not
 an C<Encode::XS> Encoding object, bad things will happen.
-(See F<cpan/Encode/encoding.pm> and L<Encode>.)
+(See L<encoding> and L<Encode>.)
 
 The PV of C<sv> is returned.
 
@@ -16020,23 +16553,23 @@ Perl_sv_recode_to_utf8(pTHX_ SV *sv, SV *encoding)
     PERL_ARGS_ASSERT_SV_RECODE_TO_UTF8;
 
     if (SvPOK(sv) && !SvUTF8(sv) && !IN_BYTES && SvROK(encoding)) {
-       SV *uni;
-       STRLEN len;
-       const char *s;
-       dSP;
-       SV *nsv = sv;
-       ENTER;
-       PUSHSTACK;
-       SAVETMPS;
-       if (SvPADTMP(nsv)) {
-           nsv = sv_newmortal();
-           SvSetSV_nosteal(nsv, sv);
-       }
-       save_re_context();
-       PUSHMARK(sp);
-       EXTEND(SP, 3);
-       PUSHs(encoding);
-       PUSHs(nsv);
+        SV *uni;
+        STRLEN len;
+        const char *s;
+        dSP;
+        SV *nsv = sv;
+        ENTER;
+        PUSHSTACK;
+        SAVETMPS;
+        if (SvPADTMP(nsv)) {
+            nsv = sv_newmortal();
+            SvSetSV_nosteal(nsv, sv);
+        }
+        save_re_context();
+        PUSHMARK(sp);
+        EXTEND(SP, 3);
+        PUSHs(encoding);
+        PUSHs(nsv);
 /*
   NI-S 2002/07/09
   Passing sv_yes is wrong - it needs to be or'ed set of constants
@@ -16045,32 +16578,32 @@ Perl_sv_recode_to_utf8(pTHX_ SV *sv, SV *encoding)
 
   Both will default the value - let them.
 
-       XPUSHs(&PL_sv_yes);
+        XPUSHs(&PL_sv_yes);
 */
-       PUTBACK;
-       call_method("decode", G_SCALAR);
-       SPAGAIN;
-       uni = POPs;
-       PUTBACK;
-       s = SvPV_const(uni, len);
-       if (s != SvPVX_const(sv)) {
-           SvGROW(sv, len + 1);
-           Move(s, SvPVX(sv), len + 1, char);
-           SvCUR_set(sv, len);
-       }
-       FREETMPS;
-       POPSTACK;
-       LEAVE;
-       if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-           /* clear pos and any utf8 cache */
-           MAGIC * mg = mg_find(sv, PERL_MAGIC_regex_global);
-           if (mg)
-               mg->mg_len = -1;
-           if ((mg = mg_find(sv, PERL_MAGIC_utf8)))
-               magic_setutf8(sv,mg); /* clear UTF8 cache */
-       }
-       SvUTF8_on(sv);
-       return SvPVX(sv);
+        PUTBACK;
+        call_method("decode", G_SCALAR);
+        SPAGAIN;
+        uni = POPs;
+        PUTBACK;
+        s = SvPV_const(uni, len);
+        if (s != SvPVX_const(sv)) {
+            SvGROW(sv, len + 1);
+            Move(s, SvPVX(sv), len + 1, char);
+            SvCUR_set(sv, len);
+        }
+        FREETMPS;
+        POPSTACK;
+        LEAVE;
+        if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
+            /* clear pos and any utf8 cache */
+            MAGIC * mg = mg_find(sv, PERL_MAGIC_regex_global);
+            if (mg)
+                mg->mg_len = -1;
+            if ((mg = mg_find(sv, PERL_MAGIC_utf8)))
+                magic_setutf8(sv,mg); /* clear UTF8 cache */
+        }
+        SvUTF8_on(sv);
+        return SvPVX(sv);
     }
     return SvPOKp(sv) ? SvPVX(sv) : NULL;
 }
@@ -16092,34 +16625,34 @@ Returns TRUE if the terminator was found, else returns FALSE.
 
 bool
 Perl_sv_cat_decode(pTHX_ SV *dsv, SV *encoding,
-                  SV *ssv, int *offset, char *tstr, int tlen)
+                   SV *ssv, int *offset, char *tstr, int tlen)
 {
     bool ret = FALSE;
 
     PERL_ARGS_ASSERT_SV_CAT_DECODE;
 
     if (SvPOK(ssv) && SvPOK(dsv) && SvROK(encoding)) {
-       SV *offsv;
-       dSP;
-       ENTER;
-       SAVETMPS;
-       save_re_context();
-       PUSHMARK(sp);
-       EXTEND(SP, 6);
-       PUSHs(encoding);
-       PUSHs(dsv);
-       PUSHs(ssv);
-       offsv = newSViv(*offset);
-       mPUSHs(offsv);
-       mPUSHp(tstr, tlen);
-       PUTBACK;
-       call_method("cat_decode", G_SCALAR);
-       SPAGAIN;
-       ret = SvTRUE(TOPs);
-       *offset = SvIV(offsv);
-       PUTBACK;
-       FREETMPS;
-       LEAVE;
+        SV *offsv;
+        dSP;
+        ENTER;
+        SAVETMPS;
+        save_re_context();
+        PUSHMARK(sp);
+        EXTEND(SP, 6);
+        PUSHs(encoding);
+        PUSHs(dsv);
+        PUSHs(ssv);
+        offsv = newSViv(*offset);
+        mPUSHs(offsv);
+        mPUSHp(tstr, tlen);
+        PUTBACK;
+        call_method("cat_decode", G_SCALAR);
+        SPAGAIN;
+        ret = SvTRUE(TOPs);
+        *offset = SvIV(offsv);
+        PUTBACK;
+        FREETMPS;
+        LEAVE;
     }
     else
         Perl_croak(aTHX_ "Invalid argument to sv_cat_decode");
@@ -16143,32 +16676,26 @@ Perl_sv_cat_decode(pTHX_ SV *dsv, SV *encoding,
 STATIC SV*
 S_find_hash_subscript(pTHX_ const HV *const hv, const SV *const val)
 {
-    dVAR;
     HE **array;
     I32 i;
 
     PERL_ARGS_ASSERT_FIND_HASH_SUBSCRIPT;
 
-    if (!hv || SvMAGICAL(hv) || !HvARRAY(hv) ||
-                       (HvTOTALKEYS(hv) > FUV_MAX_SEARCH_SIZE))
-       return NULL;
+    if (!hv || SvMAGICAL(hv) || !HvTOTALKEYS(hv) ||
+                        (HvTOTALKEYS(hv) > FUV_MAX_SEARCH_SIZE))
+        return NULL;
+
+    if (val == &PL_sv_undef || val == &PL_sv_placeholder)
+        return NULL;
 
     array = HvARRAY(hv);
 
     for (i=HvMAX(hv); i>=0; i--) {
-       HE *entry;
-       for (entry = array[i]; entry; entry = HeNEXT(entry)) {
-           if (HeVAL(entry) != val)
-               continue;
-           if (    HeVAL(entry) == &PL_sv_undef ||
-                   HeVAL(entry) == &PL_sv_placeholder)
-               continue;
-           if (!HeKEY(entry))
-               return NULL;
-           if (HeKLEN(entry) == HEf_SVKEY)
-               return sv_mortalcopy(HeKEY_sv(entry));
-           return sv_2mortal(newSVhek(HeKEY_hek(entry)));
-       }
+        HE *entry;
+        for (entry = array[i]; entry; entry = HeNEXT(entry)) {
+            if (HeVAL(entry) == val)
+                return newSVhek_mortal(HeKEY_hek(entry));
+        }
     }
     return NULL;
 }
@@ -16182,16 +16709,16 @@ S_find_array_subscript(pTHX_ const AV *const av, const SV *const val)
     PERL_ARGS_ASSERT_FIND_ARRAY_SUBSCRIPT;
 
     if (!av || SvMAGICAL(av) || !AvARRAY(av) ||
-                       (AvFILLp(av) > FUV_MAX_SEARCH_SIZE))
-       return -1;
+                        (AvFILLp(av) > FUV_MAX_SEARCH_SIZE))
+        return -1;
 
     if (val != &PL_sv_undef) {
-       SV ** const svp = AvARRAY(av);
-       SSize_t i;
+        SV ** const svp = AvARRAY(av);
+        SSize_t i;
 
-       for (i=AvFILLp(av); i>=0; i--)
-           if (svp[i] == val)
-               return i;
+        for (i=AvFILLp(av); i>=0; i--)
+            if (svp[i] == val)
+                return i;
     }
     return -1;
 }
@@ -16209,59 +16736,59 @@ S_find_array_subscript(pTHX_ const AV *const av, const SV *const val)
 
 SV*
 Perl_varname(pTHX_ const GV *const gv, const char gvtype, PADOFFSET targ,
-       const SV *const keyname, SSize_t aindex, int subscript_type)
+        const SV *const keyname, SSize_t aindex, int subscript_type)
 {
 
     SV * const name = sv_newmortal();
     if (gv && isGV(gv)) {
-       char buffer[2];
-       buffer[0] = gvtype;
-       buffer[1] = 0;
+        char buffer[2];
+        buffer[0] = gvtype;
+        buffer[1] = 0;
 
-       /* as gv_fullname4(), but add literal '^' for $^FOO names  */
+        /* as gv_fullname4(), but add literal '^' for $^FOO names  */
 
-       gv_fullname4(name, gv, buffer, 0);
+        gv_fullname4(name, gv, buffer, 0);
 
-       if ((unsigned int)SvPVX(name)[1] <= 26) {
-           buffer[0] = '^';
-           buffer[1] = SvPVX(name)[1] + 'A' - 1;
+        if ((unsigned int)SvPVX(name)[1] <= 26) {
+            buffer[0] = '^';
+            buffer[1] = SvPVX(name)[1] + 'A' - 1;
 
-           /* Swap the 1 unprintable control character for the 2 byte pretty
-              version - ie substr($name, 1, 1) = $buffer; */
-           sv_insert(name, 1, 1, buffer, 2);
-       }
+            /* Swap the 1 unprintable control character for the 2 byte pretty
+               version - ie substr($name, 1, 1) = $buffer; */
+            sv_insert(name, 1, 1, buffer, 2);
+        }
     }
     else {
-       CV * const cv = gv ? ((CV *)gv) : find_runcv(NULL);
-       PADNAME *sv;
+        CV * const cv = gv ? ((CV *)gv) : find_runcv(NULL);
+        PADNAME *sv;
 
-       assert(!cv || SvTYPE(cv) == SVt_PVCV || SvTYPE(cv) == SVt_PVFM);
+        assert(!cv || SvTYPE(cv) == SVt_PVCV || SvTYPE(cv) == SVt_PVFM);
 
-       if (!cv || !CvPADLIST(cv))
-           return NULL;
-       sv = padnamelist_fetch(PadlistNAMES(CvPADLIST(cv)), targ);
-       sv_setpvn(name, PadnamePV(sv), PadnameLEN(sv));
-       SvUTF8_on(name);
+        if (!cv || !CvPADLIST(cv))
+            return NULL;
+        sv = padnamelist_fetch(PadlistNAMES(CvPADLIST(cv)), targ);
+        sv_setpvn(name, PadnamePV(sv), PadnameLEN(sv));
+        SvUTF8_on(name);
     }
 
     if (subscript_type == FUV_SUBSCRIPT_HASH) {
-       SV * const sv = newSV(0);
+        SV * const sv = newSV_type(SVt_NULL);
         STRLEN len;
         const char * const pv = SvPV_nomg_const((SV*)keyname, len);
 
-       *SvPVX(name) = '$';
-       Perl_sv_catpvf(aTHX_ name, "{%s}",
-           pv_pretty(sv, pv, len, 32, NULL, NULL,
-                   PERL_PV_PRETTY_DUMP | PERL_PV_ESCAPE_UNI_DETECT ));
-       SvREFCNT_dec_NN(sv);
+        *SvPVX(name) = '$';
+        Perl_sv_catpvf(aTHX_ name, "{%s}",
+            pv_pretty(sv, pv, len, 32, NULL, NULL,
+                    PERL_PV_PRETTY_DUMP | PERL_PV_ESCAPE_UNI_DETECT ));
+        SvREFCNT_dec_NN(sv);
     }
     else if (subscript_type == FUV_SUBSCRIPT_ARRAY) {
-       *SvPVX(name) = '$';
-       Perl_sv_catpvf(aTHX_ name, "[%" IVdf "]", (IV)aindex);
+        *SvPVX(name) = '$';
+        Perl_sv_catpvf(aTHX_ name, "[%" IVdf "]", (IV)aindex);
     }
     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);
+        /* 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;
@@ -16269,6 +16796,7 @@ Perl_varname(pTHX_ const GV *const gv, const char gvtype, PADOFFSET targ,
 
 
 /*
+=apidoc_section $warning
 =for apidoc find_uninit_var
 
 Find the name of the undefined variable (if any) that caused the operator
@@ -16292,9 +16820,8 @@ C<PL_comppad>/C<PL_curpad> points to the currently executing pad.
 
 STATIC SV *
 S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
-                 bool match, const char **desc_p)
+                  bool match, const char **desc_p)
 {
-    dVAR;
     SV *sv;
     const GV *gv;
     const OP *o, *o2, *kid;
@@ -16302,14 +16829,25 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
     PERL_ARGS_ASSERT_FIND_UNINIT_VAR;
 
     if (!obase || (match && (!uninit_sv || uninit_sv == &PL_sv_undef ||
-                           uninit_sv == &PL_sv_placeholder)))
-       return NULL;
+                            uninit_sv == &PL_sv_placeholder)))
+        return NULL;
 
     switch (obase->op_type) {
 
     case OP_UNDEF:
-        /* undef should care if its args are undef - any warnings
+        /* the optimizer rewrites '$x = undef' to 'undef $x' for lexical
+         * variables, which can occur as the source of warnings:
+         *   ($x = undef) =~ s/a/b/;
+         * The OPpUNDEF_KEEP_PV flag indicates that this used to be an
+         * assignment op.
+         * Otherwise undef should not care if its args are undef - any warnings
          * will be from tied/magic vars */
+        if (
+            (obase->op_private & (OPpTARGET_MY | OPpUNDEF_KEEP_PV)) == (OPpTARGET_MY | OPpUNDEF_KEEP_PV)
+            && (!match || PAD_SVl(obase->op_targ) == uninit_sv)
+        ) {
+            return varname(NULL, '$', obase->op_targ, NULL, 0, FUV_SUBSCRIPT_NONE);
+        }
         break;
 
     case OP_RV2AV:
@@ -16317,216 +16855,236 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
     case OP_PADAV:
     case OP_PADHV:
       {
-       const bool pad  = (    obase->op_type == OP_PADAV
+        const bool pad  = (    obase->op_type == OP_PADAV
                             || obase->op_type == OP_PADHV
                             || obase->op_type == OP_PADRANGE
                           );
 
-       const bool hash = (    obase->op_type == OP_PADHV
+        const bool hash = (    obase->op_type == OP_PADHV
                             || obase->op_type == OP_RV2HV
                             || (obase->op_type == OP_PADRANGE
                                 && SvTYPE(PAD_SVl(obase->op_targ)) == SVt_PVHV)
                           );
-       SSize_t index = 0;
-       SV *keysv = NULL;
-       int subscript_type = FUV_SUBSCRIPT_WITHIN;
-
-       if (pad) { /* @lex, %lex */
-           sv = PAD_SVl(obase->op_targ);
-           gv = NULL;
-       }
-       else {
-           if (cUNOPx(obase)->op_first->op_type == OP_GV) {
-           /* @global, %global */
-               gv = cGVOPx_gv(cUNOPx(obase)->op_first);
-               if (!gv)
-                   break;
-               sv = hash ? MUTABLE_SV(GvHV(gv)): MUTABLE_SV(GvAV(gv));
-           }
-           else if (obase == PL_op) /* @{expr}, %{expr} */
-               return find_uninit_var(cUNOPx(obase)->op_first,
+        SSize_t index = 0;
+        SV *keysv = NULL;
+        int subscript_type = FUV_SUBSCRIPT_WITHIN;
+
+        if (pad) { /* @lex, %lex */
+            sv = PAD_SVl(obase->op_targ);
+            gv = NULL;
+        }
+        else {
+            if (cUNOPx(obase)->op_first->op_type == OP_GV) {
+            /* @global, %global */
+                gv = cGVOPx_gv(cUNOPx(obase)->op_first);
+                if (!gv)
+                    break;
+                sv = hash ? MUTABLE_SV(GvHV(gv)): MUTABLE_SV(GvAV(gv));
+            }
+            else if (obase == PL_op) /* @{expr}, %{expr} */
+                return find_uninit_var(cUNOPx(obase)->op_first,
                                                 uninit_sv, match, desc_p);
-           else /* @{expr}, %{expr} as a sub-expression */
-               return NULL;
-       }
-
-       /* attempt to find a match within the aggregate */
-       if (hash) {
-           keysv = find_hash_subscript((const HV*)sv, uninit_sv);
-           if (keysv)
-               subscript_type = FUV_SUBSCRIPT_HASH;
-       }
-       else {
-           index = find_array_subscript((const AV *)sv, uninit_sv);
-           if (index >= 0)
-               subscript_type = FUV_SUBSCRIPT_ARRAY;
-       }
-
-       if (match && subscript_type == FUV_SUBSCRIPT_WITHIN)
-           break;
-
-       return varname(gv, (char)(hash ? '%' : '@'), obase->op_targ,
-                                   keysv, index, subscript_type);
+            else /* @{expr}, %{expr} as a sub-expression */
+                return NULL;
+        }
+
+        /* attempt to find a match within the aggregate */
+        if (hash) {
+            keysv = find_hash_subscript((const HV*)sv, uninit_sv);
+            if (keysv)
+                subscript_type = FUV_SUBSCRIPT_HASH;
+        }
+        else {
+            index = find_array_subscript((const AV *)sv, uninit_sv);
+            if (index >= 0)
+                subscript_type = FUV_SUBSCRIPT_ARRAY;
+        }
+
+        if (match && subscript_type == FUV_SUBSCRIPT_WITHIN)
+            break;
+
+        return varname(gv, (char)(hash ? '%' : '@'), obase->op_targ,
+                                    keysv, index, subscript_type);
       }
 
     case OP_RV2SV:
-       if (cUNOPx(obase)->op_first->op_type == OP_GV) {
-           /* $global */
-           gv = cGVOPx_gv(cUNOPx(obase)->op_first);
-           if (!gv || !GvSTASH(gv))
-               break;
-           if (match && (GvSV(gv) != uninit_sv))
-               break;
-           return varname(gv, '$', 0, NULL, 0, FUV_SUBSCRIPT_NONE);
-       }
-       /* ${expr} */
-       return find_uninit_var(cUNOPx(obase)->op_first, uninit_sv, 1, desc_p);
+        if (cUNOPx(obase)->op_first->op_type == OP_GV) {
+            /* $global */
+            gv = cGVOPx_gv(cUNOPx(obase)->op_first);
+            if (!gv || !GvSTASH(gv))
+                break;
+            if (match && (GvSV(gv) != uninit_sv))
+                break;
+            return varname(gv, '$', 0, NULL, 0, FUV_SUBSCRIPT_NONE);
+        }
+        /* ${expr} */
+        return find_uninit_var(cUNOPx(obase)->op_first, uninit_sv, 1, desc_p);
 
     case OP_PADSV:
-       if (match && PAD_SVl(obase->op_targ) != uninit_sv)
-           break;
-       return varname(NULL, '$', obase->op_targ,
-                                   NULL, 0, FUV_SUBSCRIPT_NONE);
+        if (match && PAD_SVl(obase->op_targ) != uninit_sv)
+            break;
+        return varname(NULL, '$', obase->op_targ,
+                                    NULL, 0, FUV_SUBSCRIPT_NONE);
+
+    case OP_PADSV_STORE:
+        if (match && PAD_SVl(obase->op_targ) != uninit_sv)
+            goto do_op;
+        return varname(NULL, '$', obase->op_targ,
+                                    NULL, 0, FUV_SUBSCRIPT_NONE);
 
     case OP_GVSV:
-       gv = cGVOPx_gv(obase);
-       if (!gv || (match && GvSV(gv) != uninit_sv) || !GvSTASH(gv))
-           break;
-       return varname(gv, '$', 0, NULL, 0, FUV_SUBSCRIPT_NONE);
+        gv = cGVOPx_gv(obase);
+        if (!gv || (match && GvSV(gv) != uninit_sv) || !GvSTASH(gv))
+            break;
+        return varname(gv, '$', 0, NULL, 0, FUV_SUBSCRIPT_NONE);
 
     case OP_AELEMFAST_LEX:
-       if (match) {
-           SV **svp;
-           AV *av = MUTABLE_AV(PAD_SV(obase->op_targ));
-           if (!av || SvRMAGICAL(av))
-               break;
-           svp = av_fetch(av, (I8)obase->op_private, FALSE);
-           if (!svp || *svp != uninit_sv)
-               break;
-       }
-       return varname(NULL, '$', obase->op_targ,
-                      NULL, (I8)obase->op_private, FUV_SUBSCRIPT_ARRAY);
+        if (match) {
+            SV **svp;
+            AV *av = MUTABLE_AV(PAD_SV(obase->op_targ));
+            if (!av || SvRMAGICAL(av))
+                break;
+            svp = av_fetch(av, (I8)obase->op_private, FALSE);
+            if (!svp || *svp != uninit_sv)
+                break;
+        }
+        return varname(NULL, '$', obase->op_targ,
+                       NULL, (I8)obase->op_private, FUV_SUBSCRIPT_ARRAY);
+
+    case OP_AELEMFASTLEX_STORE:
+        if (match) {
+            SV **svp;
+            AV *av = MUTABLE_AV(PAD_SV(obase->op_targ));
+            if (!av || SvRMAGICAL(av))
+                goto do_op;
+            svp = av_fetch(av, (I8)obase->op_private, FALSE);
+            if (!svp || *svp != uninit_sv)
+                goto do_op;
+        }
+        return varname(NULL, '$', obase->op_targ,
+                       NULL, (I8)obase->op_private, FUV_SUBSCRIPT_ARRAY);
+
     case OP_AELEMFAST:
-       {
-           gv = cGVOPx_gv(obase);
-           if (!gv)
-               break;
-           if (match) {
-               SV **svp;
-               AV *const av = GvAV(gv);
-               if (!av || SvRMAGICAL(av))
-                   break;
-               svp = av_fetch(av, (I8)obase->op_private, FALSE);
-               if (!svp || *svp != uninit_sv)
-                   break;
-           }
-           return varname(gv, '$', 0,
-                   NULL, (I8)obase->op_private, FUV_SUBSCRIPT_ARRAY);
-       }
-       NOT_REACHED; /* NOTREACHED */
+        {
+            gv = cGVOPx_gv(obase);
+            if (!gv)
+                break;
+            if (match) {
+                SV **svp;
+                AV *const av = GvAV(gv);
+                if (!av || SvRMAGICAL(av))
+                    break;
+                svp = av_fetch(av, (I8)obase->op_private, FALSE);
+                if (!svp || *svp != uninit_sv)
+                    break;
+            }
+            return varname(gv, '$', 0,
+                    NULL, (I8)obase->op_private, FUV_SUBSCRIPT_ARRAY);
+        }
+        NOT_REACHED; /* NOTREACHED */
 
     case OP_EXISTS:
-       o = cUNOPx(obase)->op_first;
-       if (!o || o->op_type != OP_NULL ||
-               ! (o->op_targ == OP_AELEM || o->op_targ == OP_HELEM))
-           break;
-       return find_uninit_var(cBINOPo->op_last, uninit_sv, match, desc_p);
+        o = cUNOPx(obase)->op_first;
+        if (!o || o->op_type != OP_NULL ||
+                ! (o->op_targ == OP_AELEM || o->op_targ == OP_HELEM))
+            break;
+        return find_uninit_var(cBINOPo->op_last, uninit_sv, match, desc_p);
 
     case OP_AELEM:
     case OP_HELEM:
     {
-       bool negate = FALSE;
+        bool negate = FALSE;
 
-       if (PL_op == obase)
-           /* $a[uninit_expr] or $h{uninit_expr} */
-           return find_uninit_var(cBINOPx(obase)->op_last,
+        if (PL_op == obase)
+            /* $a[uninit_expr] or $h{uninit_expr} */
+            return find_uninit_var(cBINOPx(obase)->op_last,
                                                 uninit_sv, match, desc_p);
 
-       gv = NULL;
-       o = cBINOPx(obase)->op_first;
-       kid = cBINOPx(obase)->op_last;
-
-       /* get the av or hv, and optionally the gv */
-       sv = NULL;
-       if  (o->op_type == OP_PADAV || o->op_type == OP_PADHV) {
-           sv = PAD_SV(o->op_targ);
-       }
-       else if ((o->op_type == OP_RV2AV || o->op_type == OP_RV2HV)
-               && cUNOPo->op_first->op_type == OP_GV)
-       {
-           gv = cGVOPx_gv(cUNOPo->op_first);
-           if (!gv)
-               break;
-           sv = o->op_type
-               == OP_RV2HV ? MUTABLE_SV(GvHV(gv)) : MUTABLE_SV(GvAV(gv));
-       }
-       if (!sv)
-           break;
-
-       if (kid && kid->op_type == OP_NEGATE) {
-           negate = TRUE;
-           kid = cUNOPx(kid)->op_first;
-       }
-
-       if (kid && kid->op_type == OP_CONST && SvOK(cSVOPx_sv(kid))) {
-           /* index is constant */
-           SV* kidsv;
-           if (negate) {
-               kidsv = newSVpvs_flags("-", SVs_TEMP);
-               sv_catsv(kidsv, cSVOPx_sv(kid));
-           }
-           else
-               kidsv = cSVOPx_sv(kid);
-           if (match) {
-               if (SvMAGICAL(sv))
-                   break;
-               if (obase->op_type == OP_HELEM) {
-                   HE* he = hv_fetch_ent(MUTABLE_HV(sv), kidsv, 0, 0);
-                   if (!he || HeVAL(he) != uninit_sv)
-                       break;
-               }
-               else {
-                   SV * const  opsv = cSVOPx_sv(kid);
-                   const IV  opsviv = SvIV(opsv);
-                   SV * const * const svp = av_fetch(MUTABLE_AV(sv),
-                       negate ? - opsviv : opsviv,
-                       FALSE);
-                   if (!svp || *svp != uninit_sv)
-                       break;
-               }
-           }
-           if (obase->op_type == OP_HELEM)
-               return varname(gv, '%', o->op_targ,
-                           kidsv, 0, FUV_SUBSCRIPT_HASH);
-           else
-               return varname(gv, '@', o->op_targ, NULL,
-                   negate ? - SvIV(cSVOPx_sv(kid)) : SvIV(cSVOPx_sv(kid)),
-                   FUV_SUBSCRIPT_ARRAY);
-       }
-       else  {
-           /* index is an expression;
-            * attempt to find a match within the aggregate */
-           if (obase->op_type == OP_HELEM) {
-               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 SSize_t index
-                   = find_array_subscript((const AV *)sv, uninit_sv);
-               if (index >= 0)
-                   return varname(gv, '@', o->op_targ,
-                                       NULL, index, FUV_SUBSCRIPT_ARRAY);
-           }
-           if (match)
-               break;
-           return varname(gv,
-               (char)((o->op_type == OP_PADAV || o->op_type == OP_RV2AV)
-               ? '@' : '%'),
-               o->op_targ, NULL, 0, FUV_SUBSCRIPT_WITHIN);
-       }
-       NOT_REACHED; /* NOTREACHED */
+        gv = NULL;
+        o = cBINOPx(obase)->op_first;
+        kid = cBINOPx(obase)->op_last;
+
+        /* get the av or hv, and optionally the gv */
+        sv = NULL;
+        if  (o->op_type == OP_PADAV || o->op_type == OP_PADHV) {
+            sv = PAD_SV(o->op_targ);
+        }
+        else if ((o->op_type == OP_RV2AV || o->op_type == OP_RV2HV)
+                && cUNOPo->op_first->op_type == OP_GV)
+        {
+            gv = cGVOPx_gv(cUNOPo->op_first);
+            if (!gv)
+                break;
+            sv = o->op_type
+                == OP_RV2HV ? MUTABLE_SV(GvHV(gv)) : MUTABLE_SV(GvAV(gv));
+        }
+        if (!sv)
+            break;
+
+        if (kid && kid->op_type == OP_NEGATE) {
+            negate = TRUE;
+            kid = cUNOPx(kid)->op_first;
+        }
+
+        if (kid && kid->op_type == OP_CONST && SvOK(cSVOPx_sv(kid))) {
+            /* index is constant */
+            SV* kidsv;
+            if (negate) {
+                kidsv = newSVpvs_flags("-", SVs_TEMP);
+                sv_catsv(kidsv, cSVOPx_sv(kid));
+            }
+            else
+                kidsv = cSVOPx_sv(kid);
+            if (match) {
+                if (SvMAGICAL(sv))
+                    break;
+                if (obase->op_type == OP_HELEM) {
+                    HE* he = hv_fetch_ent(MUTABLE_HV(sv), kidsv, 0, 0);
+                    if (!he || HeVAL(he) != uninit_sv)
+                        break;
+                }
+                else {
+                    SV * const  opsv = cSVOPx_sv(kid);
+                    const IV  opsviv = SvIV(opsv);
+                    SV * const * const svp = av_fetch(MUTABLE_AV(sv),
+                        negate ? - opsviv : opsviv,
+                        FALSE);
+                    if (!svp || *svp != uninit_sv)
+                        break;
+                }
+            }
+            if (obase->op_type == OP_HELEM)
+                return varname(gv, '%', o->op_targ,
+                            kidsv, 0, FUV_SUBSCRIPT_HASH);
+            else
+                return varname(gv, '@', o->op_targ, NULL,
+                    negate ? - SvIV(cSVOPx_sv(kid)) : SvIV(cSVOPx_sv(kid)),
+                    FUV_SUBSCRIPT_ARRAY);
+        }
+        else {
+            /* index is an expression;
+             * attempt to find a match within the aggregate */
+            if (obase->op_type == OP_HELEM) {
+                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 SSize_t index
+                    = find_array_subscript((const AV *)sv, uninit_sv);
+                if (index >= 0)
+                    return varname(gv, '@', o->op_targ,
+                                        NULL, index, FUV_SUBSCRIPT_ARRAY);
+            }
+            if (match)
+                break;
+            return varname(gv,
+                (char)((o->op_type == OP_PADAV || o->op_type == OP_RV2AV)
+                ? '@' : '%'),
+                o->op_targ, NULL, 0, FUV_SUBSCRIPT_WITHIN);
+        }
+        NOT_REACHED; /* NOTREACHED */
     }
 
     case OP_MULTIDEREF: {
@@ -16647,8 +17205,8 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
             actions >>= MDEREF_SHIFT;
         } /* while */
 
-       if (PL_op == obase) {
-           /* most likely index was undef */
+        if (PL_op == obase) {
+            /* most likely index was undef */
 
             *desc_p = (    (actions & MDEREF_FLAG_last)
                         && (obase->op_private
@@ -16669,7 +17227,7 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
             if (index_targ) {
                 if (PL_curpad[index_targ] == uninit_sv)
                     return varname(NULL, '$', index_targ,
-                                   NULL, 0, FUV_SUBSCRIPT_NONE);
+                                    NULL, 0, FUV_SUBSCRIPT_NONE);
                 else
                     return NULL;
             }
@@ -16684,7 +17242,7 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
             break;
 
         if (agg_targ)
-           sv = PAD_SV(agg_targ);
+            sv = PAD_SV(agg_targ);
         else if (agg_gv) {
             sv = is_hv ? MUTABLE_SV(GvHV(agg_gv)) : MUTABLE_SV(GvAV(agg_gv));
             if (!sv)
@@ -16693,117 +17251,146 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
         else
             break;
 
-       if (index_type == MDEREF_INDEX_const) {
-           if (match) {
-               if (SvMAGICAL(sv))
-                   break;
-               if (is_hv) {
-                   HE* he = hv_fetch_ent(MUTABLE_HV(sv), index_const_sv, 0, 0);
-                   if (!he || HeVAL(he) != uninit_sv)
-                       break;
-               }
-               else {
-                   SV * const * const svp =
+        if (index_type == MDEREF_INDEX_const) {
+            if (match) {
+                if (SvMAGICAL(sv))
+                    break;
+                if (is_hv) {
+                    HE* he = hv_fetch_ent(MUTABLE_HV(sv), index_const_sv, 0, 0);
+                    if (!he || HeVAL(he) != uninit_sv)
+                        break;
+                }
+                else {
+                    SV * const * const svp =
                             av_fetch(MUTABLE_AV(sv), index_const_iv, FALSE);
-                   if (!svp || *svp != uninit_sv)
-                       break;
-               }
-           }
-           return is_hv
-               ? varname(agg_gv, '%', agg_targ,
+                    if (!svp || *svp != uninit_sv)
+                        break;
+                }
+            }
+            return is_hv
+                ? varname(agg_gv, '%', agg_targ,
                                 index_const_sv, 0,    FUV_SUBSCRIPT_HASH)
-               : varname(agg_gv, '@', agg_targ,
+                : varname(agg_gv, '@', agg_targ,
                                 NULL, index_const_iv, FUV_SUBSCRIPT_ARRAY);
-       }
-       else  {
-           /* index is an var */
-           if (is_hv) {
-               SV * const keysv = find_hash_subscript((const HV*)sv, uninit_sv);
-               if (keysv)
-                   return varname(agg_gv, '%', agg_targ,
-                                               keysv, 0, FUV_SUBSCRIPT_HASH);
-           }
-           else {
-               const SSize_t index
-                   = find_array_subscript((const AV *)sv, uninit_sv);
-               if (index >= 0)
-                   return varname(agg_gv, '@', agg_targ,
-                                       NULL, index, FUV_SUBSCRIPT_ARRAY);
-           }
-           if (match)
-               break;
-           return varname(agg_gv,
-               is_hv ? '%' : '@',
-               agg_targ, NULL, 0, FUV_SUBSCRIPT_WITHIN);
-       }
-       NOT_REACHED; /* NOTREACHED */
+        }
+        else {
+            /* index is an var */
+            if (is_hv) {
+                SV * const keysv = find_hash_subscript((const HV*)sv, uninit_sv);
+                if (keysv)
+                    return varname(agg_gv, '%', agg_targ,
+                                                keysv, 0, FUV_SUBSCRIPT_HASH);
+            }
+            else {
+                const SSize_t index
+                    = find_array_subscript((const AV *)sv, uninit_sv);
+                if (index >= 0)
+                    return varname(agg_gv, '@', agg_targ,
+                                        NULL, index, FUV_SUBSCRIPT_ARRAY);
+            }
+            /* look for an element not found */
+            if (!SvMAGICAL(sv)) {
+                SV *index_sv = NULL;
+                if (index_targ) {
+                    index_sv = PL_curpad[index_targ];
+                }
+                else if (index_gv) {
+                    index_sv = GvSV(index_gv);
+                }
+                if (index_sv && !SvMAGICAL(index_sv) && !SvROK(index_sv)) {
+                    if (is_hv) {
+                        SV *report_index_sv = SvOK(index_sv) ? index_sv : &PL_sv_no;
+                        HE *he = hv_fetch_ent(MUTABLE_HV(sv), report_index_sv, 0, 0);
+                        if (!he) {
+                            return varname(agg_gv, '%', agg_targ,
+                                           report_index_sv, 0, FUV_SUBSCRIPT_HASH);
+                        }
+                    }
+                    else {
+                        SSize_t index = SvOK(index_sv) ? SvIV(index_sv) : 0;
+                        SV * const * const svp =
+                            av_fetch(MUTABLE_AV(sv), index, FALSE);
+                        if (!svp) {
+                            return varname(agg_gv, '@', agg_targ,
+                                           NULL, index, FUV_SUBSCRIPT_ARRAY);
+                        }
+                    }
+                }
+            }
+            if (match)
+                break;
+            return varname(agg_gv,
+                is_hv ? '%' : '@',
+                agg_targ, NULL, 0, FUV_SUBSCRIPT_WITHIN);
+        }
+        NOT_REACHED; /* NOTREACHED */
     }
 
     case OP_AASSIGN:
-       /* only examine RHS */
-       return find_uninit_var(cBINOPx(obase)->op_first, uninit_sv,
+        /* only examine RHS */
+        return find_uninit_var(cBINOPx(obase)->op_first, uninit_sv,
                                                                 match, desc_p);
 
     case OP_OPEN:
-       o = cUNOPx(obase)->op_first;
-       if (   o->op_type == OP_PUSHMARK
-          || (o->op_type == OP_NULL && o->op_targ == OP_PUSHMARK)
+        o = cUNOPx(obase)->op_first;
+        if (   o->op_type == OP_PUSHMARK
+           || (o->op_type == OP_NULL && o->op_targ == OP_PUSHMARK)
         )
             o = OpSIBLING(o);
 
-       if (!OpHAS_SIBLING(o)) {
-           /* one-arg version of open is highly magical */
-
-           if (o->op_type == OP_GV) { /* open FOO; */
-               gv = cGVOPx_gv(o);
-               if (match && GvSV(gv) != uninit_sv)
-                   break;
-               return varname(gv, '$', 0,
-                           NULL, 0, FUV_SUBSCRIPT_NONE);
-           }
-           /* other possibilities not handled are:
-            * open $x; or open my $x;  should return '${*$x}'
-            * open expr;               should return '$'.expr ideally
-            */
-            break;
-       }
-       match = 1;
-       goto do_op;
+        if (!OpHAS_SIBLING(o)) {
+            /* one-arg version of open is highly magical */
+
+            if (o->op_type == OP_GV) { /* open FOO; */
+                gv = cGVOPx_gv(o);
+                if (match && GvSV(gv) != uninit_sv)
+                    break;
+                return varname(gv, '$', 0,
+                            NULL, 0, FUV_SUBSCRIPT_NONE);
+            }
+            /* other possibilities not handled are:
+             * open $x; or open my $x; should return '${*$x}'
+             * open expr;              should return '$'.expr ideally
+             */
+             break;
+        }
+        match = 1;
+        goto do_op;
 
     /* ops where $_ may be an implicit arg */
     case OP_TRANS:
     case OP_TRANSR:
     case OP_SUBST:
     case OP_MATCH:
-       if ( !(obase->op_flags & OPf_STACKED)) {
-           if (uninit_sv == DEFSV)
-               return newSVpvs_flags("$_", SVs_TEMP);
-           else if (obase->op_targ
-                 && uninit_sv == PAD_SVl(obase->op_targ))
-               return varname(NULL, '$', obase->op_targ, NULL, 0,
-                              FUV_SUBSCRIPT_NONE);
-       }
-       goto do_op;
+        if ( !(obase->op_flags & OPf_STACKED)) {
+            if (uninit_sv == DEFSV)
+                return newSVpvs_flags("$_", SVs_TEMP);
+            else if (obase->op_targ
+                  && uninit_sv == PAD_SVl(obase->op_targ))
+                return varname(NULL, '$', obase->op_targ, NULL, 0,
+                               FUV_SUBSCRIPT_NONE);
+        }
+        goto do_op;
 
     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)
+        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
                || (o->op_type == OP_NULL && o->op_targ == OP_PUSHMARK)))
             o = OpSIBLING(OpSIBLING(o));
-       goto do_op2;
+        goto do_op2;
 
 
     case OP_ENTEREVAL: /* could be eval $undef or $x='$undef'; eval $x */
     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) */
+        /* the following ops are capable of returning PL_sv_undef even for
+         * defined arg(s) */
 
     case OP_BACKTICK:
     case OP_PIPE_OP:
@@ -16873,91 +17460,92 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
     case OP_UNPACK:
     case OP_SYSOPEN:
     case OP_SYSSEEK:
-       match = 1;
-       goto do_op;
+        match = 1;
+        goto do_op;
 
     case OP_ENTERSUB:
     case OP_GOTO:
-       /* XXX tmp hack: these two may call an XS sub, and currently
-         XS subs don't have a SUB entry on the context stack, so CV and
-         pad determination goes wrong, and BAD things happen. So, just
-         don't try to determine the value under those circumstances.
-         Need a better fix at dome point. DAPM 11/2007 */
-       break;
+        /* XXX tmp hack: these two may call an XS sub, and currently
+          XS subs don't have a SUB entry on the context stack, so CV and
+          pad determination goes wrong, and BAD things happen. So, just
+          don't try to determine the value under those circumstances.
+          Need a better fix at dome point. DAPM 11/2007 */
+        break;
 
     case OP_FLIP:
     case OP_FLOP:
     {
-       GV * const gv = gv_fetchpvs(".", GV_NOTQUAL, SVt_PV);
-       if (gv && GvSV(gv) == uninit_sv)
-           return newSVpvs_flags("$.", SVs_TEMP);
-       goto do_op;
+        GV * const gv = gv_fetchpvs(".", GV_NOTQUAL, SVt_PV);
+        if (gv && GvSV(gv) == uninit_sv)
+            return newSVpvs_flags("$.", SVs_TEMP);
+        goto do_op;
     }
 
     case OP_POS:
-       /* def-ness of rval pos() is independent of the def-ness of its arg */
-       if ( !(obase->op_flags & OPf_MOD))
-           break;
+        /* def-ness of rval pos() is independent of the def-ness of its arg */
+        if ( !(obase->op_flags & OPf_MOD))
+            break;
         /* FALLTHROUGH */
 
     case OP_SCHOMP:
     case OP_CHOMP:
-       if (SvROK(PL_rs) && uninit_sv == SvRV(PL_rs))
-           return newSVpvs_flags("${$/}", SVs_TEMP);
-       /* FALLTHROUGH */
+        if (SvROK(PL_rs) && uninit_sv == SvRV(PL_rs))
+            return newSVpvs_flags("${$/}", SVs_TEMP);
+        /* FALLTHROUGH */
 
     default:
     do_op:
-       if (!(obase->op_flags & OPf_KIDS))
-           break;
-       o = cUNOPx(obase)->op_first;
-       
+        if (!(obase->op_flags & OPf_KIDS))
+            break;
+        o = cUNOPx(obase)->op_first;
+
     do_op2:
-       if (!o)
-           break;
-
-       /* This loop checks all the kid ops, skipping any that cannot pos-
-        * sibly be responsible for the uninitialized value; i.e., defined
-        * constants and ops that return nothing.  If there is only one op
-        * left that is not skipped, then we *know* it is responsible for
-        * the uninitialized value.  If there is more than one op left, we
-        * have to look for an exact match in the while() loop below.
+        if (!o)
+            break;
+
+        /* This loop checks all the kid ops, skipping any that cannot pos-
+         * sibly be responsible for the uninitialized value; i.e., defined
+         * constants and ops that return nothing.  If there is only one op
+         * left that is not skipped, then we *know* it is responsible for
+         * the uninitialized value.  If there is more than one op left, we
+         * have to look for an exact match in the while() loop below.
          * Note that we skip padrange, because the individual pad ops that
          * it replaced are still in the tree, so we work on them instead.
-        */
-       o2 = NULL;
-       for (kid=o; kid; kid = OpSIBLING(kid)) {
-           const OPCODE type = kid->op_type;
-           if ( (type == OP_CONST && SvOK(cSVOPx_sv(kid)))
-             || (type == OP_NULL  && ! (kid->op_flags & OPf_KIDS))
-             || (type == OP_PUSHMARK)
-             || (type == OP_PADRANGE)
-           )
-           continue;
-
-           if (o2) { /* more than one found */
-               o2 = NULL;
-               break;
-           }
-           o2 = kid;
-       }
-       if (o2)
-           return find_uninit_var(o2, uninit_sv, match, desc_p);
-
-       /* scan all args */
-       while (o) {
-           sv = find_uninit_var(o, uninit_sv, 1, desc_p);
-           if (sv)
-               return sv;
-           o = OpSIBLING(o);
-       }
-       break;
+         */
+        o2 = NULL;
+        for (kid=o; kid; kid = OpSIBLING(kid)) {
+            const OPCODE type = kid->op_type;
+            if ( (type == OP_CONST && SvOK(cSVOPx_sv(kid)))
+              || (type == OP_NULL  && ! (kid->op_flags & OPf_KIDS))
+              || (type == OP_PUSHMARK)
+              || (type == OP_PADRANGE)
+            )
+            continue;
+
+            if (o2) { /* more than one found */
+                o2 = NULL;
+                break;
+            }
+            o2 = kid;
+        }
+        if (o2)
+            return find_uninit_var(o2, uninit_sv, match, desc_p);
+
+        /* scan all args */
+        while (o) {
+            sv = find_uninit_var(o, uninit_sv, 1, desc_p);
+            if (sv)
+                return sv;
+            o = OpSIBLING(o);
+        }
+        break;
     }
     return NULL;
 }
 
 
 /*
+=for apidoc_section $warning
 =for apidoc report_uninit
 
 Print appropriate "Use of uninitialized variable" warning.
@@ -16972,17 +17560,17 @@ Perl_report_uninit(pTHX_ const SV *uninit_sv)
     SV* varname = NULL;
 
     if (PL_op) {
-       desc = PL_op->op_type == OP_STRINGIFY && PL_op->op_folded
-               ? "join or string"
+        desc = PL_op->op_type == OP_STRINGIFY && PL_op->op_folded
+                ? "join or string"
                 : PL_op->op_type == OP_MULTICONCAT
                     && (PL_op->op_private & OPpMULTICONCAT_FAKE)
                 ? "sprintf"
-               : OP_DESC(PL_op);
-       if (uninit_sv && PL_curpad) {
-           varname = find_uninit_var(PL_op, uninit_sv, 0, &desc);
-           if (varname)
-               sv_insert(varname, 0, 0, " ", 1);
-       }
+                : OP_DESC(PL_op);
+        if (uninit_sv && PL_curpad) {
+            varname = find_uninit_var(PL_op, uninit_sv, 0, &desc);
+            if (varname)
+                sv_insert(varname, 0, 0, " ", 1);
+        }
     }
     else if (PL_curstackinfo->si_type == PERLSI_SORT && cxstack_ix == 0)
         /* we've reached the end of a sort block or sub,